commit c9b43d2479e438a16e2050a1dcdda49ba8e2a230 Author: kjh Date: Mon Jul 29 17:03:12 2024 +0900 init: 민자도로 미납통행료 전자고지 시스템 diff --git a/README.md b/README.md new file mode 100644 index 0000000..41cda01 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +### 프로젝트 실행 오류 처리 +```text +import static cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng.orgMng; +관련해서 못찾는 경우가 발생 + +target > generated-sources 폴더 +annotations, java 폴더가 Excluded 상태인데 마우스 우클릭해서 Source로 변경 + +* /doc/setting.png 참조 +``` + +### 배포 +```text +[민자] +mvn clean package -P prod-iup +``` + +### 업무 +```text +[전자고지] +- 나이스 CI 소켓 +- 카카오톡 전자고지 (기존 카카오페이 내 문서함에서 변경) +- 네이버 전자문서 + +- 업무 흐름 : 카카오톡 전자고지 발송 후 실패 자료만 바로 네이버 전자문서 발송 + +[결제] +- 카카오톡 전자고지 모바일 페이지 열람 시 카카오페이 결제 버튼만 있음 +- 네이버 전자문서 모바일 페이지 열람 시 네이버 간편결제 버튼만 있음 +``` + +### 연계 +```text +[나이스 CI 소켓] +- /doc/NICE_CI모듈.zip + +[카카오톡 전자고지] +- 홈페이지 : https://developers.kakao.com/ +- 개발가이드 : https://developers.kakao.com/docs/latest/ko/kakaotalk-edoc/common +- 네트워크 연동 가이드 : https://kko.to/gB3Ba7BOKy + +[네이버 전자문서] +- /doc/네이버_고지서_연동_가이드_V_1_1.pdf + +[카카오페이 청구서] +- /doc/카카오페이청구서_조회납부_API가이드_v0.1.3.pdf +- 호출 : 민자 시스템 -> 더즌 -> 카카오페이 + +* 카카오페이 결제 관련해서 url 및 항목이 변경되었으나 더즌에서 중간에서 바이패스하지 않고 카카오페이 변경 내용을 적용함 +(카카오페이 결제 버전이 변경되었으나 민자 시스템 변경사항 없음) + +[네이버페이 간편결제] +- 개발자센터 : https://developer.pay.naver.com/ +``` \ No newline at end of file diff --git a/doc/NICE_CI모듈.zip b/doc/NICE_CI모듈.zip new file mode 100644 index 0000000..cf96c12 Binary files /dev/null and b/doc/NICE_CI모듈.zip differ diff --git a/doc/네이버_고지서_연동_가이드_V_1_1.pdf b/doc/네이버_고지서_연동_가이드_V_1_1.pdf new file mode 100644 index 0000000..020aa9c Binary files /dev/null and b/doc/네이버_고지서_연동_가이드_V_1_1.pdf differ diff --git a/doc/네이버전자문서_서비스소개자료_220427.pdf b/doc/네이버전자문서_서비스소개자료_220427.pdf new file mode 100644 index 0000000..f6476c1 Binary files /dev/null and b/doc/네이버전자문서_서비스소개자료_220427.pdf differ diff --git a/doc/카카오페이청구서_조회납부_API가이드_v0.1.3.pdf b/doc/카카오페이청구서_조회납부_API가이드_v0.1.3.pdf new file mode 100644 index 0000000..084f445 Binary files /dev/null and b/doc/카카오페이청구서_조회납부_API가이드_v0.1.3.pdf differ diff --git a/libs/VNOInterop.jar b/libs/VNOInterop.jar new file mode 100644 index 0000000..d46f04b Binary files /dev/null and b/libs/VNOInterop.jar differ diff --git a/libs/ojdbc6.jar b/libs/ojdbc6.jar new file mode 100644 index 0000000..b663cd2 Binary files /dev/null and b/libs/ojdbc6.jar differ diff --git a/libs/ojdbc8.jar b/libs/ojdbc8.jar new file mode 100644 index 0000000..bf41243 Binary files /dev/null and b/libs/ojdbc8.jar differ diff --git a/src/main/java/cokr/xit/ens/ModulePostApplication.java b/src/main/java/cokr/xit/ens/ModulePostApplication.java new file mode 100644 index 0000000..4d595ff --- /dev/null +++ b/src/main/java/cokr/xit/ens/ModulePostApplication.java @@ -0,0 +1,84 @@ +package cokr.xit.ens; + +import cokr.xit.ens.core.utils.Checks; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.ApplicationPidFileWriter; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Slf4j +@SpringBootApplication +//@Import({QuerydslConfig.class, CodeMapperConfig.class}) +@ComponentScan( +// nameGenerator = CustomBeanNameGenerator.class, + basePackages = "cokr.xit") +//@EnableAutoConfiguration +@EnableScheduling +//@EnableWebMvc +//public class ModulePostApplication{ +public class ModulePostApplication extends SpringBootServletInitializer { + public static void main(String[] args) { + log.info("ENS Application load start..."); + if (Checks.isEmpty(System.getProperty("spring.profiles.active"))) { + log.error("===================================================================="); + log.error(">>>>>>>>>>>>>> Undefined start option <<<<<<<<<<<<<<"); + log.error(">>>>>>>>>>>>>> -Dspring.profiles.active=local|dev|prod-traffic/prod-traffic-cheonan/prod-iup <<<<<<<<<<<<<<"); + log.error("============== ENS Application start fail ==============="); + log.error("===================================================================="); + System.exit(-1); + } + System.setProperty("ens.active.profile", System.getProperty("spring.profiles.active")); + + + /* + SpringApplication.run(ModulePostApplication.class, args); + */ + Long begin = System.currentTimeMillis(); + + + SpringApplication application = new SpringApplication(ModulePostApplication.class); + application.addListeners(new ApplicationPidFileWriter()); + application.run(args); + + + log.info("========================================================================================="); + log.info("========== ENS Application load Complete :: active profiles - {} ==========", System.getProperty("spring.profiles.active")); + log.info("========================================================================================="); + + + Long end = System.currentTimeMillis(); + System.out.println("===================================================="); + System.out.println("기동 소요시간: " + (end - begin) + "ms"); + System.out.println("===================================================="); + + + + + + /* multi-thread test */ +// try { +// MultiThreadSample.example(); +// MultiThreadSample.runnableExample(); +// MultiThreadSample.callableExample(); +// MultiThreadSample.completionServiceExample(); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } catch (ExecutionException e) { +// e.printStackTrace(); +// } + + /* multi-thread return result test */ +// ResultByRunnableExample.main(args); + } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(ModulePostApplication.class); + } + + +} diff --git a/src/main/java/cokr/xit/ens/ServletInitializer.java b/src/main/java/cokr/xit/ens/ServletInitializer.java new file mode 100644 index 0000000..c1a28ba --- /dev/null +++ b/src/main/java/cokr/xit/ens/ServletInitializer.java @@ -0,0 +1,13 @@ +package cokr.xit.ens; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +public class ServletInitializer extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(ModulePostApplication.class); + } + +} diff --git a/src/main/java/cokr/xit/ens/batch/sched/EnsIntgrnScheduler.java b/src/main/java/cokr/xit/ens/batch/sched/EnsIntgrnScheduler.java new file mode 100644 index 0000000..3c72578 --- /dev/null +++ b/src/main/java/cokr/xit/ens/batch/sched/EnsIntgrnScheduler.java @@ -0,0 +1,70 @@ +package cokr.xit.ens.batch.sched; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.IntgrnNotiService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Slf4j +@Component +@Profile("!local & !local-maria & !local-oracle & !local-test") +@RequiredArgsConstructor +public class EnsIntgrnScheduler { + + private final IntgrnNotiService intgrnNotiService; + + /** + * 통합고지 재전송 처리 + * -. 전송회차가 완료되지 않은 모든 자료에 대해 전송을 수행 한다. + */ + @Scheduled(cron = "0 */10 9-18 * * *") + public void resended() { + EnsResponseVO responseVO = intgrnNotiService.sendBulkAll(); + StringBuffer sb = new StringBuffer(); + sb.append("\n=======================================================") + .append("\n[ENS INTGRN] 통합고지 재전송처리") + .append("\n결과: {}") + .append("\n======================================================="); + log.info(sb.toString(), responseVO.toString()); + } + + + /** + * 통합고지 상태갱신 처리 + * -. "실패(~fail) 또는 만료(close) 외" 상태의 자료에 대해 문서상태를 갱신 한다. + * -. 문서상태는 현재 상태에 따라 "전송완료(sendcmplt) 또는 열람중(open)"으로 갱신 된다. + */ + @Scheduled(cron = "0 0 23 * * *") + public void fetched() { + EnsResponseVO responseVO = intgrnNotiService.statBulkAll(); + StringBuffer sb = new StringBuffer(); + sb.append("\n=======================================================") + .append("\n[ENS INTGRN] 통합고지 문서상태갱신 처리") + .append("\n결과: {}") + .append("\n======================================================="); + log.info(sb.toString(), responseVO.toString()); + } + + + /** + * 마감처리 + * -. "열람(open)" 상태의 자료 중 마감기한이 경과한 자료의 상태정보를 "마감(close)" 으로 변경 한다. + */ + @Scheduled(cron = "30 0 9-18 * * *") + public void closed() { + EnsResponseVO> responseVO = intgrnNotiService.closed(); + StringBuffer sb = new StringBuffer(); + sb.append("\n=======================================================") + .append("\n[ENS INTGRN] 통합고지 마감처리 - 총 {}건") + .append("\nIntSendMastId {}") + .append("\n======================================================="); + log.info(sb.toString(), responseVO.getResultInfo().size(), responseVO.getResultInfo().toString()); + } + + +} diff --git a/src/main/java/cokr/xit/ens/batch/sched/EnsKkoAlimtalkScheduler.java b/src/main/java/cokr/xit/ens/batch/sched/EnsKkoAlimtalkScheduler.java new file mode 100644 index 0000000..bf059a8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/batch/sched/EnsKkoAlimtalkScheduler.java @@ -0,0 +1,35 @@ +package cokr.xit.ens.batch.sched; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.modules.kkoalimtalk.service.KkoAlimtalkService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@Profile("!local & !local-maria & !local-oracle & !local-test") +@RequiredArgsConstructor +public class EnsKkoAlimtalkScheduler { + + private final KkoAlimtalkService kkoAlimtalkService; + + + /** + * 알림톡 전송 처리 + * -. "제작성공(makeok)" 상태의 자료 중 발송일시(sendDt)가 경과한 자료에 대해 전송을 수행 한다. + */ + @Scheduled(cron = "0 */1 9-18 * * *") + public void sended() { + EnsResponseVO responseVO = kkoAlimtalkService.sendBulkAll(); + StringBuffer sb = new StringBuffer(); + sb.append("\n=======================================================") + .append("\n[ENS] 카카오 알림톡 전송처리") + .append("\n결과: {}") + .append("\n======================================================="); + log.info(sb.toString(), responseVO.toString()); + } + +} diff --git a/src/main/java/cokr/xit/ens/batch/sched/EnsKkoMydocScheduler.java b/src/main/java/cokr/xit/ens/batch/sched/EnsKkoMydocScheduler.java new file mode 100644 index 0000000..9a4fd85 --- /dev/null +++ b/src/main/java/cokr/xit/ens/batch/sched/EnsKkoMydocScheduler.java @@ -0,0 +1,68 @@ +package cokr.xit.ens.batch.sched; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.modules.kkomydoc.service.KkoMydocHisService; +import cokr.xit.ens.modules.kkomydoc.service.KkoMydocService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@Profile("!local & !local-maria & !local-oracle & !local-test") +@RequiredArgsConstructor +public class EnsKkoMydocScheduler { + + private final KkoMydocService kkoMydocService; + private final KkoMydocHisService kkoMydocHisService; + + /** + * 카카오 내문서함(인증톡) 전송 처리 + * -. "제작성공(makeok)" 상태의 모든 자료에 대해 전송을 수행 한다. + */ + @Scheduled(cron = "0 */1 9-18 * * *") + public void sended() { + EnsResponseVO responseVO = kkoMydocService.sendBulkAll(); + StringBuffer sb = new StringBuffer(); + sb.append("\n=======================================================") + .append("\n[ENS] 카카오 내문서함(인증톡) 전송처리") + .append("\n결과: {}") + .append("\n======================================================="); + log.info(sb.toString(), responseVO.toString()); + } + + /** + * 카카오 내문서함(인증톡) 상태갱신 처리 + * -. "발송성공/발송완료/열람중(sendok/sendcmplt/open)" 상태의 자료에 대해 문서상태를 갱신 한다. + * -. 문서상태는 현재 상태에 따라 "전송완료(sendcmplt) 또는 열람중(open)"으로 갱신 된다. + */ +// @Scheduled(cron = "0 */5 9-18 * * *") + @Scheduled(cron = "0 */30 9-18 * * *") + public void fetched() { + EnsResponseVO responseVO = kkoMydocService.statBulkAll(); + StringBuffer sb = new StringBuffer(); + sb.append("\n=======================================================") + .append("\n[ENS] 카카오 내문서함(인증톡) 문서상태갱신 처리") + .append("\n결과: {}") + .append("\n======================================================="); + log.info(sb.toString(), responseVO.toString()); + } + + /** + * 카카오 내문서함(인증톡) 상태갱신요청이력 영구 삭제 + */ + @Scheduled(cron = "4 4 4 * * *") + public void deleteStateHis() { + Long totCnt = kkoMydocHisService.truncateStatHist(); + StringBuffer sb = new StringBuffer(); + sb.append("\n=======================================================") + .append("\n[ENS] 카카오 내문서함(인증톡) 상태변경요청이력 영구 삭제") + .append("\n결과: {} 건 삭제") + .append("\n======================================================="); + log.info(sb.toString(), totCnt); + } + + +} diff --git a/src/main/java/cokr/xit/ens/batch/sched/EnsKtGibisScheduler.java b/src/main/java/cokr/xit/ens/batch/sched/EnsKtGibisScheduler.java new file mode 100644 index 0000000..5438752 --- /dev/null +++ b/src/main/java/cokr/xit/ens/batch/sched/EnsKtGibisScheduler.java @@ -0,0 +1,82 @@ +package cokr.xit.ens.batch.sched; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.ktsigntalk.gibis.service.KtGibisHisService; +import cokr.xit.ens.modules.ktsigntalk.gibis.service.KtGibisService; +import com.querydsl.core.Tuple; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; + +import static cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng.orgMng; + +@Slf4j +@Component +@Profile("!local & !local-maria & !local-oracle & !local-test") +@RequiredArgsConstructor +public class EnsKtGibisScheduler { + + private final KtGibisService ktGibisService; + private final KtGibisHisService ktGibisHisService; + private final JPAQueryFactory query; + + + /** + * KT 인증톡(지비스) 전송 처리 + * -. "제작성공(makeok)" 상태의 모든 자료에 대해 전송을 수행 한다. + */ + @Scheduled(cron = "0 */1 9-18 * * *") + public void sended() { + EnsResponseVO responseVO = ktGibisService.sendBulkAll(); + log.info("======================================================="); + log.info("[ENS] KT 인증톡(지비스) 전송처리"); + log.info("결과: {}", responseVO.toString()); + log.info("======================================================="); + } + + + /** + * KT 인증톡(지비스) 인증토큰 갱신 + */ + @Scheduled(cron = "0 0 0 1 */4 *") + public void refreshAuthToken() { + List list = query.select(orgMng.orgCd, orgMng.ktStClientId, orgMng.ktStClientSecret) + .from(orgMng) + .where(orgMng.ktStAccessToken.isNotNull()) + .fetch(); + + int cntRefresh = list.stream() + .map(tuple -> { + EnsResponseVO ensResponseVO = ktGibisService.refreshAuthToken(tuple.get(orgMng.orgCd), tuple.get(orgMng.ktStClientId), tuple.get(orgMng.ktStClientSecret)); + return EnsErrCd.OK.equals(ensResponseVO.getErrCode()) ? 1 : 0; + }) + .reduce(Integer::sum) + .orElse(0); + + log.info("======================================================="); + log.info("[ENS] KT 인증톡(지비스) accessToken 갱신"); + log.info("결과: {} 건 갱신({}/{})", cntRefresh, cntRefresh, list.size()); + log.info("======================================================="); + } + + +// /** +// * KT 인증톡(지비스) 상태갱신요청이력 영구 삭제 +// */ +// @Scheduled(cron = "4 4 4 * * *") +// public void deleteStateHis() { +// EnsResponseVO ensResponseVO = ktGibisHisService.truncateStatHist(); +// log.info("======================================================="); +// log.info("[ENS] KT 인증톡(지비스) 상태변경요청이력 영구 삭제"); +// log.info("결과: {} 건 삭제", ensResponseVO.getResultInfo()); +// log.info("======================================================="); +// } + + +} diff --git a/src/main/java/cokr/xit/ens/batch/sched/EnsKtSigntalkScheduler.java b/src/main/java/cokr/xit/ens/batch/sched/EnsKtSigntalkScheduler.java new file mode 100644 index 0000000..7086ba2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/batch/sched/EnsKtSigntalkScheduler.java @@ -0,0 +1,63 @@ +package cokr.xit.ens.batch.sched; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.modules.ktsigntalk.direct.service.KtSigntalkHisService; +import cokr.xit.ens.modules.ktsigntalk.direct.service.KtSigntalkService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@Profile("!local & !local-maria & !local-oracle & !local-test") +@RequiredArgsConstructor +public class EnsKtSigntalkScheduler { + + private final KtSigntalkService ktSigntalkService; + private final KtSigntalkHisService ktSigntalkHisService; + + + /** + * KT 인증톡 전송 처리 + * -. "제작성공(makeok)" 상태의 모든 자료에 대해 전송을 수행 한다. + */ + @Scheduled(cron = "0 */1 9-18 * * *") + public void sended() { + EnsResponseVO responseVO = ktSigntalkService.sendBulkAll(); + log.info("======================================================="); + log.info("[ENS] KT 인증톡 전송처리"); + log.info("결과: {}", responseVO.toString()); + log.info("======================================================="); + } + + /** + * KT 인증톡 상태갱신 처리 + * -. "발송성공/발송완료/열람중(sendok/sendcmplt/open)" 상태의 자료에 대해 문서상태를 갱신 한다. + * -. 문서상태는 현재 상태에 따라 "전송완료(sendcmplt) 또는 열람중(open)"으로 갱신 된다. + */ +// @Scheduled(cron = "0 */5 9-18 * * *") + @Scheduled(cron = "0 */30 9-18 * * *") + public void fetched() { + EnsResponseVO responseVO = ktSigntalkService.statBulkAll(); + log.info("======================================================="); + log.info("[ENS] KT 인증톡 문서상태갱신 처리"); + log.info("결과: {}", responseVO.toString()); + log.info("======================================================="); + } + + /** + * KT 인증톡 상태갱신요청이력 영구 삭제 + */ + @Scheduled(cron = "4 4 4 * * *") + public void deleteStateHis() { + EnsResponseVO ensResponseVO = ktSigntalkHisService.truncateStatHist(); + log.info("======================================================="); + log.info("[ENS] KT 인증톡 상태변경요청이력 영구 삭제"); + log.info("결과: {} 건 삭제", ensResponseVO.getResultInfo()); + log.info("======================================================="); + } + + +} diff --git a/src/main/java/cokr/xit/ens/batch/sched/EnsNvSigntalkScheduler.java b/src/main/java/cokr/xit/ens/batch/sched/EnsNvSigntalkScheduler.java new file mode 100644 index 0000000..180beb3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/batch/sched/EnsNvSigntalkScheduler.java @@ -0,0 +1,70 @@ +package cokr.xit.ens.batch.sched; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.modules.nvsigntalk.service.NvSigntalkHisService; +import cokr.xit.ens.modules.nvsigntalk.service.NvSigntalkService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@Profile("!local & !local-maria & !local-oracle & !local-test") +@RequiredArgsConstructor +public class EnsNvSigntalkScheduler { + + private final NvSigntalkService nvSigntalkService; + private final NvSigntalkHisService nvSigntalkHisService; + + + /** + * 네이버 고지서(인증톡) 전송 처리 + * -. "제작성공(makeok)" 상태의 모든 자료에 대해 전송을 수행 한다. + */ + @Scheduled(cron = "0 */1 9-18 * * *") + public void sended() { + EnsResponseVO responseVO = nvSigntalkService.sendBulkAll(); + StringBuffer sb = new StringBuffer(); + sb.append("\n=======================================================") + .append("\n[ENS] 네이버 고지서(인증톡) 전송처리") + .append("\n결과: {}") + .append("\n======================================================="); + log.info(sb.toString(), responseVO.toString()); + } + + /** + * 네이버 고지서(인증톡) 상태갱신 처리 + * -. "발송성공/발송완료/열람중(sendok/sendcmplt/open)" 상태의 자료에 대해 문서상태를 갱신 한다. + * -. 문서상태는 현재 상태에 따라 "전송완료(sendcmplt) 또는 열람중(open)"으로 갱신 된다. + */ +// @Scheduled(cron = "0 */5 9-18 * * *") + @Scheduled(cron = "0 */30 9-18 * * *") + public void fetched() { + EnsResponseVO responseVO = nvSigntalkService.statBulkAll(); + StringBuffer sb = new StringBuffer(); + sb.append("\n=======================================================") + .append("\n[ENS] 네이버 고지서(인증톡) 문서상태갱신 처리") + .append("\n결과: {}") + .append("\n======================================================="); + log.info(sb.toString(), responseVO.toString()); + } + + + /** + * 네이버 고지서(인증톡) 상태갱신요청이력 영구 삭제 + */ + @Scheduled(cron = "4 4 4 * * *") + public void deleteStateHis() { + Long totCnt = nvSigntalkHisService.truncateStatHist(); + StringBuffer sb = new StringBuffer(); + sb.append("\n=======================================================") + .append("\n[ENS] 네이버 고지서(인증톡) 상태변경요청이력 영구 삭제") + .append("\n결과: {} 건 삭제") + .append("\n======================================================="); + log.info(sb.toString(), totCnt); + } + + +} diff --git a/src/main/java/cokr/xit/ens/batch/sched/EnsScheduler.java b/src/main/java/cokr/xit/ens/batch/sched/EnsScheduler.java new file mode 100644 index 0000000..dbf698f --- /dev/null +++ b/src/main/java/cokr/xit/ens/batch/sched/EnsScheduler.java @@ -0,0 +1,48 @@ +package cokr.xit.ens.batch.sched; + +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.domain.SendMast; +import cokr.xit.ens.modules.common.domain.repository.SendMastRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Component +@Profile("!local & !local-maria & !local-oracle & !local-test") +//@Profile({"prod-traffic", "prod-iup"}) +@RequiredArgsConstructor +public class EnsScheduler { + + private final SendMastRepository sendMastRepository; + + + /** + * 마감처리 + * -. "열람(open)" 상태의 자료 중 마감기한이 경과한 자료의 상태정보를 "마감(close)" 으로 변경 한다. + */ + @Scheduled(cron = "0 */5 9-18 * * *") + @Transactional + public void closed() { + log.info("======================================================="); + List sendMastList = sendMastRepository.findAllByStatCdInAndCloseDtBefore(Arrays.asList(StatCd.sendcmplt, StatCd.open), LocalDateTime.now()); + log.info("[ENS] 마감처리 - 총 {}건", sendMastList.size()); + log.info("SendMastId {}", sendMastList.stream() + .map(row -> { + row.setStatCd(StatCd.close); + return row.getSendMastId(); + }) + .collect(Collectors.toList()) + .toString()); + log.info("======================================================="); + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/_legacy/ApiController.java b/src/main/java/cokr/xit/ens/biz/iup/_legacy/ApiController.java new file mode 100644 index 0000000..d2049b1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/_legacy/ApiController.java @@ -0,0 +1,42 @@ +//package cokr.xit.biz.iup._legacy; +// +// +//import four.api.service.DoznService; +//import four.api.service.DoznVO; +//import java.util.Date; +//import javax.annotation.Resource; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.springframework.web.bind.annotation.RequestBody; +//import org.springframework.web.bind.annotation.RequestMapping; +//import org.springframework.web.bind.annotation.RestController; +// +//@RestController +//public class ApiController { +// private final Logger logger = LoggerFactory.getLogger(getClass()); +// +// @Resource(name = "DoznService") +// private DoznService doznService; +// +// @RequestMapping(value = {"/kakao/notice"}, produces = {"application/json; charset=utf-8;"}) +// public String createBill(@RequestBody String data) { +// this.logger.info("/kakao/notice(" + new Date() + ") : " + data); +// DoznVO doznVO = this.doznService.selectNoticeInfo(data); +// return this.doznService.updateApiResponse(doznVO); +// } +// +// @RequestMapping(value = {"/kakao/prepay"}, produces = {"application/json; charset=utf-8;"}) +// public String kakaoPrepay(@RequestBody String data) { +// this.logger.info("/kakao/prepay(" + new Date() + ") : " + data); +// DoznVO doznVO = this.doznService.selectPrepayInfo(data); +// return this.doznService.updateApiResponse(doznVO); +// } +// +// @RequestMapping(value = {"/kakao/pay-result"}, produces = {"application/json; charset=utf-8;"}) +// public String kakaoPayResult(@RequestBody String data) { +// this.logger.info("/kakao/pay-result(" + new Date() + ") : " + data); +// DoznVO doznVO = this.doznService.insertPayResultInfo(data); +// return this.doznService.updateApiResponse(doznVO); +// } +//} +// diff --git a/src/main/java/cokr/xit/ens/biz/iup/_legacy/DetailVO.java b/src/main/java/cokr/xit/ens/biz/iup/_legacy/DetailVO.java new file mode 100644 index 0000000..1e3e7d2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/_legacy/DetailVO.java @@ -0,0 +1,54 @@ +package cokr.xit.ens.biz.iup._legacy; + +public class DetailVO +{ + public String title; + public String itemType; + public String description; + public String unitName; + public Object elements; + + public DetailVO() + { + this.title = null; + this.itemType = null; + this.description = null; + this.unitName = null; + this.elements = null; } + + public String getTitle() { + return this.title; } + + public void setTitle(String title) { + this.title = title; } + + public String getItemType() { + return this.itemType; } + + public void setItemType(String item_type) { + this.itemType = item_type; } + + public String getDescription() { + return this.description; } + + public void setDescription(String description) { + this.description = description; } + + public Object getElements() { + return this.elements; } + + public void setElements(Object elements) { + this.elements = elements; } + + public String getUnitName() { + return this.unitName; } + + public void setUnitName(String unitName) { + this.unitName = unitName; + } + + public String toString() + { + return "DetailVO [title=" + this.title + ", itemType=" + this.itemType ; + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/iup/_legacy/DoznDAO.xml b/src/main/java/cokr/xit/ens/biz/iup/_legacy/DoznDAO.xml new file mode 100644 index 0000000..3022192 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/_legacy/DoznDAO.xml @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/iup/_legacy/DoznSender.java b/src/main/java/cokr/xit/ens/biz/iup/_legacy/DoznSender.java new file mode 100644 index 0000000..e23d383 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/_legacy/DoznSender.java @@ -0,0 +1,354 @@ +//package cokr.xit.biz.iup.service; +// +//import cokr.xit.biz.iup._legacy.DoznVO; +//import com.fasterxml.jackson.databind.ObjectMapper; +//import com.google.gson.FieldNamingPolicy; +//import com.google.gson.Gson; +//import com.google.gson.GsonBuilder; +//import egovframework.com.cmm.util.StringUtil; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import java.io.*; +//import java.net.HttpURLConnection; +//import java.net.URL; +//import java.net.URLEncoder; +//import java.util.ArrayList; +//import java.util.HashMap; +//import java.util.List; +//import java.util.Map; +// +//public class DoznSender +//{ +// private final Logger logger = LoggerFactory.getLogger(super.getClass()); +// +// public static int CALL_FAIL_REPEAT_COUNT = 1; +// +// public static String PROXY_USE_YN = null; +// public static String PROXY_IP = null; +// public static int PROXY_PORT = 0; +// +// public static int CALL_CONNECTION_TIMEOUT = 8000; +// +// private ObjectMapper objectMapper = null; +// +// private String API_HOST = null; +// private String BILLER_CODE = null; +// private String AUTHORIZATION = null; +// +// public DoznSender() { +// getObjectMapper(); +// this.logger.debug("DoznSender init"); +// } +// +// public DoznSender(String api_host, String biller_code, String authorization) +// { +// getObjectMapper(); +// this.API_HOST = api_host; +// this.BILLER_CODE = biller_code; +// this.AUTHORIZATION = authorization; +// +// this.logger.debug("DoznSender init"); +// } +// +// public ObjectMapper getObjectMapper() +// { +// if (this.objectMapper == null) { +// this.objectMapper = new ObjectMapper(); +// } +// return this.objectMapper; +// } +// +// public String makeQuerystring(Map params) +// throws IOException +// { +// if (params == null) return null; +// if (params.size() == 0) return null; +// StringBuffer sb = new StringBuffer(); +// for (String key : params.keySet()) { +// if (sb.length() > 0) sb.append("&"); +// sb.append(key + "=" + encodeString(params.get(key))); +// } +// return sb.toString(); +// } +// +// public String encodeString(Object value) throws IOException { +// return URLEncoder.encode(String.valueOf(value), "UTF-8"); +// } +// +// private Map parseRespData(String plaindata) +// throws IOException +// { +// return ((Map)getObjectMapper().readValue(plaindata, Map.class)); +// } +// +// private void setResponse(Response resp) throws IOException { +// if (resp == null) return; +// if ((resp.status != -1) && (resp.plaindata != null)) { +// Map respMap = parseRespData(resp.plaindata); +// if (respMap.get("res_code") != null) { +// resp.res_code = ((String)respMap.get("res_code")); +// } +// if (respMap.get("message") != null) { +// resp.message = ((String)respMap.get("message")); +// } +// if (respMap.get("data") != null) { +// resp.data = respMap.get("data"); +// } +// if (respMap.size() > 0) +// resp.plaindata = null; +// } +// } +// +// private HttpURLConnection getConnection(String address) +// throws IOException +// { +// URL url = new URL(address); +// return ((HttpURLConnection)url.openConnection()); +// } +// +// public Response callGenerateUrl(Map params) +// { +// String uri = "/external/inquiry-payment/one-time/url/" + this.BILLER_CODE; +// try +// { +// HashMap someParam = new HashMap(); +// someParam.put("some_param", params.get("org_cd")); +// +// HashMap parameters = new HashMap(); +// parameters.put("biller_user_key", params.get("data_id")); +// parameters.put("expire_at", params.get("pay_expires_dt")); +// parameters.put("parameters", someParam); +// +// HashMap sendParams = new HashMap(); +// sendParams.put("data", parameters); +// +// String querystring = this.objectMapper.writeValueAsString(sendParams); +// +// Response resp = sendData(uri, "POST", "application/json; charset=utf-8", querystring, "N"); +// setResponse(resp); +// +// return resp; +// } catch (IOException e) { +// this.logger.error("callGenerateUrl {}", e); +// } +// return null; +// } +// +// public Response callReGenerateUrl(Map params) +// { +// String uri = "/external/inquiry-payment/one-time/url/re/" + this.BILLER_CODE; +// try +// { +// HashMap someParam = new HashMap(); +// someParam.put("some_param", params.get("org_cd")); +// +// HashMap parameters = new HashMap(); +// parameters.put("biller_user_key", params.get("data_id")); +// parameters.put("expire_at", params.get("pay_expires_dt")); +// parameters.put("parameters", someParam); +// +// HashMap sendParams = new HashMap(); +// sendParams.put("data", parameters); +// +// String querystring = this.objectMapper.writeValueAsString(sendParams); +// +// Response resp = sendData(uri, "POST", "application/json; charset=utf-8", querystring, "N"); +// setResponse(resp); +// +// return resp; +// } catch (IOException e) { +// this.logger.error("callReGenerateUrl {}", e); +// } +// return null; +// } +// +// public Response sendData(String uri, String method, String contentType, String querystring, String fullUrlYn) +// { +// int respCode; +// HttpURLConnection conn = null; +// OutputStreamWriter out = null; +// +// InputStream is = null; +// BufferedReader br = null; +// +// Response resp = new Response(this); +// try +// { +// String address = ""; +// +// if ("N".equals(fullUrlYn)) { +// if ((this.API_HOST == null) || (this.API_HOST.length() < 5)) { +// throw new IOException("API_URL is null!"); +// } +// if ((uri == null) || (uri.isEmpty())) { +// throw new IOException("URI is null!"); +// } +// +// address = this.API_HOST + uri; +// } +// else { +// if ((uri == null) || (uri.isEmpty())) { +// throw new IOException("URI is null!"); +// } +// +// address = uri; +// } +// +// this.logger.debug("DoznSender uri: " + address); +// +// if ((contentType == null) || (contentType.length() == 0)) { +// contentType = "application/json; charset=utf-8"; +// } +// +// conn = getConnection(address); +// +// conn.setDefaultUseCaches(false); +// conn.setDoInput(true); +// conn.setDoOutput(true); +// conn.setRequestMethod(method); +// conn.setRequestProperty("Content-Type", contentType); +// +// if (this.AUTHORIZATION != null) { +// conn.setRequestProperty("Authorization", this.AUTHORIZATION); +// } +// +// conn.setConnectTimeout(CALL_CONNECTION_TIMEOUT); +// conn.setReadTimeout(CALL_CONNECTION_TIMEOUT); +// conn.connect(); +// +// if ((querystring != null) && (querystring.length() > 0)) { +// this.logger.debug("DoznSender querystring[" + querystring + "]"); +// out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8"); +// out.write(querystring); +// out.flush(); +// } +// +// respCode = conn.getResponseCode(); +// System.out.println("respCode:" + respCode); +// +// if (respCode >= 400) +// { +// is = conn.getErrorStream(); +// } +// else is = conn.getInputStream(); +// +// br = new BufferedReader(new InputStreamReader(is, "UTF-8")); +// +// String line = null; +// StringBuffer bf = new StringBuffer(); +// while ((line = br.readLine()) != null) { +// bf.append(line.trim()); +// } +// if (respCode != 200) { +// this.logger.warn("DoznSender HTTP status: " + respCode); +// } +// this.logger.debug("DoznSender RESPONSE: " + bf.toString()); +// +// resp.status = respCode; +// resp.plaindata = bf.toString(); +// return resp; +// } +// catch (IOException e) { +// this.logger.error("DoznSender sendData {}", e.toString()); +// if ((querystring != null) && (querystring.length() > 0) && +// (!(uri.endsWith("S510")))) { +// this.logger.warn(">>> DoznSender querystring: " + querystring); +// } +// +// resp.status = -1; +// resp.message = e.getLocalizedMessage(); +// return resp; +// } +// finally { +// if (conn != null) { conn.disconnect(); conn = null; } +// if (out != null) { try { out.close(); } catch (IOException e) { this.logger.error("sendData finally {}", e); } out = null; } +// if (br != null) { try { br.close(); } catch (IOException e) { this.logger.error("sendData finally {}", e); } br = null; } +// if (is != null) { try { is.close(); } catch (IOException e) { this.logger.error("sendData finally {}", e); } is = null; +// } +// } +// } +// +// public String simpleResponse(DoznVO doznVO) +// { +// Map respData = new HashMap(); +// DoznVO resultVO = new DoznVO(); +// Response resp = new Response(this); +// +// if ((StringUtil.evl(doznVO.getApiType(), "").equals("NOTICE")) && (doznVO.getResCode().equals("OK"))) +// { +// HashMap hashMap = new HashMap(); +// hashMap.put("biller_user_key", doznVO.getBillerUserKey()); +// hashMap.put("title", doznVO.getTitle()); +// hashMap.put("amount", doznVO.getAmount()); +// +// hashMap.put("expire_type", doznVO.getExpireType()); +// hashMap.put("pay_expire_date", doznVO.getPayExpireDate()); +// +// HashMap detail = new HashMap(); +// List elements = new ArrayList(); +// List details = new ArrayList(); +// detail.put("item_type", "TEXT"); +// +// elements.add("상세 통행료 : " + doznVO.getDetailPasngChrgeSm()); +// elements.add("상세 부가통행료 : " + doznVO.getDetailAdiPasngChrgeSm()); +// detail.put("elements", elements); +// +// details.add(detail); +// hashMap.put("details", details); +// respData.put("result", hashMap); +// } +// else { +// respData = null; +// } +// +// this.logger.debug("getResCode:" + doznVO.getResCode()); +// this.logger.debug("getMessage:" + doznVO.getMessage()); +// +// resp.res_code = doznVO.getResCode(); +// resp.message = doznVO.getMessage(); +// resp.data = respData; +// +// String result = new Gson().toJson(resp).replace("\"status\":0,", ""); +// +// this.logger.debug("return :" + result); +// return result; +// } +// +// public DoznVO getData(String data) +// { +// Gson gson = new GsonBuilder() +// .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) +// .create(); +// +// String result = data.replace(" ", "").replace("\n", "").replace("\r", "").replace("\"data\":", ""); +// +// return ((DoznVO)gson.fromJson(result.substring(1, result.length() - 1), DoznVO.class)); +// } +// +// public DoznVO callBillsInfoUrl(String request, String uri) throws Exception +// { +// try { +// Response resp = sendData(uri, "POST", "application/json; charset=utf-8", request, "Y"); +// setResponse(resp); +// +// DoznVO result = new DoznVO(); +// +// this.logger.debug("res_code:" + resp.res_code); +// this.logger.debug("message:" + resp.message); +// +// result.setResCode(resp.res_code); +// result.setMessage(resp.message); +// +// if ((!(result.getResCode().equals("OK"))) || (!(result.getMessage().equals("성공")))) { +// result.setErrMsg(result.getMessage()); +// } +// +// return result; +// } catch (IOException e) { +// this.logger.error("callBillsInfoUrl {}", e); +// } +// +// return null; +// } +//} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/iup/_legacy/DoznServiceImpl.java b/src/main/java/cokr/xit/ens/biz/iup/_legacy/DoznServiceImpl.java new file mode 100644 index 0000000..d457933 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/_legacy/DoznServiceImpl.java @@ -0,0 +1,300 @@ +//package cokr.xit.biz.iup._legacy; +// +//public class DoznServiceImpl { +// +// +// public DoznVO selectNoticeInfo(String request) +// { +// DoznVO data = this.doznSender.getData(request); +// +// String orgCd = null; +// +// if (data.getParameters() != null) { +// orgCd = (String)data.getParameters().get("some_param"); +// } +// +// DoznVO noticeVO = new DoznVO(); +// String errMsg = null; +// +// String title = this.doznDAO.selectNoticeName(data); +// +// data.setApiType("NOTICE"); +// data.setTbSeq(Integer.valueOf(this.doznDAO.c(data))); +// data.setRequestData(request); +// data.setOrgCd(orgCd); +// data.setParametersJson(); +// try +// { +// this.doznDAO.insertApiRequest(data); +// } catch (Exception e) { +// log.error("insertPayResultInfo : " + e.getMessage()); +// } +// +// if ((orgCd == null) || (orgCd.equals(""))) { +// noticeVO = new DoznVO(); +// noticeVO.setBillerUserKey(data.getBillerUserKey()); +// noticeVO.setApiType("NOTICE"); +// noticeVO.setResCode("E402"); +// noticeVO.setMessage("청구서 조회 결과가 없습니다."); +// noticeVO.setErrMsg("요청받은 값에 기관코드가 없습니다."); +// noticeVO.setTbSeq(data.getTbSeq()); +// +// return noticeVO; +// } +// +// String consignmentYn = this.doznDAO.selectConsignmentYn(orgCd); +// try +// { +// if ((consignmentYn == null) || (consignmentYn.equals(""))) +// throw new Exception("청구서 조회 DB 구분값 미등록"); +// if (consignmentYn.equals("N")) +// noticeVO = this.doznDAO.selectNoticeInfo(data); +// else if (consignmentYn.equals("Y")) { +// noticeVO = this.doznDAO.selectNoticeInfoSn(data); +// } +// +// if (noticeVO == null) +// throw new Exception("청구서 조회 결과가 없습니다."); +// } +// catch (Exception e) +// { +// log.error("selectNoticeInfo : " + e.getMessage()); +// noticeVO = new DoznVO(); +// noticeVO.setBillerUserKey(data.getBillerUserKey()); +// noticeVO.setApiType("NOTICE"); +// noticeVO.setResCode("E402"); +// noticeVO.setMessage("청구서 조회 결과가 없습니다."); +// noticeVO.setErrMsg("청구서 조회 결과가 없습니다."); +// noticeVO.setTbSeq(data.getTbSeq()); +// return noticeVO; +// } +// +// if (noticeVO != null) +// { +// noticeVO.setBillerUserKey(data.getBillerUserKey()); +// noticeVO.setApiType("NOTICE"); +// noticeVO.setResCode("OK"); +// noticeVO.setMessage("성공"); +// noticeVO.setTbSeq(data.getTbSeq()); +// noticeVO.setExpireType("D1"); +// } +// +// if ((title == null) || (title.equals(""))) +// { +// noticeVO = new DoznVO(); +// noticeVO.setBillerUserKey(data.getBillerUserKey()); +// noticeVO.setApiType("NOTICE"); +// noticeVO.setResCode("E402"); +// noticeVO.setMessage("청구서 조회 결과가 없습니다."); +// noticeVO.setErrMsg("청구서 조회 결과가 없습니다."); +// noticeVO.setTbSeq(data.getTbSeq()); +// return noticeVO; +// } +// noticeVO.setTitle(title); +// +// if ((noticeVO.getUserBirth() == null) || (noticeVO.getUserBirth().equals("")) || (!(noticeVO.getUserBirth().equals(data.getUserBirth())))) { +// noticeVO = new DoznVO(); +// noticeVO.setBillerUserKey(data.getBillerUserKey()); +// noticeVO.setApiType("NOTICE"); +// noticeVO.setResCode("E404"); +// noticeVO.setMessage("생년월일이 일치하지 않습니다."); +// noticeVO.setErrMsg("생년월일이 일치하지 않습니다."); +// noticeVO.setTbSeq(data.getTbSeq()); +// return noticeVO; +// } +// +// return noticeVO; +// } +// +// public DoznVO selectPrepayInfo(String request) { +// DoznVO data = this.doznSender.getData(request); +// String orgCd = null; +// DoznVO noticeInfo = null; +// DoznVO prepayVO = null; +// if (data.getParameters() != null) +// orgCd = (String)data.getParameters().get("some_param"); +// data.setApiType("PREPAY"); +// data.setTbSeq(Integer.valueOf(this.doznDAO.selectTbSeq(data))); +// data.setRequestData(request); +// data.setOrgCd(orgCd); +// data.setParametersJson(); +// try { +// this.doznDAO.insertApiRequest(data); +// } catch (Exception e) { +// this.logger.error("selectPrepayInfo : " + e.getMessage()); +// } +// if (orgCd == null || orgCd.equals("")) { +// prepayVO = new DoznVO(); +// prepayVO.setBillerUserKey(data.getBillerUserKey()); +// prepayVO.setApiType("PREPAY"); +// prepayVO.setResCode("E601"); +// prepayVO.setMessage("수납처리실패 - 납부요청 정보 조회 실패"); +// prepayVO.setErrMsg("요청받은 값에 기관코드가 없습니다."); +// prepayVO.setTbSeq(data.getTbSeq()); +// return prepayVO; +// } +// Date now = new Date(); +// SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); +// try { +// String consignmentYn = this.doznDAO.selectConsignmentYn(orgCd); +// if (consignmentYn == null || consignmentYn.equals("")) +// throw new Exception("청구서 조회 DB 구분값 미등록"); +// if (consignmentYn.equals("N")) { +// noticeInfo = this.doznDAO.selectNoticeInfo(data); +// } else if (consignmentYn.equals("Y")) { +// noticeInfo = this.doznDAO.selectNoticeInfoSn(data); +// } +// if (noticeInfo != null) { +// if (consignmentYn.equals("N")) { +// prepayVO = this.doznDAO.selectPrepayInfo(data); +// } else if (consignmentYn.equals("Y")) { +// +// prepayVO = this.doznSender.callBillsInfoUrl(request, this.doznDAO.selectApiUrl(data)); +// prepayVO.setApiType("PREPAY"); +// prepayVO.setTbSeq(data.getTbSeq()); +// return prepayVO; +// } +// } else { +// prepayVO = new DoznVO(); +// prepayVO.setBillerUserKey(data.getBillerUserKey()); +// prepayVO.setApiType("PREPAY"); +// prepayVO.setResCode("E502"); +// prepayVO.setMessage("납부불가 - 납부 대상 없음"); +// prepayVO.setErrMsg("납부대상이 존재하지 않습니다."); +// prepayVO.setTbSeq(data.getTbSeq()); +// this.logger.error("selectPrepayInfo : " + prepayVO.getMessage()); +// return prepayVO; +// } +// +// +// if (prepayVO != null) +// throw new Exception("수납처리실패 - 납부요청 정보 조회 실패"); +// } catch (Exception e) { +// this.logger.error("selectPrepayInfo : " + e.getMessage()); +// prepayVO = new DoznVO(); +// prepayVO.setBillerUserKey(data.getBillerUserKey()); +// prepayVO.setApiType("PREPAY"); +// prepayVO.setResCode("E601"); +// prepayVO.setMessage("수납처리실패 - 납부요청 정보 조회 실패"); +// prepayVO.setErrMsg("수납처리실패 - 납부요청 정보 조회 실패"); +// prepayVO.setTbSeq(data.getTbSeq()); +// return prepayVO; +// } +// +// +// if (prepayVO == null) { +// prepayVO = new DoznVO(); +// prepayVO.setBillerUserKey(data.getBillerUserKey()); +// prepayVO.setApiType("PREPAY"); +// prepayVO.setResCode("OK"); +// prepayVO.setMessage("성공"); +// prepayVO.setTbSeq(data.getTbSeq()); +// } +// if (noticeInfo.getPayExpireDate() != null && +// Integer.parseInt(noticeInfo.getPayExpireDate()) < Integer.parseInt(format.format(now).replace("-", ""))) { +// this.logger.error("selectPrepayInfo - noticeInfo.getPayExpireDate() : " + noticeInfo.getPayExpireDate()); +// prepayVO = new DoznVO(); +// prepayVO.setBillerUserKey(data.getBillerUserKey()); +// prepayVO.setApiType("PREPAY"); +// prepayVO.setResCode("E506"); +// prepayVO.setMessage("납부기한이 경과했습니다."); +// prepayVO.setErrMsg("납부기한이 경과하여 납부가 불가능합니다. 이용기관에 문의하세요"); +// prepayVO.setTbSeq(data.getTbSeq()); +// return prepayVO; +// } +// if (noticeInfo.getAmount() == null || noticeInfo.getAmount().intValue() == 0 || !noticeInfo.getAmount().equals(data.getAmount())) { +// prepayVO.setResCode("E403"); +// prepayVO.setMessage("납부 가능 금액이 없습니다."); +// prepayVO.setErrMsg("고객정보 및 금액이 일치하지 않아 납부가 불가합니다"); +// prepayVO.setTbSeq(data.getTbSeq()); +// return prepayVO; +// } +// return prepayVO; +// } +// +// +// public DoznVO insertPayResultInfo(String request) +// { +// DoznVO resultVO = new DoznVO(); +// +// String orgCd = null; +// DoznVO data = null; +// try +// { +// data = this.doznSender.getData(request); +// if (data.getParameters() != null) +// orgCd = (String)data.getParameters().get("some_param"); +// } +// catch (Exception consignmentYn) +// { +// log.error("FAILED TO PARSE DoznVO : " + request); +// log.error("insertPayResultInfo : " + consignmentYn.getMessage()); +// } +// finally { +// data.setApiType("PAY_RESULT"); +// data.setTbSeq(Integer.valueOf(this.doznDAO.selectTbSeq(data))); +// data.setRequestData(request); +// data.setOrgCd(orgCd); +// data.setParametersJson(); +// try +// { +// this.doznDAO.insertApiRequest(data); +// } catch (Exception e) { +// log.error("insertPayResultInfo : " + e.getMessage()); +// } +// +// resultVO.setBillerUserKey(data.getBillerUserKey()); +// resultVO.setApiType("PAY_RESULT"); +// resultVO.setResCode("OK"); +// resultVO.setMessage("성공"); +// resultVO.setTbSeq(data.getTbSeq()); +// +// if (data.getBillerUserKey().substring(0, 2).equals("EL")) { +// data.setJobSe("2"); +// } +// else { +// data.setJobSe("1"); +// } +// +// this.doznDAO.insertPayResultInfo(data); +// +// String consignmentYn = this.doznDAO.selectConsignmentYn(orgCd); +// if (consignmentYn.equals("Y")) +// { +// try { +// resultVO = this.doznSender.callBillsInfoUrl(request, this.doznDAO.selectApiUrl(data)); +// resultVO.setApiType("PAY_RESULT"); +// resultVO.setTbSeq(data.getTbSeq()); +// } catch (Exception e) { +// log.error("insertPayResultInfo : " + e.getMessage()); +// resultVO.setResCode("SYSERR"); +// resultVO.setMessage(orgCd + "(orgCd) 기관과의 통신 오류"); +// resultVO.setApiType("PAY_RESULT"); +// resultVO.setTbSeq(data.getTbSeq()); +// } +// +// return resultVO; } +// if ((consignmentYn == null) || (consignmentYn.equals(""))) { +// resultVO.setResCode("SYSERR"); +// resultVO.setMessage("위탁업체여부 구분값 미등록"); +// resultVO.setApiType("PAY_RESULT"); +// resultVO.setTbSeq(data.getTbSeq()); +// } +// } +// +// return resultVO; +// } +// +// public String updateApiResponse(DoznVO doznVO) +// { +// doznVO.setResponseData(this.doznSender.simpleResponse(doznVO)); +// try +// { +// this.doznDAO.updateApiResponse(doznVO); +// } catch (Exception e) { +// log.error("insertPayResultInfo : " + e.getMessage()); +// } +// +// return doznVO.getResponseData(); +// } +//} diff --git a/src/main/java/cokr/xit/ens/biz/iup/_legacy/DoznVO.java b/src/main/java/cokr/xit/ens/biz/iup/_legacy/DoznVO.java new file mode 100644 index 0000000..1021918 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/_legacy/DoznVO.java @@ -0,0 +1,450 @@ +package cokr.xit.ens.biz.iup._legacy; + +import java.util.List; +import java.util.Map; + +public class DoznVO +{ + + private String billerUserKey; + private String billedYearMonth; + private String ordinal; + private String billerNoticeKey; + private Map parameters; + private String userBirth; + + + private Integer tbSeq; + private String settlementCode; + private String title; + private Integer amount; + private Integer taxFreeAmount; + private Integer vatAmount; + private String expireType; + private String payExpireDate; + private String secondPayExpireDate; + private String bankCode; + private String accountNo; + private String holderName; + private String senderName; + private String accountType; + private List details; + private String enfrcLevMasterId; + private String enfrcLevRcivId; + private String jobSe; + private Integer detailPasngChrgeSm; + private Integer detailAdiPasngChrgeSm; + private String payBy; + private String payType; + private String payDetail1; + private String payDetail2; + private String payDetail3; + private Integer payAmount; + private String payFeeType; + private String payFee; + private String payFeeTax; + private String adjustDate; + private String paidAt; + private String payId; + private String requestData; + private String responseData; + private String resCode; + private String message; + private String errMsg; + private String orgCd; + private String parametersJson; + private String apiType; + private String crtr; + + public DoznVO() + { + this.taxFreeAmount = null; + + this.vatAmount = null; + + this.crtr = "SYSTEM"; } + + public String getParametersJson() { + return this.parametersJson; + } + + public void setParametersJson() { + this.parametersJson = "{\"some_param\" : \"" + this.orgCd + "\"}"; + } + + public List getDetails() { + return this.details; + } + + public void setDetails(List details) { + this.details = details; + } + + public String getPayId() { + return this.payId; + } + + public void setPayId(String payId) { + this.payId = payId; + } + + public Integer getTbSeq() { + return this.tbSeq; + } + + public void setTbSeq(Integer tbSeq) { + this.tbSeq = tbSeq; + } + + public String getUserBirth() { + return this.userBirth; + } + + public void setUserBirth(String userBirth) { + this.userBirth = userBirth; + } + + public String getSettlementCode() { + return this.settlementCode; + } + + public void setSettlementCode(String settlementCode) { + this.settlementCode = settlementCode; + } + + public String getBillerUserKey() { + return this.billerUserKey; + } + + public void setBillerUserKey(String billerUserKey) { + this.billerUserKey = billerUserKey; + } + + public String getBilledYearMonth() { + return this.billedYearMonth; + } + + public void setBilledYearMonth(String billedYearMonth) { + this.billedYearMonth = billedYearMonth; + } + + public String getOrdinal() { + return this.ordinal; + } + + public void setOrdinal(String ordinal) { + this.ordinal = ordinal; + } + + public String getBillerNoticeKey() { + return this.billerNoticeKey; + } + + public void setBillerNoticeKey(String billerNoticeKey) { + this.billerNoticeKey = billerNoticeKey; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Integer getAmount() { + return this.amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public Integer getTaxFreeAmount() { + return this.taxFreeAmount; + } + + public void setTaxFreeAmount(Integer taxFreeAmount) { + this.taxFreeAmount = taxFreeAmount; + } + + public Integer getVatAmount() { + return this.vatAmount; + } + + public void setVatAmount(Integer vatAmount) { + this.vatAmount = vatAmount; + } + + public String getExpireType() { + return this.expireType; + } + + public void setExpireType(String expireType) { + this.expireType = expireType; + } + + public String getPayExpireDate() { + return this.payExpireDate; + } + + public void setPayExpireDate(String payExpireDate) { + this.payExpireDate = payExpireDate; + } + + public String getSecondPayExpireDate() { + return this.secondPayExpireDate; + } + + public void setSecondPayExpireDate(String secondPayExpireDate) { + this.secondPayExpireDate = secondPayExpireDate; + } + + public Map getParameters() { + return this.parameters; + } + + public void setParameters(Map parameters) { + this.parameters = parameters; + } + + public String getApiType() { + return this.apiType; + } + + public void setApiType(String apiType) { + this.apiType = apiType; + } + + public String getBankCode() { + return this.bankCode; + } + + public void setBankCode(String bankCode) { + this.bankCode = bankCode; + } + + public String getAccountNo() { + return this.accountNo; + } + + public void setAccountNo(String accountNo) { + this.accountNo = accountNo; + } + + public String getHolderName() { + return this.holderName; + } + + public void setHolderName(String holderName) { + this.holderName = holderName; + } + + public String getSenderName() { + return this.senderName; + } + + public void setSenderName(String senderName) { + this.senderName = senderName; + } + + public String getAccountType() { + return this.accountType; + } + + public void setAccountType(String accountType) { + this.accountType = accountType; + } + + public String getEnfrcLevMasterId() { + return this.enfrcLevMasterId; + } + + public void setEnfrcLevMasterId(String enfrcLevMasterId) { + this.enfrcLevMasterId = enfrcLevMasterId; + } + + public String getJobSe() { + return this.jobSe; + } + + public void setJobSe(String jobSe) { + this.jobSe = jobSe; + } + + public Integer getDetailPasngChrgeSm() { + return this.detailPasngChrgeSm; + } + + public void setDetailPasngChrgeSm(Integer detailPasngChrgeSm) { + this.detailPasngChrgeSm = detailPasngChrgeSm; + } + + public Integer getDetailAdiPasngChrgeSm() { + return this.detailAdiPasngChrgeSm; + } + + public void setDetailAdiPasngChrgeSm(Integer detailAdiPasngChrgeSm) { + this.detailAdiPasngChrgeSm = detailAdiPasngChrgeSm; + } + + public String getPayBy() { + return this.payBy; + } + + public void setPayBy(String payBy) { + this.payBy = payBy; + } + + public String getPayType() { + return this.payType; + } + + public void setPayType(String payType) { + this.payType = payType; + } + + public String getPayDetail1() { + return this.payDetail1; + } + + public void setPayDetail1(String payDetail1) { + this.payDetail1 = payDetail1; + } + + public String getPayDetail2() { + return this.payDetail2; + } + + public void setPayDetail2(String payDetail2) { + this.payDetail2 = payDetail2; + } + + public String getPayDetail3() { + return this.payDetail3; + } + + public void setPayDetail3(String payDetail3) { + this.payDetail3 = payDetail3; + } + + public Integer getPayAmount() { + return this.payAmount; + } + + public void setPayAmount(Integer payAmount) { + this.payAmount = payAmount; + } + + public String getPayFeeType() { + return this.payFeeType; + } + + public void setPayFeeType(String payFeeType) { + this.payFeeType = payFeeType; + } + + public String getPayFee() { + return this.payFee; + } + + public void setPayFee(String payFee) { + this.payFee = payFee; + } + + public String getPayFeeTax() { + return this.payFeeTax; + } + + public void setPayFeeTax(String payFeeTax) { + this.payFeeTax = payFeeTax; + } + + public String getAdjustDate() { + return this.adjustDate; + } + + public void setAdjustDate(String adjustDate) { + this.adjustDate = adjustDate; + } + + public String getPaidAt() { + return this.paidAt; + } + + public void setPaidAt(String paidAt) { + this.paidAt = paidAt; + } + + public String getPaidId() { + return this.payId; + } + + public void setPaidId(String paidId) { + this.payId = paidId; + } + + public String getRequestData() { + return this.requestData; + } + + public void setRequestData(String requestData) { + this.requestData = requestData; + } + + public String getResponseData() { + return this.responseData; + } + + public void setResponseData(String responseData) { + this.responseData = responseData; + } + + public String getResCode() { + return this.resCode; + } + + public void setResCode(String resCode) { + this.resCode = resCode; + } + + public String getMessage() { + return this.message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getErrMsg() { + return this.errMsg; + } + + public void setErrMsg(String errMsg) { + this.errMsg = errMsg; + } + + public String getOrgCd() { + return this.orgCd; + } + + public void setOrgCd(String orgCd) { + this.orgCd = orgCd; + } + + public String getEnfrcLevRcivId() { + return this.enfrcLevRcivId; + } + + public void setEnfrcLevRcivId(String enfrcLevRcivId) { + this.enfrcLevRcivId = enfrcLevRcivId; + } + + public String getCrtr() { + return this.crtr; + } + + public void setCrtr(String crtr) { + this.crtr = crtr; + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/api/IupKkoPayUseSysApi.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/api/IupKkoPayUseSysApi.java new file mode 100644 index 0000000..861217a --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/api/IupKkoPayUseSysApi.java @@ -0,0 +1,190 @@ +package cokr.xit.ens.biz.iup.billpay.api; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.code.BillKkoErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoApiRespDTO; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.http.*; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import java.io.IOException; +import java.net.URI; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +@Slf4j +@Component +@Profile({"!local-test"}) +public class IupKkoPayUseSysApi implements IupKkoPayUseSysApiSpec { + + /** + * 고객사별 납부가능조회 API 호출 + * + * @param uri + * @param mParam + * @return + */ + @Override + public BillKkoApiRespDTO callApiByOrg(String uri, Map mParam) { + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + + + StringBuilder url = new StringBuilder(); + url.append(uri); + + String jsonStr = CmmnUtil.toJsonString(mParam); + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers); + + return setResponse(resp, url.toString()); + } + + + /** + * API 호출 응답정보를 IupBillPayRespVO 로 반환 + * + * @param resp + * @return + */ + private BillKkoApiRespDTO setResponse(ResponseEntity resp, String url) { + if (log.isDebugEnabled()) { + StringBuffer sb = new StringBuffer(); + sb.append("\n================================================") + .append("\nKkoBillClientApi.setResponse...") + .append("\n" + resp.getBody()) + .append("\n================================================"); + log.debug(sb.toString()); + } + BillKkoApiRespDTO respVO = null; + try { + if (HttpStatus.OK.equals(resp.getStatusCode())) { + + ObjectMapper mapper = new ObjectMapper(); + Map mResp = mapper.readValue(resp.getBody(), Map.class); + if ("OK".equals(mResp.get("res_code")) || "성공".equals(mResp.get("res_code"))) + respVO = BillKkoApiRespDTO.okBuilder() + .data(null) + .build(); + else + respVO = BillKkoApiRespDTO.errBuilder() + .resCode(String.valueOf(mResp.get("res_code"))) + .message(String.valueOf(mResp.get("message"))) + .build(); + } else { + respVO = BillKkoApiRespDTO.errBuilder() + .resCode(BillKkoErrCd.ERR601.getCode()) + .message(String.format("기관과 통신 실패. [URL]:::%s. [ERROR]:::%s %s.", url, resp.getStatusCode().toString(), resp.getBody())) + .build(); + } + } catch (IOException e) { + respVO = BillKkoApiRespDTO.errBuilder() + .resCode(BillKkoErrCd.ERR505.getCode()) + .message(e.getMessage()) + .build(); + } catch (Exception e) { + respVO = BillKkoApiRespDTO.errBuilder() + .resCode(BillKkoErrCd.ERR999.getCode()) + .message(e.getMessage()) + .build(); + } + + return respVO; + + } + + + /** + *
메소드 설명: API 호출
+     * 
+ * + * @param method + * @param url + * @param body + * @param headers + * @return ResponseEntity 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 4. + * @apiNote: 사이트 참조 https://e2e2e2.tistory.com/15 + */ + private ResponseEntity callApi(HttpMethod method, String url, String body, HttpHeaders headers) { + + StringBuffer sb = new StringBuffer(); + ResponseEntity responseEntity = null; + try { + + HttpEntity entity = null; + UriComponents uri = null; + switch (method) { + case GET: + entity = new HttpEntity<>(headers); + uri = UriComponentsBuilder + .fromHttpUrl(String.format("%s?%s", url, body == null ? "" : body)) +// .encode(StandardCharsets.UTF_8) //"%"기호가 "%25"로 인코딩 발생하여 주석처리 함. + .build(false); + break; + case POST: + entity = new HttpEntity<>(body, headers); + uri = UriComponentsBuilder + .fromHttpUrl(url) + .encode(StandardCharsets.UTF_8) + .build(); + break; + + default: + break; + } + + + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + factory.setConnectTimeout(5000); +// factory.setReadTimeout(3000); +// factory.setReadTimeout(10000); + factory.setReadTimeout(15000); + RestTemplate restTemplate = new RestTemplate(factory); + sb.append("\n url => " + uri.toString()) + .append("\n method => " + method) + .append("\n headers => " + entity.getHeaders().toString()) + .append("\n body => " + entity.getBody()); + responseEntity = restTemplate.exchange(URI.create(uri.toString()), method, entity, String.class); + + /* + * HttpStatus 정보 확인 방법 + * -.코드: responseEntity.getStatusCodeValue() + * -.메시지: responseEntity.getStatusCode() + */ + + } catch (HttpServerErrorException e) { + responseEntity = new ResponseEntity(e.getResponseBodyAsString(), e.getStatusCode()); + log.error("call API 서버오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } catch (HttpClientErrorException e) { + responseEntity = new ResponseEntity(e.getResponseBodyAsString(), e.getStatusCode()); + log.error("call API 클라이언트오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } catch (RestClientException e) { + responseEntity = new ResponseEntity(e.getMessage(), HttpStatus.REQUEST_TIMEOUT); + log.error("RestAPI 호출 오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } catch (Exception e) { + responseEntity = new ResponseEntity(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + log.error("call API 기타오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } finally { + log.info("카카오페이 청구서 Client API\n[ REQUEST ]-----------------------------------------------------------------------\n{}\n[ RESPONSE ]-----------------------------------------------------------------------\n{}", sb.toString(), responseEntity.getBody()); + } + + + return responseEntity; + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/api/IupKkoPayUseSysApiSpec.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/api/IupKkoPayUseSysApiSpec.java new file mode 100644 index 0000000..1ca6393 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/api/IupKkoPayUseSysApiSpec.java @@ -0,0 +1,17 @@ +package cokr.xit.ens.biz.iup.billpay.api; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoApiRespDTO; + +import java.util.Map; + +public interface IupKkoPayUseSysApiSpec { + + /** + * 고객사별 납부가능조회 API 호출 + * + * @param uri + * @param mParam + * @return + */ + BillKkoApiRespDTO callApiByOrg(String uri, Map mParam); +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/api/IupKkoPayUseSysApiTest.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/api/IupKkoPayUseSysApiTest.java new file mode 100644 index 0000000..7819160 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/api/IupKkoPayUseSysApiTest.java @@ -0,0 +1,104 @@ +package cokr.xit.ens.biz.iup.billpay.api; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoApiRespDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.http.*; +import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +@Slf4j +@Component +@Profile({"local-test"}) +public class IupKkoPayUseSysApiTest implements IupKkoPayUseSysApiSpec { + + /** + * 고객사별 납부가능조회 API 호출 + * + * @param uri + * @param mParam + * @return + */ + @Override + public BillKkoApiRespDTO callApiByOrg(String uri, Map mParam) { + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + + + StringBuilder url = new StringBuilder(); + url.append(uri); + + String jsonStr = CmmnUtil.toJsonString(mParam); + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers); + + + return BillKkoApiRespDTO.okBuilder() + .data(null) + .build(); + } + + /** + *
메소드 설명: API 호출
+     * 
+ * + * @param method + * @param url + * @param body + * @param headers + * @return ResponseEntity 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 4. + * @apiNote: 사이트 참조 https://e2e2e2.tistory.com/15 + */ + private ResponseEntity callApi(HttpMethod method, String url, String body, HttpHeaders headers) { + + StringBuffer sb = new StringBuffer(); + ResponseEntity responseEntity = ResponseEntity.ok("test"); + try { + + HttpEntity entity = null; + UriComponents uri = null; + switch (method) { + case GET: + entity = new HttpEntity<>(headers); + uri = UriComponentsBuilder + .fromHttpUrl(String.format("%s?%s", url, body == null ? "" : body)) + .build(false); + break; + case POST: + entity = new HttpEntity<>(body, headers); + uri = UriComponentsBuilder + .fromHttpUrl(url) + .encode(StandardCharsets.UTF_8) + .build(); + break; + + default: + break; + } + + sb.append("\n url => " + uri.toString()) + .append("\n method => " + method) + .append("\n headers => " + entity.getHeaders().toString()) + .append("\n body => " + entity.getBody()); + } catch (Exception e) { + log.error("call API 기타오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } finally { + log.info("카카오페이 청구서 Client API\n[ REQUEST ]-----------------------------------------------------------------------\n{}\n[ RESPONSE ]-----------------------------------------------------------------------\n{}", sb.toString(), responseEntity.getBody()); + } + + + return responseEntity; + } + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/presentation/IupBillKkoPayUseSysController.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/presentation/IupBillKkoPayUseSysController.java new file mode 100644 index 0000000..f83c439 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/presentation/IupBillKkoPayUseSysController.java @@ -0,0 +1,276 @@ +package cokr.xit.ens.biz.iup.billpay.presentation; + +import cokr.xit.ens.biz.iup.billpay.service.IupBillKkoPayUseSysService; +import cokr.xit.ens.biz.iup.domain.TbInputDataXit; +import cokr.xit.ens.biz.iup.domain.repository.TbInputDataXitRepository; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoApiRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +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.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@Tag(name = "IupBillKkoPayUseSysController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class IupBillKkoPayUseSysController { + + private final TbInputDataXitRepository tbInputDataXitRepository; + + private final Map iupBillKkoPayUseSysServiceMap; + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "sample" + , value = "{\n" + + "\"data\": {\n" + + "\"biller_user_key\": \"0000000001\",\n" + + "\"user_birth\":\"19900301\",\n" + + "\"parameters\": {\n" + + "\"some_param\": \"KT00000001\"\n" + + "}\n" + + "}\n" + + "}" + ) + }) + }) + @ApiResponses({ + @ApiResponse(responseCode = "200", content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Success Example..." + , summary = "Success" + , value = "{\n" + + " \"res_code\": \"OK\",\n" + + " \"message\": \"성공\",\n" + + " \"data\": {\n" + + " \"result\": {\n" + + " \"biller_user_key\": \"0000000001\",\n" + + " \"title\": \"통신요금\",\n" + + " \"amount\": 29000,\n" + + " \"tax_free_amount\": 0,\n" + + " \"vat_amount\": 0,\n" + + " \"pay_expire_date\": \"20190801\",\n" + + " \"details\": [\n" + + " {\n" + + " \"title\": \"고객정보\",\n" + + " \"itemType\": \"KEY_VALUE\",\n" + + " \"elements\": [\n" + + " {\n" + + " \"key\": \"이름\",\n" + + " \"value\": \"홍길동\",\n" + + " \"level\": \"1\"\n" + + " },\n" + + " {\n" + + " \"key\": \"고객번호\",\n" + + " \"value\": \"945034260\",\n" + + " \"level\": \"1\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"title\": \"상세내용\",\n" + + " \"itemType\": \"KEY_VALUE\",\n" + + " \"elements\": [\n" + + " {\n" + + " \"key\": \"상품명(서비스번호)\",\n" + + " \"value\": \"모바일(010-61**-*234)\",\n" + + " \"level\": \"1\"\n" + + " },\n" + + " {\n" + + " \"key\": \"당월요금계\",\n" + + " \"value\": \"42,610원\",\n" + + " \"level\": \"1\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + "}" + ), + @ExampleObject(name = "Fail Example..." + , summary = "Fail" + , value = "{\n" + + "\"res_code\": \"E402\",\n" + + "\"message\": \"청구서 조회 결과가 없습니다.\",\n" + + "\"data\": null\n" + + "}" + ) + }) + }) + }) + @Operation(summary = "청구서 조회") + @PostMapping(value = "/iup/kakao/notice", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity kakaoNotice(@RequestBody Map mParam) { + try { + Map data = (Map) mParam.get("data"); + String billerUserKey = (String) data.get("biller_user_key"); + TbInputDataXit tbInputDataXit = tbInputDataXitRepository.findById(billerUserKey).orElseThrow(() -> new RuntimeException("biller_user_key와 일치하는 데이터를 찾을 수 없습니다.")); + IupBillKkoPayUseSysService iupPayProcessService = iupBillKkoPayUseSysServiceMap.get("iupBillKkoPayUseSysService_" + tbInputDataXit.getTbInputXit().getSendType()); + + return new ResponseEntity(iupPayProcessService.findNoticeInfo(mParam), HttpStatus.OK); + + } finally { + + StringBuffer sb = new StringBuffer(); + sb.append("\n==============================================================================") + .append("\n[ kakao 청구서 - 청구서조회 ]") + .append("\n### Request Info...") + .append("\n" + CmmnUtil.toJsonString(mParam)) +// .append("\n### Response Info...") +// .append("\n" + resp.getBody()) + .append("\n=============================================================================="); + log.info(sb.toString()); + } + + + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "sample" + , value = "{\n" + + "\"data\": {\n" + + "\"biller_user_key\": \"0000000001\",\n" + + "\"amount\": 29000,\n" + + "\"parameters\": {\n" + + "\"pay_rqt_seq\": \"KT00000001\"\n" + + "}\n" + + "}\n" + + "}") + }) + }) + @ApiResponses({ + @ApiResponse(responseCode = "200", content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Success Example..." + , summary = "Success" + , value = "{\n" + + "\"res_code\": \"OK\",\n" + + "\"message\": \"성공\",\n" + + "\"data\": null\n" + + "}" + ), + @ExampleObject(name = "Fail Example..." + , summary = "Fail" + , value = "{\n" + + "\"res_code\": \"E502\",\n" + + "\"message\": \"납부불가 - 납부 대상 없음\",\n" + + "\"data\": null\n" + + "}" + ) + }) + }) + }) + @Operation(summary = "납부 가능 조회") + @PostMapping(value = "/iup/kakao/prepay", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity kakaoPrepay(@RequestBody Map mParam) { + try { + Map data = (Map) mParam.get("data"); + String billerUserKey = (String) data.get("biller_user_key"); + TbInputDataXit tbInputDataXit = tbInputDataXitRepository.findById(billerUserKey).orElseThrow(() -> new RuntimeException("biller_user_key와 일치하는 데이터를 찾을 수 없습니다.")); + IupBillKkoPayUseSysService iupBillPayService = iupBillKkoPayUseSysServiceMap.get("iupBillKkoPayUseSysService_" + tbInputDataXit.getTbInputXit().getSendType()); + + return new ResponseEntity(iupBillPayService.findPrepayInfo(mParam), HttpStatus.OK); + + } finally { + + StringBuffer sb = new StringBuffer(); + sb.append("\n==============================================================================") + .append("\n[ kakao 청구서 - 납부가능조회 ]") + .append("\n### Request Info...") + .append("\n" + CmmnUtil.toJsonString(mParam)) +// .append("\n### Response Info...") +// .append("\n" + resp.getBody()) + .append("\n=============================================================================="); + log.info(sb.toString()); + } + + + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "sample" + , value = "{\n" + + "\"data\": {\n" + + "\"biller_user_key\": \"0000000001\",\n" + + "\"parameters\": {\n" + + "\"pay_rqt_seq\": \"KT00000001\"\n" + + "},\n" + + "\"pay_by\": \"MONEY\",\n" + + "\"pay_type\": \"P\",\n" + + "\"pay_detail1\": \"\",\n" + + "\"pay_detail2\": \"\",\n" + + "\"amount\": 20000,\n" + + "\"pay_amount\": 20000,\n" + + "\"pay_fee_type\": \"BEFORE\",\n" + + "\"pay_fee\": 150,\n" + + "\"pay_fee_tax\": 15,\n" + + "\"paid_at\": \"20190220161656\",\n" + + "\"pay_id\": 2748877\n" + + "}\n" + + "}") + }) + }) + @ApiResponses({ + @ApiResponse(responseCode = "200", content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Success Example..." + , summary = "Success" + , value = "{\n" + + "\"res_code\": \"OK\",\n" + + "\"message\": \"성공\",\n" + + "\"data\": null\n" + + "}" + ) + }) + }) + }) + @Operation(summary = "납부 결과 전달") + @PostMapping(value = "/iup/kakao/pay-result", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity kakaoPayResult(@RequestBody Map mParam) { + try { + Map data = (Map) mParam.get("data"); + String billerUserKey = (String) data.get("biller_user_key"); + TbInputDataXit tbInputDataXit = tbInputDataXitRepository.findById(billerUserKey).orElseThrow(() -> new RuntimeException("biller_user_key와 일치하는 데이터를 찾을 수 없습니다.")); + IupBillKkoPayUseSysService iupBillPayService = iupBillKkoPayUseSysServiceMap.get("iupBillKkoPayUseSysService_" + tbInputDataXit.getTbInputXit().getSendType()); + + return new ResponseEntity(iupBillPayService.addPayReultIfno(mParam), HttpStatus.OK); + + } finally { + + StringBuffer sb = new StringBuffer(); + sb.append("\n==============================================================================") + .append("\n[ kakao 청구서 - 납부결과전달 ]") + .append("\n### Request Info...") + .append("\n" + CmmnUtil.toJsonString(mParam)) +// .append("\n### Response Info...") +// .append("\n" + resp.getBody()) + .append("\n=============================================================================="); + log.info(sb.toString()); + } + + } + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/presentation/IupPayUseSysController.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/presentation/IupPayUseSysController.java new file mode 100644 index 0000000..507afd3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/presentation/IupPayUseSysController.java @@ -0,0 +1,135 @@ +package cokr.xit.ens.biz.iup.billpay.presentation; + +import cokr.xit.ens.biz.iup.billpay.service.IupPayUseSysServiceFactory; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.Map; + +@Tag(name = "IupPayUseSysController") +@Slf4j +@RequiredArgsConstructor +@RestController +//public class IupPayUseSysController implements PayUseSysController> { +public class IupPayUseSysController { + + private final IupPayUseSysServiceFactory factory; + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "kkopay(카카오페이)" + , summary = "kkopay(카카오페이)" + , value = "{\"data\":{\"billerUserKey\":\"빌러유저키\"}}") + }) + }) + @Parameters({ + @Parameter(name = "paySe", example = "kkopay", required = true, in = ParameterIn.PATH), + }) + @Operation(summary = "청구서링크생성 정보") + @PostMapping(value = "/iup/bill/{paySe}/gnr/url", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity gnrUrl(@PathVariable String paySe, @RequestBody Map param) { + + if (Arrays.stream(IupPayUseSysServiceFactory.IupPaySe.values()).noneMatch(iupPaySe -> iupPaySe.name().equals(paySe))) + throw new EnsException(EnsErrCd.INVALID_REQUEST_URL, EnsErrCd.INVALID_REQUEST_URL.getCodeNm()); + return new ResponseEntity(factory.getService(IupPayUseSysServiceFactory.IupPaySe.valueOf(paySe)).gnrUrl(param), HttpStatus.OK); + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "kkopay(카카오페이)" + , summary = "kkopay(카카오페이)" + , value = "{\"data\":{\"biller_user_key\":\"빌러유저키\",\"user_birth\":\"\",\"parameters\":{\"some_param\":\"\"}}}"), + @ExampleObject(name = "nvpay(네이버페이)" + , summary = "nvpay(네이버페이)" + , value = "{\"data\":{\"billerUserKey\":\"빌러유저키\"}}") + }) + }) + @Parameters({ + @Parameter(name = "paySe", example = "kkopay", required = true, in = ParameterIn.PATH), + }) + @Operation(summary = "납부(결제)정보") + @PostMapping(value = "/iup/bill/{paySe}/pay/notice", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity payNotice(@PathVariable String paySe, @RequestBody Map param) { + + if (Arrays.stream(IupPayUseSysServiceFactory.IupPaySe.values()).noneMatch(iupPaySe -> iupPaySe.name().equals(paySe))) + throw new EnsException(EnsErrCd.INVALID_REQUEST_URL, EnsErrCd.INVALID_REQUEST_URL.getCodeNm()); + return new ResponseEntity(factory.getService(IupPayUseSysServiceFactory.IupPaySe.valueOf(paySe)).payNotice(param), HttpStatus.OK); + } + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "kkopay(카카오페이)" + , summary = "kkopay(카카오페이)" + , value = "{\"data\":{\"biller_user_key\":\"빌러유저키\",\"amount\":29000,\"parameters\":{\"pay_rqt_seq\":\"KT00000001\"}}}"), + @ExampleObject(name = "nvpay(네이버페이)" + , summary = "nvpay(네이버페이)" + , value = "{\"data\":{\"billerUserKey\":\"빌러유저키\",\"productName\":\"\",\"totalPayAmount\":1000,\"taxScopeAmount\":1000,\"taxExScopeAmount\":null}}") + }) + }) + @Parameters({ + @Parameter(name = "paySe", example = "kkopay", required = true, in = ParameterIn.PATH), + }) + @Operation(summary = "납부(결제)가능여부") + @PostMapping(value = "/iup/bill/{paySe}/pay/able", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity payAble(@PathVariable String paySe, @RequestBody Map param) { + if (Arrays.stream(IupPayUseSysServiceFactory.IupPaySe.values()).noneMatch(iupPaySe -> iupPaySe.name().equals(paySe))) + throw new EnsException(EnsErrCd.INVALID_REQUEST_URL, EnsErrCd.INVALID_REQUEST_URL.getCodeNm()); + return new ResponseEntity(factory.getService(IupPayUseSysServiceFactory.IupPaySe.valueOf(paySe)).payAble(param), HttpStatus.OK); + } + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "kkopay(카카오페이)" + , summary = "kkopay(카카오페이)" + , value = "{\"data\":{\"biller_user_key\":\"빌러유저키\",\"parameters\":{\"pay_rqt_seq\":\"KT00000001\"},\"pay_by\":\"MONEY\",\"pay_type\":\"P\",\"pay_detail1\":\"\",\"pay_detail2\":\"\",\"amount\":20000,\"pay_amount\":20000,\"pay_fee_type\":\"BEFORE\",\"pay_fee\":150,\"pay_fee_tax\":15,\"paid_at\":\"20190220161656\",\"pay_id\":2748877}}"), + @ExampleObject(name = "nvpay(네이버페이)" + , summary = "nvpay(네이버페이)" + , value = "{\"code\":\"Success\",\"message\":\"detail message(optional)\",\"body\":{\"paymentId\":\"네이버페이 결제번호\",\"detail\":{\"productName\":\"샘플상품\",\"merchantId\":\"loginId\",\"merchantName\":\"가맹점명\",\"cardNo\":\"465887**********\",\"admissionYmdt\":\"20170201151722\",\"payHistId\":\"20170201NP1043587781\",\"totalPayAmount\":1000,\"primaryPayAmount\":1000,\"npointPayAmount\":0,\"giftCardAmount\":0,\"taxScopeAmount\":1000,\"taxExScopeAmount\":0,\"environmentDepositAmount\":0,\"primaryPayMeans\":\"CARD\",\"merchantPayKey\":\"청구서UID\",\"merchantUserKey\":\"빌러유저키\",\"cardCorpCode\":\"C0\",\"paymentId\":\"20170201NP1043587746\",\"admissionTypeCode\":\"01\",\"settleExpectAmount\":971,\"payCommissionAmount\":29,\"admissionState\":\"SUCCESS\",\"tradeConfirmYmdt\":\"20170201152510\",\"cardAuthNo\":\"17545616\",\"cardInstCount\":0,\"usedCardPoint\":false,\"bankCorpCode\":\"\",\"bankAccountNo\":\"\",\"settleExpected\":false,\"extraDeduction\":false,\"useCfmYmdt\":\"20180703\"}}}") + }) + }) + @Parameters({ + @Parameter(name = "paySe", example = "kkopay", required = true, in = ParameterIn.PATH), + }) + @Operation(summary = "납부(결제)결과") + @PostMapping(value = "/iup/bill/{paySe}/pay/result", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity payResult(@PathVariable String paySe, @RequestBody Map param) { + + if (Arrays.stream(IupPayUseSysServiceFactory.IupPaySe.values()).noneMatch(iupPaySe -> iupPaySe.name().equals(paySe))) + throw new EnsException(EnsErrCd.INVALID_REQUEST_URL, EnsErrCd.INVALID_REQUEST_URL.getCodeNm()); + return new ResponseEntity(factory.getService(IupPayUseSysServiceFactory.IupPaySe.valueOf(paySe)).payResult(param), HttpStatus.OK); + } + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "nvpay(네이버페이)" + , summary = "nvpay(네이버페이)" + , value = "{\"code\":\"Success\",\"message\":\"detail message(optional)\",\"body\":{\"responseCount\":1,\"totalCount\":1,\"totalPageCount\":1,\"currentPageNumber\":1,\"list\":[{\"cardAuthNo\":\"00000000\",\"bankAccountNo\":\"\",\"bankCorpCode\":\"\",\"paymentId\":\"20170000NP1000229665\",\"cardCorpCode\":\"C0\",\"cardInstCount\":0,\"usedCardPoint\":false,\"settleInfo\":{\"primaryCommissionAmount\":30,\"npointCommissionAmount\":20,\"giftCardCommissionAmount\":0,\"primarySettleAmount\":470,\"npointSettleAmount\":480,\"giftCardSettleAmount\":0,\"totalSettleAmount\":850,\"totalCommissionAmount\":50,\"settleCreated\":true},\"merchantName\":\"나의가맹점\",\"productName\":\"나의상품\",\"payHistId\":\"20170000NP1000229668\",\"merchantId\":\"MID12345\",\"admissionYmdt\":\"20170914163930\",\"tradeConfirmYmdt\":\"20170915163956\",\"totalPayAmount\":1000,\"merchantPayKey\":\"orderKey-91516397\",\"merchantUserKey\":\"빌러유저키\",\"admissionTypeCode\":\"01\",\"primaryPayMeans\":\"CARD\",\"admissionState\":\"SUCCESS\",\"primaryPayAmount\":500,\"npointPayAmount\":500,\"giftCardPayAmount\":0,\"taxScopeAmount\":1000,\"taxExScopeAmount\":0,\"environmentDepositAmount\":0,\"cardNo\":\"123456**********\",\"extraDeduction\":false,\"useCfmYmdt\":\"20180703\"}]}}") + }) + }) + @Parameters({ + @Parameter(name = "paySe", example = "kkopay", required = true, in = ParameterIn.PATH), + }) + @Operation(summary = "결제취소정보") + @PostMapping(value = "/iup/bill/{paySe}/pay/cancel", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity payCancel(@PathVariable String paySe, @RequestBody Map param) { + + if (Arrays.stream(IupPayUseSysServiceFactory.IupPaySe.values()).noneMatch(iupPaySe -> iupPaySe.name().equals(paySe))) + throw new EnsException(EnsErrCd.INVALID_REQUEST_URL, EnsErrCd.INVALID_REQUEST_URL.getCodeNm()); + return new ResponseEntity(factory.getService(IupPayUseSysServiceFactory.IupPaySe.valueOf(paySe)).payCancel(param), HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/IupBillKkoPayUseSysService.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/IupBillKkoPayUseSysService.java new file mode 100644 index 0000000..ac11798 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/IupBillKkoPayUseSysService.java @@ -0,0 +1,191 @@ +package cokr.xit.ens.biz.iup.billpay.service; + +import cokr.xit.ens.biz.iup.domain.VKakaoNoticeInfo; +import cokr.xit.ens.biz.iup.domain.VKakaoNoticeInfoSn; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Component +public abstract class IupBillKkoPayUseSysService { + + @Autowired + private BillHistRepository billHistRepository; + + + /** + * 청구서 이력 저장 - 요청 + * + * @param reqSeCd + * @param billerUserKey + * @param orgCd + * @param mParam + * @return + */ + protected BillHist addBillHistByReqInfo(BillReqSeCd reqSeCd, String billerUserKey, String orgCd, String billUid, Map mParam) { + BillHist billHist = BillHist.builder() + .billSe(BillSeCd.bpKko) + .billUid(billUid) + .reqSe(reqSeCd) + .orgMng(orgCd == null ? null : OrgMng.builder().orgCd(orgCd).build()) + .linkedUuid(billerUserKey) + .requestData(CmmnUtil.toJsonString(mParam)) + .build(); + billHistRepository.save(billHist); + return billHist; + } + + /** + * 청구서 이력 저장 - 응답 + * + * @param billHist + * @param respData + * @param errCd + * @param errMsg + */ + protected void modifyBillHistByRespInfo(BillHist billHist, Object respData, EnsErrCd errCd, String errMsg) { + billHist.setResponseData(CmmnUtil.toJsonString(respData)); + billHist.setError(FieldError.initBuilder() + .errorCode(CmmnUtil.isEmpty(errCd) ? null : errCd.getCode()) + .errorMessage(errMsg) + .build()); + billHistRepository.save(billHist); + } + + /** + * 청구서 조회 + * + * @param mParam + * @return + */ + abstract public BillKkoApiRespDTO findNoticeInfo(Map mParam); + + /** + * 납부 가능 조회 + * + * @param mParam + * @return + */ + abstract public BillKkoApiRespDTO findPrepayInfo(Map mParam); + + /** + * 납부결과 저장 + * + * @param mParam + * @return + */ + abstract public BillKkoApiRespDTO addPayReultIfno(Map mParam); + + + /** + * 청구서조회 "강제징수" 응답메시지 매핑 + * + * @param title + * @param orgMng + * @param vKakaoNoticeInfo + * @return + */ + protected Map respNoticeData(String title, OrgMng orgMng, VKakaoNoticeInfo vKakaoNoticeInfo) { + Map mParam = new HashMap<>(); + mParam.put("biller_user_key", vKakaoNoticeInfo.getEnfrcLevMastrId()); + mParam.put("user_birth ", vKakaoNoticeInfo.getUserBirth()); + mParam.put("amount", vKakaoNoticeInfo.getAmount()); + mParam.put("pay_expire_date", vKakaoNoticeInfo.getPayExpireDate()); + mParam.put("detail_pasng_chrge_sm", vKakaoNoticeInfo.getDetailPasngChrgeSm()); + mParam.put("detail_adi_pasng_chrge_sm", vKakaoNoticeInfo.getDetailAdiPasngChrgeSm()); + return this.makeNoticeData(title, orgMng, mParam); + } + + /** + * 청구서조회 "단순미납" 응답메시지 매핑 + * + * @param title + * @param orgMng + * @param vKakaoNoticeInfoSn + * @return + */ + protected Map respNoticeSnData(String title, OrgMng orgMng, VKakaoNoticeInfoSn vKakaoNoticeInfoSn) { + Map mParam = new HashMap<>(); + mParam.put("biller_user_key", vKakaoNoticeInfoSn.getDataId()); + mParam.put("user_birth", vKakaoNoticeInfoSn.getUserBirth()); + mParam.put("amount", vKakaoNoticeInfoSn.getAmount()); + mParam.put("pay_expire_date", vKakaoNoticeInfoSn.getPayExpireDate()); + mParam.put("detail_pasng_chrge_sm", vKakaoNoticeInfoSn.getDetailPasngChrgeSm()); + mParam.put("detail_adi_pasng_chrge_sm", vKakaoNoticeInfoSn.getDetailAdiPasngChrgeSm()); + return this.makeNoticeData(title, orgMng, mParam); + } + + /** + * 청구서조회 Response 데이터 생성 + * + * @param title + * @param orgMng + * @param mParam + * @return + */ + protected Map makeNoticeData(String title, OrgMng orgMng, Map mParam) { + +// Map bank_accounts = new HashMap<>(); +// bank_accounts.put("bank_code", ""); +// bank_accounts.put("account_no", ""); +// bank_accounts.put("holder_name", ""); +// bank_accounts.put("sender_name", ""); +// bank_accounts.put("account_type", ""); + + + Map result = new HashMap<>(); +// result.put("settlement_code", ""); + result.put("biller_user_key", mParam.get("biller_user_key")); +// result.put("billed_year_month", ""); +// result.put("ordinal", ""); +// result.put("biller_notice_key", ""); + result.put("title", title); + result.put("amount", mParam.get("amount")); +// result.put("tax_free_amount", ""); +// result.put("tax_free_amount", mParam.get("amount")); // 비과세 (카카오에서 답변이 없어서 배포 안함) +// result.put("vat_amount", ""); + result.put("expire_type", "D1"); + result.put("pay_expire_date", mParam.get("pay_expire_date")); +// result.put("second_pay_expire_date", ""); +// result.put("bank_accounts", bank_accounts); + result.put("details", this.makeNoticeDetailsData(mParam)); + + + Map data = new HashMap<>(); + data.put("result", result); + + return data; + } + + /** + * 청구서조회 Response "details" 데이터 생성 + * + * @param mParam + * @return + */ + protected List> makeNoticeDetailsData(Map mParam) { + Map detail = new HashMap<>(); + detail.put("item_type", "TEXT"); + detail.put("elements", Arrays.asList(String.format("상세 통행료: %s", mParam.get("detail_pasng_chrge_sm")) + , String.format("상세 부가통행료: %s", mParam.get("detail_adi_pasng_chrge_sm")))); + + List> details = Arrays.asList(detail); + return details; + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/IupPayUseSysService.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/IupPayUseSysService.java new file mode 100644 index 0000000..9a8a94e --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/IupPayUseSysService.java @@ -0,0 +1,6 @@ +package cokr.xit.ens.biz.iup.billpay.service; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.PayProcessService; + +public interface IupPayUseSysService extends PayProcessService { +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/IupPayUseSysServiceFactory.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/IupPayUseSysServiceFactory.java new file mode 100644 index 0000000..d5288fd --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/IupPayUseSysServiceFactory.java @@ -0,0 +1,32 @@ +package cokr.xit.ens.biz.iup.billpay.service; + +import cokr.xit.ens.biz.iup.billpay.service.impl.IupKkoPayUseSysServiceImpl; +import cokr.xit.ens.biz.iup.billpay.service.impl.IupNvPayUseSysServiceImpl; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class IupPayUseSysServiceFactory { + private final IupKkoPayUseSysServiceImpl iupKkoPayUseSysService; + private final IupNvPayUseSysServiceImpl iupNvPayUseSysService; + + public enum IupPaySe { + kkopay, + nvpay + } + + public IupPayUseSysService getService(IupPaySe iupPaySe) { + switch (iupPaySe) { + case kkopay: + return iupKkoPayUseSysService; + case nvpay: + return iupNvPayUseSysService; + default: + throw new EnsException(EnsErrCd.INVALID_REQUEST_URL, EnsErrCd.INVALID_REQUEST_URL.getCodeNm()); + } + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/impl/IupKkoPayUseSysServiceImpl.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/impl/IupKkoPayUseSysServiceImpl.java new file mode 100644 index 0000000..183e53a --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/impl/IupKkoPayUseSysServiceImpl.java @@ -0,0 +1,86 @@ +package cokr.xit.ens.biz.iup.billpay.service.impl; + +import cokr.xit.ens.biz.iup.billpay.service.IupPayUseSysService; +import cokr.xit.ens.biz.iup.billpay.service.process.IupKkoPayAbleService; +import cokr.xit.ens.biz.iup.billpay.service.process.IupKkoPayNoticeService; +import cokr.xit.ens.biz.iup.billpay.service.process.IupKkoPayResultService; +import cokr.xit.ens.biz.iup.billpay.service.process.IupKkoPayUrlService; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.KkoPayNoticeRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.KkoPayUrlRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.Pay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.template.PayHelper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Map; + + +@Slf4j +@Service +@RequiredArgsConstructor +public class IupKkoPayUseSysServiceImpl implements IupPayUseSysService> { + + private final IupKkoPayUrlService iupKkoPayUrlService; + private final IupKkoPayNoticeService iupKkoPayNoticeService; + private final IupKkoPayAbleService iupKkoPayAbleService; + private final IupKkoPayResultService iupKkoPayResultService; + + @Override + public PayApiRespDTO gnrUrl(Map param) { + Pay> pay = PayHelper., Map, PayApiRespDTO>builder() + .param(param) + .payHelperService(iupKkoPayUrlService) + .build(); + + pay.exec(); + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payNotice(Map param) { + Pay> pay = PayHelper., Map, PayApiRespDTO>builder() + .param(param) + .payHelperService(iupKkoPayNoticeService) + .build(); + + pay.exec(); + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payAble(Map param) { + Pay>> pay = PayHelper., Map, PayApiRespDTO>>builder() + .param(param) + .payHelperService(iupKkoPayAbleService) + .build(); + + pay.exec(); + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payResult(Map param) { + Pay>> pay = PayHelper., Map, PayApiRespDTO>>builder() + .param(param) + .payHelperService(iupKkoPayResultService) + .build(); + + pay.exec(); + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payCancel(Map param) { + return PayApiRespDTO.errBuilder() + .resCode(EnsErrCd.SERVICE_NOT_SUPPORTED.getCode()) + .message(EnsErrCd.SERVICE_NOT_SUPPORTED.getCodeNm()) + .build(); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/impl/IupNvPayUseSysServiceImpl.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/impl/IupNvPayUseSysServiceImpl.java new file mode 100644 index 0000000..a8639bf --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/impl/IupNvPayUseSysServiceImpl.java @@ -0,0 +1,81 @@ +package cokr.xit.ens.biz.iup.billpay.service.impl; + +import cokr.xit.ens.biz.iup.billpay.service.IupPayUseSysService; +import cokr.xit.ens.biz.iup.billpay.service.process.IupNvPayAbleService; +import cokr.xit.ens.biz.iup.billpay.service.process.IupNvPayCancelService; +import cokr.xit.ens.biz.iup.billpay.service.process.IupNvPayNoticeService; +import cokr.xit.ens.biz.iup.billpay.service.process.IupNvPayResultService; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.NvPayNoticeRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.Pay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.template.PayHelper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Map; + + +@Slf4j +@Service +@RequiredArgsConstructor +public class IupNvPayUseSysServiceImpl implements IupPayUseSysService> { + + private final IupNvPayNoticeService iupNvPayNoticeService; + private final IupNvPayAbleService iupNvPayAbleService; + private final IupNvPayResultService iupNvPayResultService; + private final IupNvPayCancelService iupNvPayCancelService; + + @Override + public PayApiRespDTO gnrUrl(Map param) { + return PayApiRespDTO.errBuilder() + .resCode(EnsErrCd.SERVICE_NOT_SUPPORTED.getCode()) + .message(EnsErrCd.SERVICE_NOT_SUPPORTED.getCodeNm()) + .build(); + } + + @Override + public PayApiRespDTO payNotice(Map param) { + Pay> pay = PayHelper., Map, PayApiRespDTO>builder() + .param(param) + .payHelperService(iupNvPayNoticeService) + .build(); + + pay.exec(); + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payAble(Map param) { + Pay>> pay = PayHelper., Map, PayApiRespDTO>>builder() + .param(param) + .payHelperService(iupNvPayAbleService) + .build(); + + pay.exec(); + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payResult(Map param) { + Pay>> pay = PayHelper., Map, PayApiRespDTO>>builder() + .param(param) + .payHelperService(iupNvPayResultService) + .build(); + + pay.exec(); + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payCancel(Map param) { + return PayApiRespDTO.errBuilder() + .resCode(EnsErrCd.SERVICE_NOT_SUPPORTED.getCode()) + .message(EnsErrCd.SERVICE_NOT_SUPPORTED.getCodeNm()) + .build(); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupKkoPayAbleService.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupKkoPayAbleService.java new file mode 100644 index 0000000..c25cd9e --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupKkoPayAbleService.java @@ -0,0 +1,217 @@ +package cokr.xit.ens.biz.iup.billpay.service.process; + +import cokr.xit.ens.biz.iup.domain.*; +import cokr.xit.ens.biz.iup.domain.repository.TbEnfrcLevMastrRepository; +import cokr.xit.ens.biz.iup.domain.repository.TbIupBillPayHistRepository; +import cokr.xit.ens.biz.iup.domain.repository.VKakaoNoticeInfoRepository; +import cokr.xit.ens.biz.iup.domain.repository.VKakaoNoticeInfoSnRepository; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysHisSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PaidTypeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayAbleService; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Service +public class IupKkoPayAbleService implements PayAbleService, Map, PayApiRespDTO>> { + + private final JPAQueryFactory query; + private final VKakaoNoticeInfoSnRepository vKakaoNoticeInfoSnRepository; + private final VKakaoNoticeInfoRepository vKakaoNoticeInfoRepository; + private final TbEnfrcLevMastrRepository tbEnfrcLevMastrRepository; + private final PayUseSysApi payUseSysApi; + private final TbIupBillPayHistRepository tbIupBillPayHistRepository; + private Gson gson = new Gson(); + + private enum DataKeys { + tbInputDataXit, + payApiRespDTO, + responseJsonStr, + } + + @Override + public Map getData(Map reqParam) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + String billerUserKey = (String) reqData.get("biller_user_key"); +// Integer amount = (Integer) reqData.get("amount"); + + if (billerUserKey == null) billerUserKey = ""; + TbInputDataXit tbInputDataXit = query.selectFrom(QTbInputDataXit.tbInputDataXit) + .innerJoin(QTbInputDataXit.tbInputDataXit.tbInputXit, QTbInputXit.tbInputXit).fetchJoin() + .innerJoin(QTbInputXit.tbInputXit.fsJob, QFsJob.fsJob).fetchJoin() + .where(QTbInputDataXit.tbInputDataXit.linkedUuid.eq(billerUserKey)) + .fetchOne(); + + + Map data = new HashMap<>(); + data.put(DataKeys.tbInputDataXit.name(), tbInputDataXit); + return data; + } + + @Override + public void validate(Map reqParam, Map data) { + + if (CmmnUtil.isEmpty(data.get(DataKeys.tbInputDataXit.name()))) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, EnsErrCd.NO_DATA_FOUND.getCodeNm()); + } + + @Override + public void callApi(Map reqParam, Map data) { + TbInputDataXit tbInputDataXit = (TbInputDataXit) data.get(DataKeys.tbInputDataXit.name()); + TbInputXit tbInputXit = tbInputDataXit.getTbInputXit(); + FsJob fsJob = tbInputXit.getFsJob(); + final String dataId = tbInputDataXit.getDataId(); + + if ("Y".equals(fsJob.getBpEntrustYn()) || "y".equals(fsJob.getBpEntrustYn())) { + + final String url = fsJob.getBpKkoPrepayApi(); + + VKakaoNoticeInfoSn vKakaoNoticeInfoSn = vKakaoNoticeInfoSnRepository.findById(dataId) + .orElseThrow(() -> new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 단순미납부과 자료가 없습니다.")); + Optional.of(vKakaoNoticeInfoSn) + .map(entity -> payUseSysApi.payAble(url, reqParam, null)) + .map(response -> checkResponse(response)) + .map(payApiRespDTO -> loadRespData(data, payApiRespDTO)) + .orElseThrow(() -> new EnsException(EnsErrCd.FAILED_CREATE_RESPONSE_DATA, "단순미납 응답데이터 수신에 실패했습니다.")) + ; + } else if ("N".equals(fsJob.getBpEntrustYn()) || "n".equals(fsJob.getBpEntrustYn())) { + if (dataId.length() < 20) + throw new EnsException(EnsErrCd.INVALID_DATA, "데이터ID가 20자리 미만 입니다."); + VKakaoNoticeInfo vKakaoNoticeInfo = vKakaoNoticeInfoRepository.findById(dataId.substring(0, 20)) + .orElseThrow(() -> new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 강제징수부과 자료가 없습니다.")); + Optional.of(vKakaoNoticeInfo) + .map(entity -> validateData(reqParam, entity)); + TbEnfrcLevMastr tbEnfrcLevMastr = tbEnfrcLevMastrRepository.findByEnfrcLevMastrIdAndEnfrcLevMastrProcessSttusAndDeleteAt(dataId.substring(0, 20), "04", "N") + .orElseThrow(() -> new EnsException(EnsErrCd.NO_DATA_FOUND, "납부가능 상태가 아닙니다.", PayUseSysResCd.NO_TARGET_PAYABLE)); + Optional.of(tbEnfrcLevMastr) + .map(entity -> createRespData()) + .map(payApiRespDTO -> loadRespData(data, payApiRespDTO)) + .orElseThrow(() -> new EnsException(EnsErrCd.FAILED_CREATE_RESPONSE_DATA, "강제징수 응답데이터 생성에 실패했습니다.")); + } else { + throw new EnsException(EnsErrCd.INVALID_DATA, "위탁여부가 등록되지 않았습니다."); + } + + } + + private PayApiRespDTO> checkResponse(ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + PayApiRespDTO> result = null; + try { + result = gson.fromJson(response.getBody(), PayApiRespDTO.class); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RESPONSE, EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + } + + return result; + } + + private PayApiRespDTO loadRespData(Map data, PayApiRespDTO payApiRespDTO) { + if (CmmnUtil.isEmpty(payApiRespDTO)) + return null; + + data.put(DataKeys.payApiRespDTO.name(), payApiRespDTO); + data.put(DataKeys.responseJsonStr.name(), gson.toJson(payApiRespDTO)); + return payApiRespDTO; + } + + private VKakaoNoticeInfo validateData(Map reqParam, VKakaoNoticeInfo vKakaoNoticeInfo) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + + final Integer amount = (Integer) reqData.getOrDefault("amount", 0); + if (amount != Integer.parseInt(vKakaoNoticeInfo.getAmount())) + throw new EnsException(EnsErrCd.INVALID_DATA + , String.format("납부 가능 금액이 없거나 일치하지 않습니다. (요청금액:%s, 실제금액:%s)", amount, vKakaoNoticeInfo.getAmount()) + , PayUseSysResCd.NO_AMOUNT_PAYABLE); + if (amount > Integer.parseInt(vKakaoNoticeInfo.getAmount())) + throw new EnsException(EnsErrCd.INVALID_DATA + , String.format("납부 가능 금액을 초과했습니다. (요청금액:%s, 실제금액:%s)", amount, vKakaoNoticeInfo.getAmount()) + , PayUseSysResCd.OVERPAYABLE_AMOUNT); + if (CmmnUtil.isEmpty(vKakaoNoticeInfo.getPayExpireDate())) + throw new EnsException(EnsErrCd.INVALID_DATA + , "납부기한의 값이 비어있습니다." + , PayUseSysResCd.EXPIRED_DATE); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); + if (Integer.parseInt(vKakaoNoticeInfo.getPayExpireDate()) < Integer.parseInt(simpleDateFormat.format(new Date()))) + throw new EnsException(EnsErrCd.INVALID_DATA + , "납부기한이 경과한 자료 입니다." + , PayUseSysResCd.EXPIRED_DATE); + + return vKakaoNoticeInfo; + } + + private PayApiRespDTO createRespData() { + return PayApiRespDTO.okBuilder().build(); + } + + + @Override + public PayApiRespDTO> generateResult(Map reqParam, Map data, EnsException e) { + if (e == null) { + PayApiRespDTO payApiRespDTO = (PayApiRespDTO) data.get(DataKeys.payApiRespDTO.name()); + return gson.fromJson(gson.toJson(payApiRespDTO), PayApiRespDTO.class); + + } else { + if (e.getData() != null && e.getData() instanceof PayUseSysResCd) { + PayUseSysResCd resCode = (PayUseSysResCd) e.getData(); + return PayApiRespDTO.>errBuilder() + .resCode(resCode.getCode()) + .message(resCode.getCodeNm()) + .build(); + } else { + return PayApiRespDTO.>errBuilder() + .resCode(PayUseSysResCd.FAILED_CHECK_INFO.getCode()) + .message(PayUseSysResCd.FAILED_CHECK_INFO.getCodeNm()) + .build(); + } + } + } + + @Override + public void saveHist(Map reqParam, Map data, EnsException e) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + String billerUserKey = (String) reqData.get("biller_user_key"); + + String errorCode = null; + String errorMessage = null; + if (e != null) { + errorCode = e.getErrCd().getCode(); + errorMessage = String.format("%s %s", e.getMessage(), CmmnUtil.printStackTraceToString(e)); + } + + TbIupBillPayHist tbIupBillPayHist = TbIupBillPayHist.builder() + .dataId(billerUserKey) + .paidType(PaidTypeCd.kakaoPay) + .hisSeCd(PayUseSysHisSeCd.payAble) + .requestData(gson.toJson(reqParam)) + .responseData((String) data.get(DataKeys.responseJsonStr.name())) + .error(FieldError.initBuilder() + .errorCode(errorCode) + .errorMessage(errorMessage) + .build()) + .build(); + tbIupBillPayHistRepository.save(tbIupBillPayHist); + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupKkoPayNoticeService.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupKkoPayNoticeService.java new file mode 100644 index 0000000..25be927 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupKkoPayNoticeService.java @@ -0,0 +1,227 @@ +package cokr.xit.ens.biz.iup.billpay.service.process; + +import cokr.xit.ens.biz.iup.domain.*; +import cokr.xit.ens.biz.iup.domain.repository.TbIupBillPayHistRepository; +import cokr.xit.ens.biz.iup.domain.repository.VKakaoNoticeInfoRepository; +import cokr.xit.ens.biz.iup.domain.repository.VKakaoNoticeInfoSnRepository; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.KkoPayNoticeRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysHisSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PaidTypeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayNoticeService; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Slf4j +@RequiredArgsConstructor +@Service +public class IupKkoPayNoticeService implements PayNoticeService, Map, PayApiRespDTO> { + + private final JPAQueryFactory query; + private final VKakaoNoticeInfoSnRepository vKakaoNoticeInfoSnRepository; + private final VKakaoNoticeInfoRepository vKakaoNoticeInfoRepository; + private final TbIupBillPayHistRepository tbIupBillPayHistRepository; + private Gson gson = new Gson(); + + private enum DataKeys { + tbInputDataXit, + kkoPayNoticeRespData, + responseJsonStr, + } + + private enum PayDataKeys { + billerUserKey, + userBirth, + amount, + payExpireDate, + detailPasngChrgeSm, + detailAdiPasngChrgeSm, + } + + @Override + public Map getData(Map reqParam) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + String billerUserKey = (String) reqData.get("biller_user_key"); + + if (billerUserKey == null) billerUserKey = ""; + TbInputDataXit tbInputDataXit = query.selectFrom(QTbInputDataXit.tbInputDataXit) + .innerJoin(QTbInputDataXit.tbInputDataXit.tbInputXit, QTbInputXit.tbInputXit).fetchJoin() + .innerJoin(QTbInputXit.tbInputXit.fsJob, QFsJob.fsJob).fetchJoin() + .where(QTbInputDataXit.tbInputDataXit.linkedUuid.eq(billerUserKey)) + .fetchOne(); + + + Map data = new HashMap<>(); + data.put(DataKeys.tbInputDataXit.name(), tbInputDataXit); + return data; + } + + @Override + public void validate(Map reqParam, Map data) { + + if (CmmnUtil.isEmpty(data.get(DataKeys.tbInputDataXit.name()))) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, EnsErrCd.NO_DATA_FOUND.getCodeNm()); + } + + @Override + public void callApi(Map reqParam, Map data) { + TbInputDataXit tbInputDataXit = (TbInputDataXit) data.get(DataKeys.tbInputDataXit.name()); + TbInputXit tbInputXit = tbInputDataXit.getTbInputXit(); + FsJob fsJob = tbInputXit.getFsJob(); + final String dataId = tbInputDataXit.getDataId(); + + if ("Y".equals(fsJob.getBpEntrustYn()) || "y".equals(fsJob.getBpEntrustYn())) { + VKakaoNoticeInfoSn vKakaoNoticeInfoSn = vKakaoNoticeInfoSnRepository.findById(dataId) + .orElseThrow(() -> new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 단순미납부과 자료가 없습니다.")); + Optional.of(vKakaoNoticeInfoSn) + .map(entity -> toDataMap(entity)) + .map(payData -> validateData(reqParam, payData)) + .map(payData -> createRespData(tbInputDataXit, payData)) + .map(kkoPayNoticeRespData -> loadRespData(data, kkoPayNoticeRespData)) + .orElseThrow(() -> new EnsException(EnsErrCd.FAILED_CREATE_RESPONSE_DATA, "단순미납 응답데이터 생성에 실패했습니다.")) + ; + } else if ("N".equals(fsJob.getBpEntrustYn()) || "n".equals(fsJob.getBpEntrustYn())) { + if (dataId.length() < 20) + throw new EnsException(EnsErrCd.INVALID_DATA, "데이터ID가 20자리 미만 입니다."); + VKakaoNoticeInfo vKakaoNoticeInfo = vKakaoNoticeInfoRepository.findById(dataId.substring(0, 20)) + .orElseThrow(() -> new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 강제징수부과 자료가 없습니다.")); + Optional.of(vKakaoNoticeInfo) + .map(entity -> toDataMap(entity)) + .map(map -> validateData(reqParam, map)) + .map(map -> createRespData(tbInputDataXit, map)) + .map(kkoPayNoticeRespData -> loadRespData(data, kkoPayNoticeRespData)) + .orElseThrow(() -> new EnsException(EnsErrCd.FAILED_CREATE_RESPONSE_DATA, "강제징수 응답데이터 생성에 실패했습니다.")) + ; + } else { + throw new EnsException(EnsErrCd.INVALID_DATA, "위탁여부가 등록되지 않았습니다."); + } + + + } + + private Map toDataMap(VKakaoNoticeInfoSn vKakaoNoticeInfoSn) { + Map payData = new HashMap<>(); + payData.put(PayDataKeys.billerUserKey, vKakaoNoticeInfoSn.getDataId()); + payData.put(PayDataKeys.userBirth, vKakaoNoticeInfoSn.getUserBirth()); + payData.put(PayDataKeys.amount, vKakaoNoticeInfoSn.getAmount().intValue()); + payData.put(PayDataKeys.payExpireDate, vKakaoNoticeInfoSn.getPayExpireDate()); + payData.put(PayDataKeys.detailPasngChrgeSm, vKakaoNoticeInfoSn.getDetailPasngChrgeSm()); + payData.put(PayDataKeys.detailAdiPasngChrgeSm, vKakaoNoticeInfoSn.getDetailAdiPasngChrgeSm()); + return payData; + } + + private Map toDataMap(VKakaoNoticeInfo vKakaoNoticeInfo) { + Map payData = new HashMap<>(); + payData.put(PayDataKeys.billerUserKey, vKakaoNoticeInfo.getEnfrcLevMastrId()); + payData.put(PayDataKeys.userBirth, vKakaoNoticeInfo.getUserBirth()); + payData.put(PayDataKeys.amount, Integer.parseInt(vKakaoNoticeInfo.getAmount())); + payData.put(PayDataKeys.payExpireDate, vKakaoNoticeInfo.getPayExpireDate()); + payData.put(PayDataKeys.detailPasngChrgeSm, vKakaoNoticeInfo.getDetailPasngChrgeSm()); + payData.put(PayDataKeys.detailAdiPasngChrgeSm, vKakaoNoticeInfo.getDetailAdiPasngChrgeSm()); + return payData; + } + + private Map validateData(Map reqParam, Map payData) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + + String userBirth = (String) reqData.getOrDefault("user_birth", ""); + if (!userBirth.equals(payData.get(PayDataKeys.userBirth))) + throw new EnsException(EnsErrCd.INVALID_DATA, String.format("요청과 실제 생년월일이 일치하지 않습니다. (요청: %s 실제: %s)", userBirth, payData.get(PayDataKeys.userBirth))); + + return payData; + } + + + private KkoPayNoticeRespData createRespData(TbInputDataXit tbInputDataXit, Map payData) { + + Map detail = new HashMap<>(); + detail.put("item_type", "TEXT"); + detail.put("elements", Arrays.asList(String.format("상세 통행료: %s", payData.get(PayDataKeys.detailPasngChrgeSm)) + , String.format("상세 부가통행료: %s", payData.get(PayDataKeys.detailAdiPasngChrgeSm)))); + List> details = Arrays.asList(detail); + + return KkoPayNoticeRespData.builder() + .title(tbInputDataXit.getTbInputXit().getFsJob().getJobName()) + .amount((Integer) payData.get(PayDataKeys.amount)) + .expireType("D1") + .payExpireDate((String) payData.get(PayDataKeys.payExpireDate)) + .details(details) + .build(); + } + + private KkoPayNoticeRespData loadRespData(Map data, KkoPayNoticeRespData kkoPayNoticeRespData) { + if (CmmnUtil.isEmpty(kkoPayNoticeRespData)) + return null; + + data.put(DataKeys.kkoPayNoticeRespData.name(), kkoPayNoticeRespData); + data.put(DataKeys.responseJsonStr.name(), gson.toJson(kkoPayNoticeRespData)); + return kkoPayNoticeRespData; + } + + + @Override + public PayApiRespDTO generateResult(Map reqParam, Map data, EnsException e) { + if (e == null) { + KkoPayNoticeRespData kkoPayNoticeRespData = (KkoPayNoticeRespData) data.get(DataKeys.kkoPayNoticeRespData.name()); + return PayApiRespDTO.okBuilder() + .data(kkoPayNoticeRespData) + .build(); + + } else { + String resCode = null; + String message = null; + switch (e.getErrCd()) { + case NO_DATA_FOUND: + resCode = PayUseSysResCd.NOT_FOUND_PAYDATA.getCode(); + message = PayUseSysResCd.NOT_FOUND_PAYDATA.getCodeNm(); + break; + default: + resCode = PayUseSysResCd.PAYDATA_FIND_FAILED.getCode(); + message = PayUseSysResCd.PAYDATA_FIND_FAILED.getCodeNm(); + break; + } + + return PayApiRespDTO.errBuilder() + .resCode(resCode) + .message(message) + .build(); + } + } + + @Override + public void saveHist(Map reqParam, Map data, EnsException e) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + String billerUserKey = (String) reqData.get("biller_user_key"); + + String errorCode = null; + String errorMessage = null; + if (e != null) { + errorCode = e.getErrCd().getCode(); + errorMessage = String.format("%s %s", e.getMessage(), CmmnUtil.printStackTraceToString(e)); + } + + TbIupBillPayHist tbIupBillPayHist = TbIupBillPayHist.builder() + .dataId(billerUserKey) + .paidType(PaidTypeCd.kakaoPay) + .hisSeCd(PayUseSysHisSeCd.payNotice) + .requestData(gson.toJson(reqParam)) + .responseData((String) data.get(DataKeys.responseJsonStr.name())) + .error(FieldError.initBuilder() + .errorCode(errorCode) + .errorMessage(errorMessage) + .build()) + .build(); + tbIupBillPayHistRepository.save(tbIupBillPayHist); + + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupKkoPayResultService.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupKkoPayResultService.java new file mode 100644 index 0000000..b9dacb5 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupKkoPayResultService.java @@ -0,0 +1,191 @@ +package cokr.xit.ens.biz.iup.billpay.service.process; + +import cokr.xit.ens.biz.iup.domain.*; +import cokr.xit.ens.biz.iup.domain.repository.TbIupBillPayHistRepository; +import cokr.xit.ens.biz.iup.domain.repository.TbKakaoPayResultRepository; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.KkoPayResultReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysHisSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PaidTypeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayResultService; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Service +public class IupKkoPayResultService implements PayResultService, Map, PayApiRespDTO>> { + + private final JPAQueryFactory query; + private final PayUseSysApi payUseSysApi; + private final TbKakaoPayResultRepository tbKakaoPayResultRepository; + private final TbIupBillPayHistRepository tbIupBillPayHistRepository; + + private Gson gson = new Gson(); + + private enum DataKeys { + tbInputDataXit, + responseJsonStr, + } + + @Override + public Map getData(Map reqParam) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + String billerUserKey = (String) reqData.get("biller_user_key"); + + if (billerUserKey == null) billerUserKey = ""; + TbInputDataXit tbInputDataXit = query.selectFrom(QTbInputDataXit.tbInputDataXit) + .innerJoin(QTbInputDataXit.tbInputDataXit.tbInputXit, QTbInputXit.tbInputXit).fetchJoin() + .innerJoin(QTbInputXit.tbInputXit.fsJob, QFsJob.fsJob).fetchJoin() + .where(QTbInputDataXit.tbInputDataXit.linkedUuid.eq(billerUserKey)) + .fetchOne(); + + + Map data = new HashMap<>(); + data.put(DataKeys.tbInputDataXit.name(), tbInputDataXit); + return data; + } + + @Override + public void validate(Map reqParam, Map data) { + + if (CmmnUtil.isEmpty(data.get(DataKeys.tbInputDataXit.name()))) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, EnsErrCd.NO_DATA_FOUND.getCodeNm()); + } + + @Override + public void callApi(Map reqParam, Map data) { + TbInputDataXit tbInputDataXit = (TbInputDataXit) data.get(DataKeys.tbInputDataXit.name()); + TbInputXit tbInputXit = tbInputDataXit.getTbInputXit(); + FsJob fsJob = tbInputXit.getFsJob(); + + final String url = fsJob.getBpKkoPayresultApi(); + + + Optional.ofNullable(gson.fromJson(gson.toJson(reqParam.get("data")), KkoPayResultReqData.class)) + .map(kkoPayResultReqData -> toEntity(kkoPayResultReqData)) + .map(entity -> savePayResult(entity)) + .map(entity -> tbInputDataXit) + .filter(detail -> "Y".equals(detail.getTbInputXit().getFsJob())) + .map(vKakaoNoticeInfoSn -> payUseSysApi.payResult(url, reqParam, null)) + .map(response -> loadRespData(data, response)) + .map(response -> checkResponse(response)) + ; + + } + + private TbKakaoPayResult toEntity(KkoPayResultReqData kkoPayResultReqData) { + + + final String jobSe = "EL".equals(kkoPayResultReqData.getBillerUserKey().substring(0, 2)) ? "2" : "1"; + + + final String payAmount = CmmnUtil.isEmpty(kkoPayResultReqData.getPayAmount()) ? null : String.valueOf(kkoPayResultReqData.getPayAmount()); + final String payFee = CmmnUtil.isEmpty(kkoPayResultReqData.getPayFee()) ? null : String.valueOf(kkoPayResultReqData.getPayFee()); + final String payFeeTax = CmmnUtil.isEmpty(kkoPayResultReqData.getPayFeeTax()) ? null : String.valueOf(kkoPayResultReqData.getPayFeeTax()); + final String payId = CmmnUtil.isEmpty(kkoPayResultReqData.getPayId()) ? null : String.valueOf(kkoPayResultReqData.getPayId()); + + return TbKakaoPayResult.builder() + .dataId(kkoPayResultReqData.getBillerUserKey()) + .jobSe(jobSe) + .payMn(kkoPayResultReqData.getPayBy()) + .payTy(kkoPayResultReqData.getPayType()) + .payDetail1(kkoPayResultReqData.getPayDetail1()) + .payDetail2(kkoPayResultReqData.getPayDetail2()) + .payDetail3(kkoPayResultReqData.getPayDetail3()) + .payAmount(payAmount) + .payFeeTy(kkoPayResultReqData.getPayFeeType()) + .payFeeAmount(payFee) + .payFeeVat(payFeeTax) + .excclcPrearngeDe(kkoPayResultReqData.getAdjustDate()) + .payDt(kkoPayResultReqData.getPaidAt()) + .payId(payId) + .payResultProcessSttus("0") +// .creatDt() + .crtr("ENS_SYS") +// .updtDt() +// .updusr() + .build(); + + } + + private TbKakaoPayResult savePayResult(TbKakaoPayResult entity) { + tbKakaoPayResultRepository.save(entity); + return entity; + } + + private ResponseEntity loadRespData(Map data, ResponseEntity response) { + data.put(DataKeys.responseJsonStr.name(), response.getBody()); + return response; + } + + private PayApiRespDTO> checkResponse(ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + PayApiRespDTO> result = null; + try { + result = gson.fromJson(response.getBody(), PayApiRespDTO.class); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RESPONSE, EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + } + + return result; + } + + @Override + public PayApiRespDTO> generateResult(Map reqParam, Map data, EnsException e) { + if (e == null) { + return PayApiRespDTO.>okBuilder().build(); + + } else { + return PayApiRespDTO.>errDataBuilder() + .resCode(PayUseSysResCd.FAILED_SAVE_PAYRSLT.getCode()) + .message(PayUseSysResCd.FAILED_SAVE_PAYRSLT.getCodeNm()) + .data(null) + .build(); + } + } + + @Override + public void saveHist(Map reqParam, Map data, EnsException e) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + String billerUserKey = (String) reqData.get("biller_user_key"); + + String errorCode = null; + String errorMessage = null; + if (e != null) { + errorCode = e.getErrCd().getCode(); + errorMessage = String.format("%s %s", e.getMessage(), CmmnUtil.printStackTraceToString(e)); + } + + TbIupBillPayHist tbIupBillPayHist = TbIupBillPayHist.builder() + .dataId(billerUserKey) + .paidType(PaidTypeCd.kakaoPay) + .hisSeCd(PayUseSysHisSeCd.payResult) + .requestData(gson.toJson(reqParam)) + .responseData((String) data.get(DataKeys.responseJsonStr.name())) + .error(FieldError.initBuilder() + .errorCode(errorCode) + .errorMessage(errorMessage) + .build()) + .build(); + tbIupBillPayHistRepository.save(tbIupBillPayHist); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupKkoPayUrlService.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupKkoPayUrlService.java new file mode 100644 index 0000000..7d9f94f --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupKkoPayUrlService.java @@ -0,0 +1,147 @@ +package cokr.xit.ens.biz.iup.billpay.service.process; + +import cokr.xit.ens.biz.iup.domain.*; +import cokr.xit.ens.biz.iup.domain.repository.TbIupBillPayHistRepository; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.CustomUrl; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.KkoPayUrlRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PaidTypeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysHisSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayUrlService; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Service +public class IupKkoPayUrlService implements PayUrlService, Map, PayApiRespDTO> { + + private final JPAQueryFactory query; + private final TbIupBillPayHistRepository tbIupBillPayHistRepository; + + private Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + @Value("${contract.kakao.pay.bill.dozn.api.validate.host}") + private String BILL_HOST; + @Value("${contract.kakao.pay.bill.dozn.api.validate.notice}") + private String BILL_NOTICE_URL; + @Value("${contract.kakao.pay.bill.dozn.api.validate.prepay}") + private String BILL_PREPAY_URL; + @Value("${contract.kakao.pay.bill.dozn.api.validate.payresult}") + private String BILL_PAYREUSLT_URL; + + + private enum DataKeys { + tbInputDataXit, + responseJsonStr, + } + + @Override + public Map getData(Map reqParam) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + final String billerUserKey = (String) reqData.getOrDefault("billerUserKey", ""); + + TbInputDataXit tbInputDataXit = query.selectFrom(QTbInputDataXit.tbInputDataXit) + .innerJoin(QTbInputDataXit.tbInputDataXit.tbInputXit, QTbInputXit.tbInputXit).fetchJoin() + .innerJoin(QTbInputXit.tbInputXit.fsJob, QFsJob.fsJob).fetchJoin() + .where(QTbInputDataXit.tbInputDataXit.linkedUuid.eq(billerUserKey)) + .fetchOne(); + + Map data = new HashMap<>(); + data.put(DataKeys.tbInputDataXit.name(), tbInputDataXit); + return data; + } + + @Override + public void validate(Map reqParam, Map data) { + + if (CmmnUtil.isEmpty(data.get(DataKeys.tbInputDataXit.name()))) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, EnsErrCd.NO_DATA_FOUND.getCodeNm()); + } + + @Override + public void callApi(Map reqParam, Map data) { + Optional.ofNullable(createRespData(data)) + .map(kkoPayUrlRespData -> loadRespData(data, kkoPayUrlRespData)); + } + + + private KkoPayUrlRespData createRespData(Map data) { + TbInputDataXit tbInputDataXit = (TbInputDataXit) data.get(DataKeys.tbInputDataXit.name()); + return KkoPayUrlRespData.builder() + .billedYearMonth(null) + .ordinal(null) + .expireAt(tbInputDataXit.getTbInputXit().getPayExpiresDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .parameters(null) + .customUrl(CustomUrl.builder() + .noticeUrl(this.BILL_HOST + this.BILL_NOTICE_URL) + .prepayUrl(this.BILL_HOST + this.BILL_PREPAY_URL) + .payResultUrl(this.BILL_HOST + this.BILL_PAYREUSLT_URL) + .build()) + .build(); + + } + + private Map loadRespData(Map data, KkoPayUrlRespData kkoPayUrlRespData) { + + data.put(DataKeys.responseJsonStr.name(), gson.toJson(kkoPayUrlRespData)); + return data; + } + + + @Override + public PayApiRespDTO generateResult(Map reqParam, Map data, EnsException e) { + if (e == null) { + KkoPayUrlRespData kkoPayUrlRespData = gson.fromJson((String) data.get(DataKeys.responseJsonStr.name()), KkoPayUrlRespData.class); + return PayApiRespDTO.okBuilder() + .data(kkoPayUrlRespData) + .build(); + + } else { + return PayApiRespDTO.errBuilder() + .resCode(PayUseSysResCd.GRNURL_FIND_FAILED.getCode()) + .message(PayUseSysResCd.GRNURL_FIND_FAILED.getCodeNm()) + .build(); + } + } + + @Override + public void saveHist(Map reqParam, Map data, EnsException e) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + final String billerUserKey = (String) reqData.getOrDefault("billerUserKey", ""); + + String errorCode = null; + String errorMessage = null; + if (e != null) { + errorCode = e.getErrCd().getCode(); + errorMessage = String.format("%s %s", e.getMessage(), CmmnUtil.printStackTraceToString(e)); + } + + TbIupBillPayHist tbIupBillPayHist = TbIupBillPayHist.builder() + .dataId(billerUserKey) + .paidType(PaidTypeCd.kakaoPay) + .hisSeCd(PayUseSysHisSeCd.gnrUrl) + .requestData(gson.toJson(reqParam)) + .responseData((String) data.get(DataKeys.responseJsonStr.name())) + .error(FieldError.initBuilder() + .errorCode(errorCode) + .errorMessage(errorMessage) + .build()) + .build(); + tbIupBillPayHistRepository.save(tbIupBillPayHist); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupNvPayAbleService.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupNvPayAbleService.java new file mode 100644 index 0000000..72266d6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupNvPayAbleService.java @@ -0,0 +1,224 @@ +package cokr.xit.ens.biz.iup.billpay.service.process; + +import cokr.xit.ens.biz.iup.domain.*; +import cokr.xit.ens.biz.iup.domain.repository.TbEnfrcLevMastrRepository; +import cokr.xit.ens.biz.iup.domain.repository.TbIupBillPayHistRepository; +import cokr.xit.ens.biz.iup.domain.repository.VKakaoNoticeInfoRepository; +import cokr.xit.ens.biz.iup.domain.repository.VKakaoNoticeInfoSnRepository; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysHisSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PaidTypeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayAbleService; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Service +public class IupNvPayAbleService implements PayAbleService, Map, PayApiRespDTO>> { + + private final JPAQueryFactory query; + private final VKakaoNoticeInfoSnRepository vKakaoNoticeInfoSnRepository; + private final VKakaoNoticeInfoRepository vKakaoNoticeInfoRepository; + private final TbEnfrcLevMastrRepository tbEnfrcLevMastrRepository; + private final PayUseSysApi payUseSysApi; + private final TbIupBillPayHistRepository tbIupBillPayHistRepository; + private Gson gson = new Gson(); + + private enum DataKeys { + tbInputDataXit, + payApiRespDTO, + responseJsonStr, + } + + @Override + public Map getData(Map reqParam) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + String billerUserKey = (String) reqData.get("billerUserKey"); +// String productName = (String) reqData.get("productName"); +// Integer totalPayAmount = (Integer) reqData.get("totalPayAmount"); +// Integer taxScopeAmount = (Integer) reqData.get("taxScopeAmount"); +// Integer taxExScopeAmount = (Integer) reqData.get("taxExScopeAmount"); + + if (billerUserKey == null) billerUserKey = ""; + TbInputDataXit tbInputDataXit = query.selectFrom(QTbInputDataXit.tbInputDataXit) + .innerJoin(QTbInputDataXit.tbInputDataXit.tbInputXit, QTbInputXit.tbInputXit).fetchJoin() + .innerJoin(QTbInputXit.tbInputXit.fsJob, QFsJob.fsJob).fetchJoin() + .where(QTbInputDataXit.tbInputDataXit.linkedUuid.eq(billerUserKey)) + .fetchOne(); + + + Map data = new HashMap<>(); + data.put(DataKeys.tbInputDataXit.name(), tbInputDataXit); + return data; + } + + @Override + public void validate(Map reqParam, Map data) { + + if (CmmnUtil.isEmpty(data.get(DataKeys.tbInputDataXit.name()))) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, EnsErrCd.NO_DATA_FOUND.getCodeNm()); + } + + @Override + public void callApi(Map reqParam, Map data) { + TbInputDataXit tbInputDataXit = (TbInputDataXit) data.get(DataKeys.tbInputDataXit.name()); + TbInputXit tbInputXit = tbInputDataXit.getTbInputXit(); + FsJob fsJob = tbInputXit.getFsJob(); + final String dataId = tbInputDataXit.getDataId(); + + if ("Y".equals(fsJob.getBpEntrustYn()) || "y".equals(fsJob.getBpEntrustYn())) { + + final String url = fsJob.getBpNvPrepayApi(); + + VKakaoNoticeInfoSn vKakaoNoticeInfoSn = vKakaoNoticeInfoSnRepository.findById(dataId) + .orElseThrow(() -> new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 단순미납부과 자료가 없습니다.")); + Optional.of(vKakaoNoticeInfoSn) + .map(entity -> payUseSysApi.payAble(url, reqParam, null)) + .map(response -> checkResponse(response)) + .map(payApiRespDTO -> loadRespData(data, payApiRespDTO)) + .orElseThrow(() -> new EnsException(EnsErrCd.FAILED_CREATE_RESPONSE_DATA, "단순미납 응답데이터 수신에 실패했습니다.")) + ; + } else if ("N".equals(fsJob.getBpEntrustYn()) || "n".equals(fsJob.getBpEntrustYn())) { + if (dataId.length() < 20) + throw new EnsException(EnsErrCd.INVALID_DATA, "데이터ID가 20자리 미만 입니다."); + VKakaoNoticeInfo vKakaoNoticeInfo = vKakaoNoticeInfoRepository.findById(dataId.substring(0, 20)) + .orElseThrow(() -> new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 강제징수부과 자료가 없습니다.")); + Optional.of(vKakaoNoticeInfo) + .map(entity -> validateData(reqParam, entity)); + TbEnfrcLevMastr tbEnfrcLevMastr = tbEnfrcLevMastrRepository.findByEnfrcLevMastrIdAndEnfrcLevMastrProcessSttusAndDeleteAt(dataId.substring(0, 20), "04", "N") + .orElseThrow(() -> new EnsException(EnsErrCd.NO_DATA_FOUND, "납부가능 상태가 아닙니다.", PayUseSysResCd.NO_TARGET_PAYABLE)); + Optional.of(tbEnfrcLevMastr) + .map(entity -> createRespData()) + .map(payApiRespDTO -> loadRespData(data, payApiRespDTO)) + .orElseThrow(() -> new EnsException(EnsErrCd.FAILED_CREATE_RESPONSE_DATA, "강제징수 응답데이터 생성에 실패했습니다.")); + } else { + throw new EnsException(EnsErrCd.INVALID_DATA, "위탁여부가 등록되지 않았습니다."); + } + + } + + private PayApiRespDTO> checkResponse(ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + PayApiRespDTO> result = null; + try { + result = gson.fromJson(response.getBody(), PayApiRespDTO.class); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RESPONSE, EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + } + + return result; + } + + private PayApiRespDTO loadRespData(Map data, PayApiRespDTO payApiRespDTO) { + if (CmmnUtil.isEmpty(payApiRespDTO)) + return null; + + data.put(DataKeys.payApiRespDTO.name(), payApiRespDTO); + data.put(DataKeys.responseJsonStr.name(), gson.toJson(payApiRespDTO)); + return payApiRespDTO; + } + + private VKakaoNoticeInfo validateData(Map reqParam, VKakaoNoticeInfo vKakaoNoticeInfo) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + + final String productName = (String) reqData.get("productName"); + final Integer totalPayAmount = (Integer) reqData.getOrDefault("totalPayAmount", 0); + final Integer taxScopeAmount = (Integer) reqData.get("taxScopeAmount"); + final Integer taxExScopeAmount = (Integer) reqData.get("taxExScopeAmount"); + + + if (totalPayAmount != Integer.parseInt(vKakaoNoticeInfo.getAmount())) + throw new EnsException(EnsErrCd.INVALID_DATA + , String.format("납부 가능 금액이 없거나 일치하지 않습니다. (요청금액:%s, 실제금액:%s)", totalPayAmount, vKakaoNoticeInfo.getAmount()) + , PayUseSysResCd.NO_AMOUNT_PAYABLE); + if (totalPayAmount > Integer.parseInt(vKakaoNoticeInfo.getAmount())) + throw new EnsException(EnsErrCd.INVALID_DATA + , String.format("납부 가능 금액을 초과했습니다. (요청금액:%s, 실제금액:%s)", totalPayAmount, vKakaoNoticeInfo.getAmount()) + , PayUseSysResCd.OVERPAYABLE_AMOUNT); + if (CmmnUtil.isEmpty(vKakaoNoticeInfo.getPayExpireDate())) + throw new EnsException(EnsErrCd.INVALID_DATA + , "납부기한의 값이 비어있습니다." + , PayUseSysResCd.EXPIRED_DATE); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); + if (Integer.parseInt(vKakaoNoticeInfo.getPayExpireDate()) < Integer.parseInt(simpleDateFormat.format(new Date()))) + throw new EnsException(EnsErrCd.INVALID_DATA + , "납부기한이 경과한 자료 입니다." + , PayUseSysResCd.EXPIRED_DATE); + + return vKakaoNoticeInfo; + } + + private PayApiRespDTO> createRespData() { + return PayApiRespDTO.>okBuilder().build(); + } + + @Override + public PayApiRespDTO> generateResult(Map reqParam, Map data, EnsException e) { + if (e == null) { + PayApiRespDTO> payApiRespDTO = (PayApiRespDTO>) data.get(DataKeys.payApiRespDTO.name()); + return payApiRespDTO; + + } else { + if (e.getData() != null && e.getData() instanceof PayUseSysResCd) { + PayUseSysResCd resCode = (PayUseSysResCd) e.getData(); + return PayApiRespDTO.>errBuilder() + .resCode(resCode.getCode()) + .message(resCode.getCodeNm()) + .build(); + } else { + return PayApiRespDTO.>errBuilder() + .resCode(PayUseSysResCd.FAILED_CHECK_INFO.getCode()) + .message(PayUseSysResCd.FAILED_CHECK_INFO.getCodeNm()) + .build(); + } + } + } + + @Override + public void saveHist(Map reqParam, Map data, EnsException e) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + String billerUserKey = (String) reqData.get("billerUserKey"); + + String errorCode = null; + String errorMessage = null; + if (e != null) { + errorCode = e.getErrCd().getCode(); + errorMessage = String.format("%s %s", e.getMessage(), CmmnUtil.printStackTraceToString(e)); + } + + TbIupBillPayHist tbIupBillPayHist = TbIupBillPayHist.builder() + .dataId(billerUserKey) + .paidType(PaidTypeCd.naverPay) + .hisSeCd(PayUseSysHisSeCd.payAble) + .requestData(gson.toJson(reqParam)) + .responseData((String) data.get(DataKeys.responseJsonStr.name())) + .error(FieldError.initBuilder() + .errorCode(errorCode) + .errorMessage(errorMessage) + .build()) + .build(); + tbIupBillPayHistRepository.save(tbIupBillPayHist); + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupNvPayCancelService.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupNvPayCancelService.java new file mode 100644 index 0000000..8d61b5b --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupNvPayCancelService.java @@ -0,0 +1,51 @@ +package cokr.xit.ens.biz.iup.billpay.service.process; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.utils.MapDeserailizer; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.BillNvEasyPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayCancelService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayCancelData; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Slf4j +@RequiredArgsConstructor +@Service +public class IupNvPayCancelService implements PayCancelService, Map, PayApiRespDTO>> { + + private final JPAQueryFactory query; + + private Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).create(); + + @Override + public PayCancelData getData(Map reqParam) { + return null; + } + + @Override + public void validate(Map reqParam, PayCancelData data) { + + } + + @Override + public void callApi(Map reqParam, PayCancelData data) { + + } + + @Override + public PayApiRespDTO> generateResult(Map reqParam, PayCancelData data, EnsException e) { + return null; + } + + @Override + public void saveHist(Map reqParam, PayCancelData data, EnsException e) { + + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupNvPayNoticeService.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupNvPayNoticeService.java new file mode 100644 index 0000000..387ea9a --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupNvPayNoticeService.java @@ -0,0 +1,229 @@ +package cokr.xit.ens.biz.iup.billpay.service.process; + +import cokr.xit.ens.biz.iup.domain.*; +import cokr.xit.ens.biz.iup.domain.repository.TbIupBillPayHistRepository; +import cokr.xit.ens.biz.iup.domain.repository.VKakaoNoticeInfoRepository; +import cokr.xit.ens.biz.iup.domain.repository.VKakaoNoticeInfoSnRepository; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.code.NvEpCtgyIdCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.NvPayNoticeRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.config.notice.ProductItem; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PaidTypeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysHisSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayNoticeService; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Slf4j +@RequiredArgsConstructor +@Service +public class IupNvPayNoticeService implements PayNoticeService, Map, PayApiRespDTO> { + + private final JPAQueryFactory query; + private final VKakaoNoticeInfoSnRepository vKakaoNoticeInfoSnRepository; + private final VKakaoNoticeInfoRepository vKakaoNoticeInfoRepository; + private final TbIupBillPayHistRepository tbIupBillPayHistRepository; + private Gson gson = new Gson(); + @Value("${contract.naver.pay.easy.api.validate.host}") + private String BILL_HOST; + @Value("${contract.naver.pay.easy.api.validate.prepay}") + private String BILL_PAYABLE_URL; + + private enum DataKeys { + tbInputDataXit, + nvPayNoticeRespData, + responseJsonStr, + } + + private enum PayDataKeys { + billerUserKey, + userBirth, + amount, + payExpireDate, + detailPasngChrgeSm, + detailAdiPasngChrgeSm, + } + + @Override + public Map getData(Map reqParam) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + final String billerUserKey = (String) reqData.getOrDefault("billerUserKey", ""); + + TbInputDataXit tbInputDataXit = query.selectFrom(QTbInputDataXit.tbInputDataXit) + .innerJoin(QTbInputDataXit.tbInputDataXit.tbInputXit, QTbInputXit.tbInputXit).fetchJoin() + .innerJoin(QTbInputXit.tbInputXit.fsJob, QFsJob.fsJob).fetchJoin() + .where(QTbInputDataXit.tbInputDataXit.linkedUuid.eq(billerUserKey)) + .fetchOne(); + + Map data = new HashMap<>(); + data.put(DataKeys.tbInputDataXit.name(), tbInputDataXit); + return data; + } + + @Override + public void validate(Map reqParam, Map data) { + + if (CmmnUtil.isEmpty(data.get(DataKeys.tbInputDataXit.name()))) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, EnsErrCd.NO_DATA_FOUND.getCodeNm()); + } + + @Override + public void callApi(Map reqParam, Map data) { + TbInputDataXit tbInputDataXit = (TbInputDataXit) data.get(DataKeys.tbInputDataXit.name()); + TbInputXit tbInputXit = tbInputDataXit.getTbInputXit(); + FsJob fsJob = tbInputXit.getFsJob(); + final String dataId = tbInputDataXit.getDataId(); + + if ("Y".equals(fsJob.getBpEntrustYn()) || "y".equals(fsJob.getBpEntrustYn())) { + VKakaoNoticeInfoSn vKakaoNoticeInfoSn = vKakaoNoticeInfoSnRepository.findById(dataId) + .orElseThrow(() -> new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 단순미납부과 자료가 없습니다.")); + Optional.of(vKakaoNoticeInfoSn) + .map(entity -> toDataMap(entity)) + .map(payData -> validateData(reqParam, payData)) + .map(payData -> createRespData(tbInputDataXit, payData)) + .map(kkoPayNoticeRespData -> loadRespData(data, kkoPayNoticeRespData)) + .orElseThrow(() -> new EnsException(EnsErrCd.FAILED_CREATE_RESPONSE_DATA, "단순미납 응답데이터 생성에 실패했습니다.")) + ; + } else if ("N".equals(fsJob.getBpEntrustYn()) || "n".equals(fsJob.getBpEntrustYn())) { + if (dataId.length() < 20) + throw new EnsException(EnsErrCd.INVALID_DATA, "데이터ID가 20자리 미만 입니다."); + VKakaoNoticeInfo vKakaoNoticeInfo = vKakaoNoticeInfoRepository.findById(dataId.substring(0, 20)) + .orElseThrow(() -> new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 강제징수부과 자료가 없습니다.")); + Optional.of(vKakaoNoticeInfo) + .map(entity -> toDataMap(entity)) + .map(map -> validateData(reqParam, map)) + .map(map -> createRespData(tbInputDataXit, map)) + .map(kkoPayNoticeRespData -> loadRespData(data, kkoPayNoticeRespData)) + .orElseThrow(() -> new EnsException(EnsErrCd.FAILED_CREATE_RESPONSE_DATA, "강제징수 응답데이터 생성에 실패했습니다.")) + ; + } else { + throw new EnsException(EnsErrCd.INVALID_DATA, "위탁여부가 등록되지 않았습니다."); + } + } + + private Map toDataMap(VKakaoNoticeInfoSn vKakaoNoticeInfoSn) { + Map payData = new HashMap<>(); + payData.put(PayDataKeys.billerUserKey, vKakaoNoticeInfoSn.getDataId()); + payData.put(PayDataKeys.userBirth, vKakaoNoticeInfoSn.getUserBirth()); + payData.put(PayDataKeys.amount, vKakaoNoticeInfoSn.getAmount().intValue()); + payData.put(PayDataKeys.payExpireDate, vKakaoNoticeInfoSn.getPayExpireDate()); + payData.put(PayDataKeys.detailPasngChrgeSm, vKakaoNoticeInfoSn.getDetailPasngChrgeSm()); + payData.put(PayDataKeys.detailAdiPasngChrgeSm, vKakaoNoticeInfoSn.getDetailAdiPasngChrgeSm()); + return payData; + } + + private Map toDataMap(VKakaoNoticeInfo vKakaoNoticeInfo) { + Map payData = new HashMap<>(); + payData.put(PayDataKeys.billerUserKey, vKakaoNoticeInfo.getEnfrcLevMastrId()); + payData.put(PayDataKeys.userBirth, vKakaoNoticeInfo.getUserBirth()); + payData.put(PayDataKeys.amount, Integer.parseInt(vKakaoNoticeInfo.getAmount())); + payData.put(PayDataKeys.payExpireDate, vKakaoNoticeInfo.getPayExpireDate()); + payData.put(PayDataKeys.detailPasngChrgeSm, vKakaoNoticeInfo.getDetailPasngChrgeSm()); + payData.put(PayDataKeys.detailAdiPasngChrgeSm, vKakaoNoticeInfo.getDetailAdiPasngChrgeSm()); + return payData; + } + + private Map validateData(Map reqParam, Map payData) { + return payData; + } + + + private NvPayNoticeRespData createRespData(TbInputDataXit tbInputDataXit, Map payData) { + NvEpCtgyIdCd productSe = NvEpCtgyIdCd.ETC_ETC; + List productItems = Arrays.asList(ProductItem.builder() + .categoryType(productSe.getCategoryTypeCd()) + .categoryId(productSe.getCode().split("_")[1]) +// .uid(tbInputDataXit.getLinkedUuid()) + .uid(tbInputDataXit.getTbInputXit().getFsJob().getJobCd()) //2023.03.14 네이버페이 검수 결과 - 상품고유ID로 변경 + .name(tbInputDataXit.getTbInputXit().getFsJob().getJobName()) + .count(1) + .build()); + Integer productCount = productItems.stream().map(productItem -> productItem.getCount()).reduce(Integer::sum).get(); + return NvPayNoticeRespData.builder() + .productName(tbInputDataXit.getTbInputXit().getFsJob().getJobName()) + .productCount(productCount) + .totalPayAmount((Integer) payData.get(PayDataKeys.amount)) + .taxScopeAmount(0) + .taxExScopeAmount((Integer) payData.get(PayDataKeys.amount)) + .environmentDepositAmount(0) + .productItems(productItems) + .returnUrl(this.BILL_HOST + this.BILL_PAYABLE_URL) + .build(); + } + + private NvPayNoticeRespData loadRespData(Map data, NvPayNoticeRespData kkoPayNoticeRespData) { + if (CmmnUtil.isEmpty(kkoPayNoticeRespData)) + return null; + + data.put(DataKeys.nvPayNoticeRespData.name(), kkoPayNoticeRespData); + data.put(DataKeys.responseJsonStr.name(), gson.toJson(kkoPayNoticeRespData)); + return kkoPayNoticeRespData; + } + + + @Override + public PayApiRespDTO generateResult(Map reqParam, Map data, EnsException e) { + if (e == null) { + NvPayNoticeRespData nvPayNoticeRespData = (NvPayNoticeRespData) data.get(DataKeys.nvPayNoticeRespData.name()); + return PayApiRespDTO.okBuilder() + .data(nvPayNoticeRespData) + .build(); + + } else { + String resCode = null; + String message = null; + switch (e.getErrCd()) { + case NO_DATA_FOUND: + resCode = PayUseSysResCd.NOT_FOUND_PAYDATA.getCode(); + message = PayUseSysResCd.NOT_FOUND_PAYDATA.getCodeNm(); + break; + default: + resCode = PayUseSysResCd.PAYDATA_FIND_FAILED.getCode(); + message = PayUseSysResCd.PAYDATA_FIND_FAILED.getCodeNm(); + break; + } + + return PayApiRespDTO.errBuilder() + .resCode(resCode) + .message(message) + .build(); + } + } + + @Override + public void saveHist(Map reqParam, Map data, EnsException e) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + final String billerUserKey = (String) reqData.getOrDefault("billerUserKey", ""); + + String errorCode = null; + String errorMessage = null; + if (e != null) { + errorCode = e.getErrCd().getCode(); + errorMessage = String.format("%s %s", e.getMessage(), CmmnUtil.printStackTraceToString(e)); + } + + TbIupBillPayHist tbIupBillPayHist = TbIupBillPayHist.builder() + .dataId(billerUserKey) + .paidType(PaidTypeCd.naverPay) + .hisSeCd(PayUseSysHisSeCd.payNotice) + .requestData(gson.toJson(reqParam)) + .responseData((String) data.get(DataKeys.responseJsonStr.name())) + .error(FieldError.initBuilder() + .errorCode(errorCode) + .errorMessage(errorMessage) + .build()) + .build(); + tbIupBillPayHistRepository.save(tbIupBillPayHist); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupNvPayResultService.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupNvPayResultService.java new file mode 100644 index 0000000..9ec2b85 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/process/IupNvPayResultService.java @@ -0,0 +1,213 @@ +package cokr.xit.ens.biz.iup.billpay.service.process; + +import cokr.xit.ens.biz.iup.domain.*; +import cokr.xit.ens.biz.iup.domain.repository.TbIupBillPayHistRepository; +import cokr.xit.ens.biz.iup.domain.repository.TbNaverPayResultRepository; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.NvPayResultDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.NvPayResultReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PaidTypeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysHisSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayResultService; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Service +public class IupNvPayResultService implements PayResultService, Map, PayApiRespDTO>> { + + private final JPAQueryFactory query; + private final PayUseSysApi payUseSysApi; + private final TbNaverPayResultRepository tbNaverPayResultRepository; + private final TbIupBillPayHistRepository tbIupBillPayHistRepository; + + private Gson gson = new Gson(); + + private enum DataKeys { + tbInputDataXit, + responseJsonStr, + } + + @Override + public Map getData(Map reqParam) { + Map body = (Map) reqParam.getOrDefault("body", new HashMap<>()); + Map detail = (Map) body.getOrDefault("detail", new HashMap<>()); + String billerUserKey = (String) detail.get("merchantUserKey"); + + if (billerUserKey == null) billerUserKey = ""; + TbInputDataXit tbInputDataXit = query.selectFrom(QTbInputDataXit.tbInputDataXit) + .innerJoin(QTbInputDataXit.tbInputDataXit.tbInputXit, QTbInputXit.tbInputXit).fetchJoin() + .innerJoin(QTbInputXit.tbInputXit.fsJob, QFsJob.fsJob).fetchJoin() + .where(QTbInputDataXit.tbInputDataXit.linkedUuid.eq(billerUserKey)) + .fetchOne(); + + + Map data = new HashMap<>(); + data.put(DataKeys.tbInputDataXit.name(), tbInputDataXit); + return data; + } + + @Override + public void validate(Map reqParam, Map data) { + + if (CmmnUtil.isEmpty(data.get(DataKeys.tbInputDataXit.name()))) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, EnsErrCd.NO_DATA_FOUND.getCodeNm()); + } + + @Override + public void callApi(Map reqParam, Map data) { + TbInputDataXit tbInputDataXit = (TbInputDataXit) data.get(DataKeys.tbInputDataXit.name()); + TbInputXit tbInputXit = tbInputDataXit.getTbInputXit(); + FsJob fsJob = tbInputXit.getFsJob(); + + final String url = fsJob.getBpNvPayresultApi(); + + + Optional.ofNullable(gson.fromJson(gson.toJson(reqParam.get("body")), NvPayResultReqData.class)) + .map(nvPayResultReqData -> toEntity(nvPayResultReqData)) + .map(entity -> savePayResult(entity)) + .map(entity -> tbInputDataXit) + .filter(detail -> "Y".equals(detail.getTbInputXit().getFsJob())) + .map(vKakaoNoticeInfoSn -> payUseSysApi.payResult(url, reqParam, null)) + .map(respnose -> loadRespData(data, respnose)) + .map(response -> checkResponse(response)) + ; + + } + + private TbNaverPayResult toEntity(NvPayResultReqData nvPayResultReqData) { + NvPayResultDetail detail = nvPayResultReqData.getDetail(); + final String billerUserKey = detail.getMerchantUserKey(); + + + final String jobSe = "EL".equals(billerUserKey.substring(0, 2)) ? "2" : "1"; + + + return TbNaverPayResult.builder() + .dataId(billerUserKey) + .jobSe(jobSe) + .paymentId(detail.getPaymentId()) + .payHistId(detail.getPayHistId()) + .merchantId(detail.getMerchantId()) + .merchantName(detail.getMerchantName()) + .merchantPayKey(detail.getMerchantPayKey()) + .merchantUserKey(detail.getMerchantUserKey()) + .admissionTypeCode(detail.getAdmissionTypeCode()) + .admissionYmdt(detail.getAdmissionYmdt()) + .tradeConfirmYmdt(detail.getTradeConfirmYmdt()) + .admissionState(detail.getAdmissionState()) + .totalPayAmount(detail.getTotalPayAmount()) + .primaryPayAmount(detail.getPrimaryPayAmount()) + .npointPayAmount(detail.getNpointPayAmount()) + .giftCardAmount(detail.getGiftCardAmount()) + .taxScopeAmount(detail.getTaxScopeAmount()) + .taxExScopeAmount(detail.getTaxExScopeAmount()) + .environmentDepositAmount(detail.getEnvironmentDepositAmount()) + .primaryPayMeans(detail.getPrimaryPayMeans()) + .cardCorpCode(detail.getCardCorpCode()) + .cardNo(detail.getCardNo()) + .cardAuthNo(detail.getCardAuthNo()) + .cardInstCount(detail.getCardInstCount()) + .usedCardPoint(detail.getUsedCardPoint()) + .bankCorpCode(detail.getBankCorpCode()) + .bankAccountNo(detail.getBankAccountNo()) + .productName(detail.getProductName()) + .settleExpected(detail.getSettleExpected()) + .settleExpectAmount(detail.getSettleExpectAmount()) + .payCommissionAmount(detail.getPayCommissionAmount()) + .extraDeduction(detail.getExtraDeduction()) + .useCfmYmdt(detail.getUseCfmYmdt()) + .merchantExtraParameter(detail.getMerchantExtraParameter()) + .userIdentifier(detail.getUserIdentifier()) + .payResultProcessSttus("0") +// .creatDt() + .crtr("ENS_SYS") +// .updtDt() +// .updusr() + .build(); + + } + + private TbNaverPayResult savePayResult(TbNaverPayResult entity) { + tbNaverPayResultRepository.save(entity); + return entity; + } + + private ResponseEntity loadRespData(Map data, ResponseEntity response) { + data.put(DataKeys.responseJsonStr.name(), response.getBody()); + return response; + } + + private PayApiRespDTO> checkResponse(ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + PayApiRespDTO> result = null; + try { + result = gson.fromJson(response.getBody(), PayApiRespDTO.class); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RESPONSE, EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + } + + return result; + } + + + @Override + public PayApiRespDTO> generateResult(Map reqParam, Map data, EnsException e) { + if (e == null) { + return PayApiRespDTO.>okBuilder().build(); + + } else { + return PayApiRespDTO.>errDataBuilder() + .resCode(PayUseSysResCd.FAILED_SAVE_PAYRSLT.getCode()) + .message(PayUseSysResCd.FAILED_SAVE_PAYRSLT.getCodeNm()) + .data(null) + .build(); + } + } + + @Override + public void saveHist(Map reqParam, Map data, EnsException e) { + Map body = (Map) reqParam.getOrDefault("body", new HashMap<>()); + Map detail = (Map) body.getOrDefault("detail", new HashMap<>()); + String billerUserKey = (String) detail.get("merchantUserKey"); + + String errorCode = null; + String errorMessage = null; + if (e != null) { + errorCode = e.getErrCd().getCode(); + errorMessage = String.format("%s %s", e.getMessage(), CmmnUtil.printStackTraceToString(e)); + } + + TbIupBillPayHist tbIupBillPayHist = TbIupBillPayHist.builder() + .dataId(billerUserKey) + .paidType(PaidTypeCd.naverPay) + .hisSeCd(PayUseSysHisSeCd.payResult) + .requestData(gson.toJson(reqParam)) + .responseData((String) data.get(DataKeys.responseJsonStr.name())) + .error(FieldError.initBuilder() + .errorCode(errorCode) + .errorMessage(errorMessage) + .build()) + .build(); + tbIupBillPayHistRepository.save(tbIupBillPayHist); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/code/IupPrcsCd.java b/src/main/java/cokr/xit/ens/biz/iup/code/IupPrcsCd.java new file mode 100644 index 0000000..fa23376 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/code/IupPrcsCd.java @@ -0,0 +1,47 @@ +package cokr.xit.ens.biz.iup.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *
    + *
  • 업무 그룹명: 민자고속도로 전자고지 상태코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2022. 2. 15. 오후 3:51:43 + *
+ * @author 박민규 + */ + +public enum IupPrcsCd implements CodeMapperType { + + TGRG("대상등록중") + ,TGRI("대상이관등록대기") + ,TGRF("대상등록실패") + ,TGRC("대상등록완료") + ,GRUR("결제URL생성중") + ,GRUC("결제URL생성완료") + ,CICV("변환대상입수") + ,CICC("변환대상입수완료") + ,COMP("변환완료") + ,INCM("입수중") + ,IPCP("입수완료") + ,FAIL("입수오류") + ; + + private final String code; + private final String codeNm; + IupPrcsCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/code/IupSendSttusCd.java b/src/main/java/cokr/xit/ens/biz/iup/code/IupSendSttusCd.java new file mode 100644 index 0000000..3ae1e9d --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/code/IupSendSttusCd.java @@ -0,0 +1,51 @@ +package cokr.xit.ens.biz.iup.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *
    + *
  • 업무 그룹명: 민자고속도로 발송상태 코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2022. 3. 2. 오후 3:51:43 + *
+ * @author 박민규 + */ + +public enum IupSendSttusCd implements CodeMapperType { + TALK_SEND("알림톡발송") + ,SMS_SEND("SMS발송") + + ,READY("송신 준비") + ,NOMB("카카오 비회원") + ,DENY("카카오 거부") + ,SEND("카카오 송신") + ,RECV("카카오 수신") + ,SIGN("카카오 서명") + ,NV_NOMB("네이버 비회원") + ,NV_DENY("네이버 거부") + ,NV_SEND("네이버 송신") + ,NV_RECV("네이버 수신") + ,NV_SIGN("네이버 서명") + + + ,FAIL("송신오류") + ; + + private final String code; + private final String codeNm; + IupSendSttusCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/code/IupSendTrySttusCd.java b/src/main/java/cokr/xit/ens/biz/iup/code/IupSendTrySttusCd.java new file mode 100644 index 0000000..cdf3587 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/code/IupSendTrySttusCd.java @@ -0,0 +1,37 @@ +package cokr.xit.ens.biz.iup.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *
    + *
  • 업무 그룹명: 민자고속도로 발송시도상태 코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2022. 6. 29. 오후 3:51:43 + *
+ * @author 박민규 + */ + +public enum IupSendTrySttusCd implements CodeMapperType { + + TRYING("시도중") + , CMPLT("완료") + ; + + private final String code; + private final String codeNm; + IupSendTrySttusCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/code/IupSendTypeCd.java b/src/main/java/cokr/xit/ens/biz/iup/code/IupSendTypeCd.java new file mode 100644 index 0000000..e3f414b --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/code/IupSendTypeCd.java @@ -0,0 +1,37 @@ +package cokr.xit.ens.biz.iup.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *
    + *
  • 업무 그룹명: 민자고속도로 발송구분 코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2022. 3. 2. 오후 3:51:43 + *
+ * @author 박민규 + */ + +public enum IupSendTypeCd implements CodeMapperType { + + NI("알림톡") + ,KP("인증톡") + ; + + private final String code; + private final String codeNm; + IupSendTypeCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/FsJob.java b/src/main/java/cokr/xit/ens/biz/iup/domain/FsJob.java new file mode 100644 index 0000000..f5ccdd9 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/FsJob.java @@ -0,0 +1,113 @@ +package cokr.xit.ens.biz.iup.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.persistence.*; + +@Entity +//@Data +@Getter +@ToString +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "fs_job", schema = "", catalog = "") +public class FsJob { + + @Id + @Column(name = "job_cd", nullable = false, length = 10) + private String jobCd; + + + @Column(name = "job_name", nullable = true) + private String jobName; + + + @Column(name = "job_desc", nullable = true) + private String jobDesc; + + + @Column(name = "enc_phone_no_yn", nullable = true) + private String encPhoneNoYn; + + + @Column(name = "enc_name_yn", nullable = true) + private String encNameYn; + + + @Column(name = "enc_birthday_yn", nullable = true) + private String encBirthdayYn; + + + @Column(name = "unsube_use_yn", nullable = true) + private String unsubeUseYn; + + + @Column(name = "unsube_type", nullable = true) + private String unsubeType; + + + @Column(name = "use_yn", nullable = true) + private String useYn; + + + @Column(name = "reg_id", nullable = true) + private String regId; + + + @Column(name = "reg_dt", nullable = true) + private java.sql.Date regDt; + + + @Column(name = "upd_id", nullable = true) + private String updId; + + + @Column(name = "upd_dt", nullable = true) + private java.sql.Date updDt; + + + @Column(name = "org_cd", nullable = true) + private String orgCd; + + + @Column(name = "call_center_no", nullable = true) + private String callCenterNo; + + + @Column(name = "redirect_url", nullable = true) + private String redirectUrl; + + + @Column(name = "template_cd", nullable = true) + private String templateCd; + + + + /* ================================================= + * 2023.02.14. 페이결제 진행 시 민자사 호출을 위해 추가 함 + ================================================= */ + + @Column(name = "bp_entrust_yn", nullable = true, length = 1) + @Setter + private String bpEntrustYn; + + @Column(name = "bp_kko_prepay_api", nullable = true) + @Setter + private String bpKkoPrepayApi; + + @Column(name = "bp_kko_payresult_api", nullable = true) + @Setter + private String bpKkoPayresultApi; + + @Column(name = "bp_nv_prepay_api", nullable = true) + @Setter + private String bpNvPrepayApi; + + @Column(name = "bp_nv_payresult_api", nullable = true) + @Setter + private String bpNvPayresultApi; + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/TbEnfrcLevMastr.java b/src/main/java/cokr/xit/ens/biz/iup/domain/TbEnfrcLevMastr.java new file mode 100644 index 0000000..2ae263f --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/TbEnfrcLevMastr.java @@ -0,0 +1,237 @@ +package cokr.xit.ens.biz.iup.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.persistence.*; +import java.sql.Date; +import java.util.Objects; + +@Entity +//@Data +@Getter +@ToString +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "tb_enfrc_lev_mastr", schema = "", catalog = "") +public class TbEnfrcLevMastr { + @Id + @Column(name = "enfrc_lev_mastr_id") + private String enfrcLevMastrId; + + @Column(name = "enfrc_lev_year") + private String enfrcLevYear; + + @Column(name = "enfrc_lev_tme") + private String enfrcLevTme; + + @Column(name = "enfrc_lev_sn") + private String enfrcLevSn; + + @Column(name = "pvtcpt_road_sctn_id") + private String pvtcptRoadSctnId; + + @Column(name = "vhcle_no") + private String vhcleNo; + + @Column(name = "dfltr_id") + private String dfltrId; + + @Column(name = "pasng_chrge_sm") + private Long pasngChrgeSm; + + @Column(name = "adi_pasng_chrge_sm") + private Long adiPasngChrgeSm; + + @Column(name = "npy_pasng_chrge_sm") + private Long npyPasngChrgeSm; + + @Column(name = "npy_co_sm") + private Integer npyCoSm; + + @Column(name = "npy_occrrnc_begin_de") + private String npyOccrrncBeginDe; + + @Column(name = "npy_occrrnc_end_de") + private String npyOccrrncEndDe; + + @Column(name = "elctrn_ntic_sndng_posbl_at") + private String elctrnNticSndngPosblAt; + + @Column(name = "n_bank_virtl_acnut_no") + private String nBankVirtlAcnutNo; + + @Column(name = "k_bank_virtl_acnut_no") + private String kBankVirtlAcnutNo; + + @Column(name = "w_bank_virtl_acnut_no") + private String wBankVirtlAcnutNo; + + @Column(name = "s_bank_virtl_acnut_no") + private String sBankVirtlAcnutNo; + + @Column(name = "pay_tmlmt") + private String payTmlmt; + + @Column(name = "enfrc_lev_reqst_dt") + private String enfrcLevReqstDt; + + @Column(name = "enfrc_lev_applcnt") + private String enfrcLevApplcnt; + + @Column(name = "enfrc_lev_outset_reqst_dt") + private String enfrcLevOutsetReqstDt; + + @Column(name = "enfrc_lev_outset_applcnt") + private String enfrcLevOutsetApplcnt; + + @Column(name = "enfrc_lev_reqst_process_dt") + private String enfrcLevReqstProcessDt; + + @Column(name = "enfrc_lev_reqst_opetr") + private String enfrcLevReqstOpetr; + + @Column(name = "enfrc_lev_outset_process_dt") + private String enfrcLevOutsetProcessDt; + + @Column(name = "enfrc_lev_outset_opetr") + private String enfrcLevOutsetOpetr; + + @Column(name = "enfrc_lev_last_process_resn") + private String enfrcLevLastProcessResn; + + @Column(name = "enfrc_lev_last_process_dt") + private String enfrcLevLastProcessDt; + + @Column(name = "enfrc_lev_last_opetr") + private String enfrcLevLastOpetr; + + @Column(name = "enfrc_lev_mastr_process_sttus") + private String enfrcLevMastrProcessSttus; + + @Column(name = "enfrc_lev_wthdraw_at") + private String enfrcLevWthdrawAt; + + @Column(name = "enfrc_lev_wthdraw_mastr_id") + private String enfrcLevWthdrawMastrId; + + @Column(name = "creat_dt") + private Date creatDt; + + @Column(name = "crtr") + private String crtr; + + @Column(name = "updt_dt") + private Date updtDt; + + @Column(name = "updusr") + private String updusr; + + @Column(name = "delete_at") + private String deleteAt; + + @Column(name = "delete_dt") + private Date deleteDt; + + @Column(name = "dltr") + private String dltr; + + @Column(name = "job_sttus") + private String jobSttus; + + @Column(name = "job_tmlmt") + private String jobTmlmt; + + @Column(name = "rciv_pasng_chrge_sm") + private Long rcivPasngChrgeSm; + + @Column(name = "rciv_adi_pasng_chrge_sm") + private Long rcivAdiPasngChrgeSm; + + @Column(name = "rciv_npy_pasng_chrge_sm") + private Long rcivNpyPasngChrgeSm; + + @Column(name = "rciv_co_sm") + private Integer rcivCoSm; + + @Column(name = "blce_pasng_chrge_sm") + private Long blcePasngChrgeSm; + + @Column(name = "blce_adi_pasng_chrge_sm") + private Long blceAdiPasngChrgeSm; + + @Column(name = "blce_npy_pasng_chrge_sm") + private Long blceNpyPasngChrgeSm; + + @Column(name = "blce_co_sm") + private Integer blceCoSm; + + @Column(name = "dfct_dsps_pasng_chrge_sm") + private Long dfctDspsPasngChrgeSm; + + @Column(name = "dfct_dsps_adi_pasmny_sm") + private Long dfctDspsAdiPasmnySm; + + @Column(name = "dfct_dsps_npy_pasmny_sm") + private Long dfctDspsNpyPasmnySm; + + @Column(name = "dfct_dsps_co_sm") + private Integer dfctDspsCoSm; + + @Column(name = "part_rciv_at") + private String partRcivAt; + + @Column(name = "ntcn_sndng_de") + private String ntcnSndngDe; + + @Column(name = "ntcn_sndng_process_sttus") + private String ntcnSndngProcessSttus; + + @Column(name = "crtfc_sndng_de") + private String crtfcSndngDe; + + @Column(name = "crtfc_sndng_process_sttus") + private String crtfcSndngProcessSttus; + + @Column(name = "urgsht_sndng_de") + private String urgshtSndngDe; + + @Column(name = "urgsht_dlvr_sttus") + private String urgshtDlvrSttus; + + @Column(name = "urgsht_scd_sndng_de") + private String urgshtScdSndngDe; + + @Column(name = "urgsht_scd_dlvr_sttus") + private String urgshtScdDlvrSttus; + + @Column(name = "seizr_prvntc_sndng_de") + private String seizrPrvntcSndngDe; + + @Column(name = "seizr_prvntc_sndng_process_stt") + private String seizrPrvntcSndngProcessStt; + + @Column(name = "seizr_de") + private String seizrDe; + + @Column(name = "tkbak_de") + private String tkbakDe; + + @Column(name = "seizr_relis_de") + private String seizrRelisDe; + + @Column(name = "emrgncy_relis_de") + private String emrgncyRelisDe; + + @Column(name = "tkbak_scd_de") + private String tkbakScdDe; + + @Column(name = "rntcar_entrps_nm") + private String rntcarEntrpsNm; + + @Column(name = "lessee_change_de") + private String lesseeChangeDe; + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/TbEnfrcLevRciv.java b/src/main/java/cokr/xit/ens/biz/iup/domain/TbEnfrcLevRciv.java new file mode 100644 index 0000000..8e8c3da --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/TbEnfrcLevRciv.java @@ -0,0 +1,116 @@ +package cokr.xit.ens.biz.iup.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.sql.Date; + +@Entity +//@Data +@Getter +@ToString +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "tb_enfrc_lev_rciv", schema = "", catalog = "") +public class TbEnfrcLevRciv { + + @Id + + @Column(name = "enfrc_lev_rciv_id", nullable = false, length = 12) + private String enfrcLevRcivId; + + + @Column(name = "enfrc_lev_mastr_id", nullable = true, length = 20) + private String enfrcLevMastrId; + + + @Column(name = "enfrc_lev_year", nullable = true, length = 4) + private String enfrcLevYear; + + + @Column(name = "enfrc_lev_tme", nullable = true, length = 1) + private String enfrcLevTme; + + + @Column(name = "pvtcpt_road_sctn_id", nullable = true, length = 4) + private String pvtcptRoadSctnId; + + + @Column(name = "rciv_de", nullable = true, length = 8) + private String rcivDe; + + + @Column(name = "rciv_time", nullable = true, length = 6) + private String rcivTime; + + + @Column(name = "rciv_pasng_chrge", nullable = true, precision = 0) + private Long rcivPasngChrge; + + + @Column(name = "rciv_adi_pasng_chrge", nullable = true, precision = 0) + private Long rcivAdiPasngChrge; + + + @Column(name = "rciv_npy_pasng_chrge", nullable = true, precision = 0) + private Long rcivNpyPasngChrge; + + + @Column(name = "virtl_acnut_bank_code", nullable = true, length = 3) + private String virtlAcnutBankCode; + + + @Column(name = "virtl_acnut_no", nullable = true, length = 20) + private String virtlAcnutNo; + + + @Column(name = "virtl_acnut_delng_esntl_no", nullable = true, length = 14) + private String virtlAcnutDelngEsntlNo; + + + @Column(name = "rciv_se_code", nullable = true, length = 1) + private String rcivSeCode; + + + @Column(name = "rciv_cardfa_se_code", nullable = true, length = 20) + private String rcivCardfaSeCode; + + + @Column(name = "creat_dt", nullable = true) + private Date creatDt; + + + @Column(name = "crtr", nullable = true, length = 50) + private String crtr; + + + @Column(name = "delete_at", nullable = true, length = 1) + private String deleteAt; + + + @Column(name = "delete_dt", nullable = true) + private Date deleteDt; + + + @Column(name = "dltr", nullable = true, length = 50) + private String dltr; + + + @Column(name = "enfrc_lev_id", nullable = true, length = 20) + private String enfrcLevId; + + + @Column(name = "excclc_stdr_de", nullable = true, length = 8) + private String excclcStdrDe; + + + @Column(name = "excclc_stdr_dt", nullable = true, length = 6) + private String excclcStdrDt; + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/TbInputDataBulkTest.java b/src/main/java/cokr/xit/ens/biz/iup/domain/TbInputDataBulkTest.java new file mode 100644 index 0000000..be44a10 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/TbInputDataBulkTest.java @@ -0,0 +1,86 @@ +package cokr.xit.ens.biz.iup.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.persistence.*; + +@Entity +//@Data +@Getter +@ToString +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "TB_INPUT_DATA_BULK_TEST", schema = "", catalog = "") +public class TbInputDataBulkTest { + + @Id +// @GeneratedValue(strategy=GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.TABLE, generator = "TbInputDataBulkTest_Generator") + @TableGenerator(table = "ens_seq_generator", name = "TbInputDataBulkTest_Generator" + ,pkColumnName = "seq_name", pkColumnValue = "TbInputDataBulkTest_id" + ,initialValue = 0, allocationSize = 200) + private Long id; + +// @Id + + @Column(name = "DATA_ID", nullable = false) + private String dataId; + + + @Column(name = "SID", nullable = true) + private String sid; + + + @Column(name = "NAME", nullable = true) + private String name; + + + @Column(name = "BIRTHDAY", nullable = true) + private String birthday; + + + @Column(name = "GENDER", nullable = true) + private String gender; + + + @Column(name = "MSG_DATA", nullable = true, length = 4000) + private String msgData; + + + @Column(name = "MSG_DTL_DATA", nullable = true) + @Lob + private String msgDtlData; + + + @Column(name = "REG_ID", nullable = false) + private String regId; + + + @Column(name = "REG_DT", nullable = false) + private java.sql.Date regDt; + + + @Column(name = "UPD_ID", nullable = true) + private String updId; + + + @Column(name = "UPD_DT", nullable = true) + private java.sql.Date updDt; + + + @Column(name = "PAY_STATUS_CD", nullable = true) + private String payStatusCd; + + + @Column(name = "PAY_URL", nullable = true) + private String payUrl; + + + @Column(name = "CAR_NO", nullable = true) + private String carNo; + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/TbInputDataXit.java b/src/main/java/cokr/xit/ens/biz/iup/domain/TbInputDataXit.java new file mode 100644 index 0000000..36f4874 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/TbInputDataXit.java @@ -0,0 +1,96 @@ +package cokr.xit.ens.biz.iup.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.persistence.*; + +@Entity +//@Data +@Getter +@ToString +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "tb_input_data_xit", schema = "", catalog = "", indexes = { + @Index(name = "idx_TbInputDataXit_01", columnList = "linked_uuid") +}) +public class TbInputDataXit { + + @Id + @Column(name = "data_id", nullable = false) + private String dataId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "lnk_input_id") + private TbInputXit tbInputXit; + + + @Column(name = "sid", nullable = true) + private String sid; + + + @Column(name = "name", nullable = true) + private String name; + + + @Column(name = "birthday", nullable = true) + private String birthday; + + + @Column(name = "gender", nullable = true) + private String gender; + + + @Column(name = "msg_data", nullable = true, length = 4000) + private String msgData; + + + @Column(name = "msg_dtl_data", nullable = true) + @Lob + private String msgDtlData; + + + @Column(name = "reg_id", nullable = false) + private String regId; + + + @Column(name = "reg_dt", nullable = false) + private java.sql.Date regDt; + + + @Column(name = "upd_id", nullable = true) + private String updId; + + + @Column(name = "upd_dt", nullable = true) + private java.sql.Date updDt; + + + @Column(name = "pay_status_cd", nullable = true) + private String payStatusCd; + + + @Column(name = "pay_url", nullable = true) + private String payUrl; + + + @Column(name = "car_no", nullable = true) + private String carNo; + + + @Column(name = "moblphon_no", nullable = true) + private String moblphonNo; + + + + @Column(name = "call_center_no", nullable = true) + private String callCenterNo; + + + @Column(name = "linked_uuid", length = 40) + @Setter + private String linkedUuid; + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/TbInputXit.java b/src/main/java/cokr/xit/ens/biz/iup/domain/TbInputXit.java new file mode 100644 index 0000000..2b102b2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/TbInputXit.java @@ -0,0 +1,92 @@ +package cokr.xit.ens.biz.iup.domain; + +import cokr.xit.ens.biz.iup.code.IupPrcsCd; +import cokr.xit.ens.biz.iup.code.IupSendTypeCd; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.annotations.UpdateTimestamp; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +//@Data +@Getter +@ToString +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "tb_input_xit", schema = "", catalog = "") +public class TbInputXit { + + @Id + @Column(name = "lnk_input_id", nullable = false) + private Long lnkInputId; + + + @Column(name = "org_cd", nullable = false, length = 100) + private String orgCd; + + + @JoinColumn(name = "job_cd") + @ManyToOne(fetch = FetchType.LAZY) + private FsJob fsJob; + + + @Column(name = "tot_cnt", nullable = false) + private Long totCnt; + + + @Column(name = "prcs_cd", nullable = false) + @Enumerated(EnumType.STRING) + @Setter + private IupPrcsCd prcsCd; + + + @Column(name = "err_msg", nullable = true, length = 1000) + @Setter + private String errMsg; + + + @Column(name = "run_dt", nullable = false) +// @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime runDt; + + + @Column(name = "expires_dt", nullable = false) + private LocalDateTime expiresDt; + + + @Column(name = "send_type", nullable = false, length = 10) + @Enumerated(EnumType.STRING) + private IupSendTypeCd sendType; + + + @Column(name = "reg_id", nullable = false, length = 20) + private String regId; + + + @Column(name = "reg_dt", nullable = false) + private LocalDateTime regDt; + + + @Column(name = "upd_id", nullable = true, length = 20) + @Setter + private String updId; + + + @Column(name = "upd_dt", nullable = true) + @UpdateTimestamp + private LocalDateTime updDt; + + + @Column(name = "rcpt_dt", nullable = true, length = 30) + private String rcptDt; + + + @Column(name = "pay_expires_dt", nullable = false) + private LocalDateTime payExpiresDt; + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/TbIupBillPayHist.java b/src/main/java/cokr/xit/ens/biz/iup/domain/TbIupBillPayHist.java new file mode 100644 index 0000000..cca09b0 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/TbIupBillPayHist.java @@ -0,0 +1,33 @@ +package cokr.xit.ens.biz.iup.domain; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHistPayUseSysBaseEntity; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +import javax.persistence.*; + +@Entity +@Getter +@ToString +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "tb_iup_bill_pay_hist", schema = "", catalog = "", indexes = { + @Index(name = "idx_iup_bp_his_01", columnList = "data_id") +}) + +public class TbIupBillPayHist extends BillHistPayUseSysBaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id", nullable = false) + private Long id; + + + @Column(name = "data_id", nullable = true) + private String dataId; + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/TbKakaoPayResult.java b/src/main/java/cokr/xit/ens/biz/iup/domain/TbKakaoPayResult.java new file mode 100644 index 0000000..71c0bef --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/TbKakaoPayResult.java @@ -0,0 +1,105 @@ +package cokr.xit.ens.biz.iup.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.time.LocalDateTime; + +@Entity +//@Data +@Getter +@ToString +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "tb_kakao_pay_result", schema = "", catalog = "") +public class TbKakaoPayResult { + + @Id + @Column(name = "data_id", length = 30) + private String dataId; + + + @Column(name = "job_se", length = 1, nullable = true) + private String jobSe; + + + @Column(name = "pay_mn", length = 20, nullable = true) + private String payMn; + + + @Column(name = "pay_ty", length = 1, nullable = true) + private String payTy; + + +// @Column(name = "pay_detail1", length = 6, nullable = true) + @Column(name = "pay_detail1", length = 8, nullable = true) + private String payDetail1; + + + @Column(name = "pay_detail2", length = 20, nullable = true) + private String payDetail2; + + + @Column(name = "pay_detail3", length = 100, nullable = true) + private String payDetail3; + + + @Column(name = "pay_amount", length = 12, nullable = true) + private String payAmount; + + + @Column(name = "pay_fee_ty", length = 10, nullable = true) + private String payFeeTy; + + + @Column(name = "pay_fee_amount", length = 12, nullable = true) + private String payFeeAmount; + + + @Column(name = "pay_fee_vat", length = 12, nullable = true) + private String payFeeVat; + + + @Column(name = "excclc_prearnge_de", length = 8, nullable = true) + private String excclcPrearngeDe; + + + @Column(name = "pay_dt", length = 14, nullable = true) + private String payDt; + + + @Column(name = "pay_id", length = 20, nullable = true) + private String payId; + + + @Column(name = "pay_result_process_sttus", length = 1, nullable = true) + private String payResultProcessSttus; + + + @CreationTimestamp + @Column(name = "creat_dt", nullable = true) + private LocalDateTime creatDt; + + + @Column(name = "crtr", length = 50, nullable = true) + private String crtr; + + + @UpdateTimestamp + @Column(name = "updt_dt", nullable = true) + private LocalDateTime updtDt; + + + @Column(name = "updusr", length = 50, nullable = true) + private String updusr; + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/TbNaverPayResult.java b/src/main/java/cokr/xit/ens/biz/iup/domain/TbNaverPayResult.java new file mode 100644 index 0000000..cc2c94d --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/TbNaverPayResult.java @@ -0,0 +1,159 @@ +package cokr.xit.ens.biz.iup.domain; + +import cokr.xit.ens.core.jpa.support.BooleanToYnConverter; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +//@Data +@Getter +@ToString +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "tb_naver_pay_result", schema = "", catalog = "") +public class TbNaverPayResult { + + @Id + @Column(name = "data_id", length = 30) + private String dataId; + + + @Column(name = "job_se", length = 1, nullable = true) + private String jobSe; + + + @Column(name = "payment_id", length = 50) + private String paymentId; + + + @Column(name = "pay_hist_id", length = 50) + private String payHistId; + + @Column(name = "merchant_id", length = 50) + private String merchantId; + + @Column(name = "merchant_name", length = 50) + private String merchantName; + + @Column(name = "merchant_pay_key", length = 64) + private String merchantPayKey; + + @Column(name = "merchant_user_key", length = 50) + private String merchantUserKey; + + @Column(name = "admission_type_code", length = 2) + private String admissionTypeCode; + + @Column(name = "admission_ymdt", length = 14) + private String admissionYmdt; + + @Column(name = "trade_confirm_ymdt", length = 50) + private String tradeConfirmYmdt; + + @Column(name = "admission_state", length = 10) + private String admissionState; + + @Column(name = "total_pay_amount") + private Integer totalPayAmount; + + @Column(name = "primary_pay_amount") + private Integer primaryPayAmount; + + @Column(name = "npoint_pay_amount") + private Integer npointPayAmount; + + @Column(name = "gift_card_amount") + private Integer giftCardAmount; + + @Column(name = "tax_scope_amount") + private Integer taxScopeAmount; + + @Column(name = "tax_ex_scope_amount") + private Integer taxExScopeAmount; + + @Column(name = "environment_deposit_amount") + private Integer environmentDepositAmount; + + @Column(name = "primary_pay_means", length = 10) + private String primaryPayMeans; + + @Column(name = "card_corp_code", length = 10) + private String cardCorpCode; + + @Column(name = "card_no", length = 50) + private String cardNo; + + @Column(name = "card_auth_no", length = 30) + private String cardAuthNo; + + @Column(name = "card_inst_count") + private Integer cardInstCount; + + @Column(name = "used_card_point", length = 1) + @Convert(converter = BooleanToYnConverter.class) + private Boolean usedCardPoint; + + @Column(name = "bank_corp_code", length = 10) + private String bankCorpCode; + + @Column(name = "bank_account_no", length = 50) + private String bankAccountNo; + + @Column(name = "product_name", length = 128) + private String productName; + + @Column(name = "settle_expected", length = 1) + @Convert(converter = BooleanToYnConverter.class) + private Boolean settleExpected; + + @Column(name = "settle_expect_amount") + private Integer settleExpectAmount; + + @Column(name = "pay_commission_amount") + private Integer payCommissionAmount; + + @Column(name = "extra_deduction", length = 1) + @Convert(converter = BooleanToYnConverter.class) + private Boolean extraDeduction; + + @Column(name = "use_cfm_ymdt", length = 8) + private String useCfmYmdt; + + @Column(name = "merchant_extra_parameter", length = 400) + private String merchantExtraParameter; + + @Column(name = "user_identifier", length = 44) + private String userIdentifier; + + + + @Column(name = "pay_result_process_sttus", length = 1, nullable = true) + private String payResultProcessSttus; + + + @CreationTimestamp + @Column(name = "creat_dt", nullable = true) + private LocalDateTime creatDt; + + + @Column(name = "crtr", length = 50, nullable = true) + private String crtr; + + + @UpdateTimestamp + @Column(name = "updt_dt", nullable = true) + private LocalDateTime updtDt; + + + @Column(name = "updusr", length = 50, nullable = true) + private String updusr; + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/TbSendResult.java b/src/main/java/cokr/xit/ens/biz/iup/domain/TbSendResult.java new file mode 100644 index 0000000..c9e6b5f --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/TbSendResult.java @@ -0,0 +1,97 @@ +package cokr.xit.ens.biz.iup.domain; + +import cokr.xit.ens.biz.iup.code.IupSendSttusCd; +import cokr.xit.ens.biz.iup.code.IupSendTrySttusCd; +import cokr.xit.ens.biz.iup.code.IupSendTypeCd; +import cokr.xit.ens.biz.iup.domain.ids.TbSendResultIds; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +//@Data +@Getter +@ToString +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "tb_send_result_v2", schema = "", catalog = "") +@IdClass(TbSendResultIds.class) +public class TbSendResult { + + @Id + @Column(name = "lnk_input_id", nullable = false) + private Long lnkInputId; + + @Id + @Column(name = "data_id", nullable = false) + private String dataId; + + @Id + @Column(name = "prcs_odr", nullable = false) + private String prcsOdr; + + + @Column(name = "send_sttus_cd", nullable = true) + @Enumerated(EnumType.STRING) + private IupSendSttusCd sendSttusCd; + + + @Column(name = "send_try_sttus_cd", nullable = true) + @Enumerated(EnumType.STRING) + private IupSendTrySttusCd sendTrySttusCd; + + + @Column(name = "send_type", nullable = true) + @Enumerated(EnumType.STRING) + private IupSendTypeCd sendType; + + + @Column(name = "run_dt", nullable = true) + private LocalDateTime runDt; + + + @Column(name = "biz_send_dt", nullable = true) + private LocalDateTime bizSendDt; + + + @Column(name = "biz_recv_dt", nullable = true) + private LocalDateTime bizRecvDt; + + + @Column(name = "biz_read_dt", nullable = true) + private LocalDateTime bizReadDt; + + + @Column(name = "biz_err_msg", nullable = true, length = 1000) + private String bizErrMsg; + + + @Column(name = "reg_id", nullable = true) + private String regId; + + + @Column(name = "reg_dt", nullable = true) + @CreationTimestamp + private LocalDateTime regDt; + + + @Column(name = "lastUpdt", nullable = true) + @UpdateTimestamp + private LocalDateTime lastUpdt; + + + @Column(name = "expires_dt", nullable = true) + private LocalDateTime expiresDt; + + + @Column(name = "prcs_yn", nullable = true) + private String prcsYn; + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/VKakaoNoticeInfo.java b/src/main/java/cokr/xit/ens/biz/iup/domain/VKakaoNoticeInfo.java new file mode 100644 index 0000000..3552b3b --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/VKakaoNoticeInfo.java @@ -0,0 +1,41 @@ +package cokr.xit.ens.biz.iup.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.annotations.DynamicUpdate; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + + + +@Entity +//@Data +@Getter +@ToString +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "V_KAKAO_NOTICE_INFO") +public class VKakaoNoticeInfo { + + @Id + private String enfrcLevMastrId; + + + private String userBirth; + + + private String amount; + + + private String payExpireDate; + + + private String detailPasngChrgeSm; + + + private String detailAdiPasngChrgeSm; +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/VKakaoNoticeInfoSn.java b/src/main/java/cokr/xit/ens/biz/iup/domain/VKakaoNoticeInfoSn.java new file mode 100644 index 0000000..1b27021 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/VKakaoNoticeInfoSn.java @@ -0,0 +1,43 @@ +package cokr.xit.ens.biz.iup.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.persistence.*; +import java.util.Objects; + +@Entity +//@Data +@Getter +@ToString +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "v_kakao_notice_info_sn", schema = "", catalog = "") +public class VKakaoNoticeInfoSn { + + @Id + @Column(name = "data_id", nullable = true, length = 24) + private String dataId; + + + @Column(name = "user_birth", nullable = true, length = 4000) + private String userBirth; + + + @Column(name = "AMOUNT", nullable = true, precision = 0) + private Long amount; + + + @Column(name = "pay_expire_date", nullable = true, length = 8) + private String payExpireDate; + + + @Column(name = "detail_pasng_chrge_sm", nullable = true, precision = 0) + private Long detailPasngChrgeSm; + + + @Column(name = "detail_adi_pasng_chrge_sm", nullable = true, precision = 0) + private Long detailAdiPasngChrgeSm; +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/ids/TbSendResultIds.java b/src/main/java/cokr/xit/ens/biz/iup/domain/ids/TbSendResultIds.java new file mode 100644 index 0000000..57018d2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/ids/TbSendResultIds.java @@ -0,0 +1,28 @@ +package cokr.xit.ens.biz.iup.domain.ids; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.Column; +import java.io.Serializable; + +@Getter +@Setter +@EqualsAndHashCode +@NoArgsConstructor +public class TbSendResultIds implements Serializable { + + @Column(name = "lnk_input_id", nullable = false) + private Long lnkInputId; + + + @Column(name = "data_id", nullable = false) + private String dataId; + + + @Column(name = "prcs_odr", nullable = false) + private String prcsOdr; +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/FsJobRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/FsJobRepository.java new file mode 100644 index 0000000..073c160 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/FsJobRepository.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.FsJob; +import org.springframework.data.jpa.repository.JpaRepository; + + +public interface FsJobRepository extends JpaRepository { + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbEnfrcLevMastrRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbEnfrcLevMastrRepository.java new file mode 100644 index 0000000..af9db68 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbEnfrcLevMastrRepository.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.TbEnfrcLevMastr; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + + +public interface TbEnfrcLevMastrRepository extends JpaRepository { + + Optional findByEnfrcLevMastrIdAndEnfrcLevMastrProcessSttusAndDeleteAt(String enfrcLevMastrId, String enfrcLevMastrProcessSttus, String deleteAt); +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbEnfrcLevRcivRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbEnfrcLevRcivRepository.java new file mode 100644 index 0000000..b6e8954 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbEnfrcLevRcivRepository.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.TbEnfrcLevRciv; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + + +public interface TbEnfrcLevRcivRepository extends JpaRepository { + + List findAllByEnfrcLevMastrIdAndDeleteAt(String enfrcLevMastrId, String deleteAt); +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataBulkTestCustomRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataBulkTestCustomRepository.java new file mode 100644 index 0000000..cd50429 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataBulkTestCustomRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import java.util.List; + +public interface TbInputDataBulkTestCustomRepository { + + public void saveAll(List list); +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataBulkTestCustomRepositoryImpl.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataBulkTestCustomRepositoryImpl.java new file mode 100644 index 0000000..8009695 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataBulkTestCustomRepositoryImpl.java @@ -0,0 +1,75 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.TbInputDataBulkTest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.jdbc.core.BatchPreparedStatementSetter; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Repository +@RequiredArgsConstructor +public class TbInputDataBulkTestCustomRepositoryImpl implements TbInputDataBulkTestCustomRepository{ + private final JdbcTemplate jdbcTemplate; + + @Value("${spring.jpa.properties.hibernate.jdbc.batch_size}") + private int batchSize; + + + @Override + public void saveAll(List list) { + int batchCount = 0; + List subItems = new ArrayList<>(); + for (int i = 0; i < list.size(); i++) { + subItems.add(list.get(i)); + if ((i + 1) % batchSize == 0) { + batchCount = batchInsert(batchSize, batchCount, subItems); + } + } + if (!subItems.isEmpty()) { + batchCount = batchInsert(batchSize, batchCount, subItems); + } + log.info("batchCount: " + batchCount); + + } + + private int batchInsert(int batchSize, int batchCount, List list) { + +// jdbcTemplate.batchUpdate("INSERT INTO tb_input_data_bulk_test (birthday, car_no, data_id, gender, msg_data, msg_dtl_data, name, pay_status_cd, pay_url, reg_dt, reg_id, sid, upd_dt, upd_id, id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + jdbcTemplate.batchUpdate("INSERT INTO tb_input_data_bulk_test (birthday, car_no, data_id, gender, msg_data, msg_dtl_data, name, pay_status_cd, pay_url, reg_dt, reg_id, sid, upd_dt, upd_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setString(1, list.get(i).getBirthday()); + ps.setString(2, list.get(i).getCarNo()); + ps.setString(3, list.get(i).getDataId()); + ps.setString(4, list.get(i).getGender()); + ps.setString(5, list.get(i).getMsgData()); + ps.setString(6, list.get(i).getMsgDtlData()); + ps.setString(7, list.get(i).getName()); + ps.setString(8, list.get(i).getPayStatusCd()); + ps.setString(9, list.get(i).getPayUrl()); + ps.setDate(10, list.get(i).getRegDt()); + ps.setString(11, list.get(i).getRegId()); + ps.setString(12, list.get(i).getSid()); + ps.setDate(13, list.get(i).getUpdDt()); + ps.setString(14, list.get(i).getUpdId()); +// ps.setLong(15, list.get(i).getId()); + } + @Override + public int getBatchSize() { + return list.size(); + } + }); + list.clear(); + batchCount++; + return batchCount; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataBulkTestRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataBulkTestRepository.java new file mode 100644 index 0000000..cc9002b --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataBulkTestRepository.java @@ -0,0 +1,7 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.TbInputDataBulkTest; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TbInputDataBulkTestRepository extends JpaRepository { +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataXitCustomRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataXitCustomRepository.java new file mode 100644 index 0000000..db41c66 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataXitCustomRepository.java @@ -0,0 +1,22 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.code.IupSendTypeCd; +import cokr.xit.ens.biz.iup.domain.TbInputDataXit; + +import java.util.List; +import java.util.Optional; + +public interface TbInputDataXitCustomRepository { + + Optional findFetchByDataId(String dataId); + + List findAllFetchByLnkInputId(Long lnkInputId); + + String findDataIdFirstByLnkInputId(Long lnkInputId); + + Optional findLastSendMastIdByLnkInputIdAndSendType(Long lnkInputId, IupSendTypeCd sendTypeCd); + + List findAllByNoFwdPayResult(); + + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataXitCustomRepositoryImpl.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataXitCustomRepositoryImpl.java new file mode 100644 index 0000000..92b4505 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataXitCustomRepositoryImpl.java @@ -0,0 +1,118 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.code.IupSendTypeCd; +import cokr.xit.ens.biz.iup.domain.TbInputDataXit; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import com.querydsl.core.types.dsl.DateTemplate; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Repository; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Optional; + +import static cokr.xit.ens.biz.iup.domain.QFsJob.fsJob; +import static cokr.xit.ens.biz.iup.domain.QTbInputDataXit.tbInputDataXit; +import static cokr.xit.ens.biz.iup.domain.QTbInputXit.tbInputXit; +import static cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.QBillHist.billHist; +import static cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.QIntgrnSendDetail.intgrnSendDetail; +import static cokr.xit.ens.modules.kkoalimtalk.domain.QSendDetailKkoAlimtalk.sendDetailKkoAlimtalk; + +@Slf4j +@Repository +@RequiredArgsConstructor +public class TbInputDataXitCustomRepositoryImpl implements TbInputDataXitCustomRepository { + + private final JPAQueryFactory query; + + @Override + public Optional findFetchByDataId(String dataId) { + return Optional.ofNullable(query.selectFrom(tbInputDataXit) + .innerJoin(tbInputDataXit.tbInputXit, tbInputXit) + .fetchJoin() + .innerJoin(tbInputXit.fsJob, fsJob) + .fetchJoin() + .where(tbInputDataXit.dataId.eq(dataId)) + .fetchOne()); + } + + @Override + public List findAllFetchByLnkInputId(Long lnkInputId) { + return query.selectFrom(tbInputDataXit) + .innerJoin(tbInputDataXit.tbInputXit, tbInputXit).fetchJoin() + .innerJoin(tbInputXit.fsJob, fsJob).fetchJoin() + .where(tbInputDataXit.tbInputXit.lnkInputId.eq(lnkInputId)) + .fetch(); + } + + + @Override + public String findDataIdFirstByLnkInputId(Long lnkInputId) { + return query.select(tbInputDataXit.dataId) + .from(tbInputDataXit) + .where(tbInputDataXit.tbInputXit.lnkInputId.eq(lnkInputId)) + .fetchFirst(); + } + + + @Override + public Optional findLastSendMastIdByLnkInputIdAndSendType(Long lnkInputId, IupSendTypeCd sendTypeCd) { + if (IupSendTypeCd.KP.equals(sendTypeCd)) +// return Optional.ofNullable(query.select(sendDetailKkoMydoc.sendMast.sendMastId) +// .from(sendDetailKkoMydoc) +//// .where(sendDetailKkoMydoc.propExternalDocumentUuid.in(findDataIdsByLnkInputId(lnkInputId))) +// .where(sendDetailKkoMydoc.propExternalDocumentUuid.eq(findExternalDocumentUuidByLnkInputId(lnkInputId))) +// .groupBy(sendDetailKkoMydoc.sendMast.sendMastId) +// .orderBy(sendDetailKkoMydoc.sendMast.sendMastId.desc()) +// .fetchFirst()); + return Optional.ofNullable(query.select(intgrnSendDetail.intgrnSendMast.intSendMastId) + .from(intgrnSendDetail) + .where(intgrnSendDetail.linkedUuid.eq(findExternalDocumentUuidByLnkInputId(lnkInputId))) + .groupBy(intgrnSendDetail.intgrnSendMast.intSendMastId) + .orderBy(intgrnSendDetail.intgrnSendMast.intSendMastId.desc()) + .fetchFirst()); + else if (IupSendTypeCd.NI.equals(sendTypeCd)) + return Optional.ofNullable(query.select(sendDetailKkoAlimtalk.sendMast.sendMastId) + .from(sendDetailKkoAlimtalk) +// .where(sendDetailKkoAlimtalk.msgIdx.in(findDataIdsByLnkInputId(lnkInputId))) + .where(sendDetailKkoAlimtalk.msgIdx.eq(findExternalDocumentUuidByLnkInputId(lnkInputId))) + .groupBy(sendDetailKkoAlimtalk.sendMast.sendMastId) + .orderBy(sendDetailKkoAlimtalk.sendMast.sendMastId.desc()) + .fetchFirst()); + else + return Optional.ofNullable(null); + } + + private String findExternalDocumentUuidByLnkInputId(Long lnkInputId) { + return query.select(tbInputDataXit.linkedUuid) + .from(tbInputDataXit) + .where(tbInputDataXit.tbInputXit.lnkInputId.eq(lnkInputId)) + .fetchFirst(); + } + + + @Override + public List findAllByNoFwdPayResult() { + LocalDateTime fromDate = LocalDateTime.of(2022, 07, 04, 00, 00, 00); + LocalDateTime toDate = LocalDateTime.of(2022, 07, 05, 15, 00, 00); + + DateTemplate from = Expressions.dateTemplate(LocalDateTime.class, "TO_DATE({0}, {1})", fromDate.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")), "yyyyMMddHH24miss"); + DateTemplate to = Expressions.dateTemplate(LocalDateTime.class, "TO_DATE({0}, {1})", toDate.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")), "yyyyMMddHH24miss"); + return query.select(tbInputDataXit) + .from(tbInputDataXit) + .innerJoin(tbInputDataXit.tbInputXit, tbInputXit).fetchJoin() +// .innerJoin(kkoBillHist).on(kkoBillHist.billerUserKey.eq(tbInputDataXit.linkedUuid)).fetchJoin() + .innerJoin(billHist).on(billHist.billSe.eq(BillSeCd.bpKko).and(billHist.linkedUuid.eq(tbInputDataXit.linkedUuid))).fetchJoin() + .where( + billHist.reqSe.eq(BillReqSeCd.US_PAYRSLT) + .and(tbInputXit.runDt.between(from, to)) + .and(billHist.registDt.between(from, to)) + ) + .fetch(); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataXitRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataXitRepository.java new file mode 100644 index 0000000..2112e86 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataXitRepository.java @@ -0,0 +1,16 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.TbInputDataXit; +import cokr.xit.ens.biz.iup.domain.TbInputXit; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Optional; + +public interface TbInputDataXitRepository extends JpaRepository, TbInputDataXitCustomRepository { + + List findAllByTbInputXit(TbInputXit tbInputXit); + + Optional findByLinkedUuid(String linkedUuid); + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputXitCustomRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputXitCustomRepository.java new file mode 100644 index 0000000..a42eb11 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputXitCustomRepository.java @@ -0,0 +1,13 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.code.IupPrcsCd; +import cokr.xit.ens.biz.iup.code.IupSendTypeCd; +import cokr.xit.ens.biz.iup.domain.TbInputXit; + +import java.util.List; +import java.util.Optional; + +public interface TbInputXitCustomRepository { + Optional findByPrcsCdAndSendTypeAndId(IupPrcsCd prcsCd, IupSendTypeCd sendType, Long lnkInputId); + List findAllByPrcsCdInAndSendType(List prcsCds, IupSendTypeCd sendType); +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputXitCustomRepositoryImpl.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputXitCustomRepositoryImpl.java new file mode 100644 index 0000000..7af8850 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputXitCustomRepositoryImpl.java @@ -0,0 +1,51 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.code.IupPrcsCd; +import cokr.xit.ens.biz.iup.code.IupSendTypeCd; +import cokr.xit.ens.biz.iup.domain.TbInputXit; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +import static cokr.xit.ens.biz.iup.domain.QFsJob.fsJob; +import static cokr.xit.ens.biz.iup.domain.QTbInputXit.tbInputXit; + +@Slf4j +@Repository +@RequiredArgsConstructor +public class TbInputXitCustomRepositoryImpl implements TbInputXitCustomRepository{ + + private final JPAQueryFactory query; + + @Override + public Optional findByPrcsCdAndSendTypeAndId(IupPrcsCd prcsCd, IupSendTypeCd sendType, Long lnkInputId) { + return Optional.ofNullable(query.selectFrom(tbInputXit) + .innerJoin(tbInputXit.fsJob, fsJob) + .fetchJoin() + .where( + tbInputXit.prcsCd.eq(prcsCd) + .and(tbInputXit.sendType.eq(sendType)) + .and(tbInputXit.lnkInputId.eq(lnkInputId)) + ) + .fetchOne()); + } + + @Override + public List findAllByPrcsCdInAndSendType(List prcsCds, IupSendTypeCd sendType) { + return query.selectFrom(tbInputXit) + .innerJoin(tbInputXit.fsJob, fsJob) + .fetchJoin() + .where( + tbInputXit.prcsCd.in(prcsCds) + .and(tbInputXit.sendType.eq(sendType)) + ) + .fetch(); + } + + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputXitRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputXitRepository.java new file mode 100644 index 0000000..2a1df72 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputXitRepository.java @@ -0,0 +1,11 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.TbInputXit; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface TbInputXitRepository extends JpaRepository, TbInputXitCustomRepository { + + List findAllByLnkInputIdIn(List lnkInputIds); +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbIupBillPayHistRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbIupBillPayHistRepository.java new file mode 100644 index 0000000..2cc3432 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbIupBillPayHistRepository.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.TbIupBillPayHist; +import org.springframework.data.jpa.repository.JpaRepository; + + +public interface TbIupBillPayHistRepository extends JpaRepository { + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbKakaoPayResultRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbKakaoPayResultRepository.java new file mode 100644 index 0000000..e1126fd --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbKakaoPayResultRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.TbKakaoPayResult; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TbKakaoPayResultRepository extends JpaRepository { + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbNaverPayResultRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbNaverPayResultRepository.java new file mode 100644 index 0000000..a5e2367 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbNaverPayResultRepository.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.TbKakaoPayResult; +import cokr.xit.ens.biz.iup.domain.TbNaverPayResult; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TbNaverPayResultRepository extends JpaRepository { + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbSendResultCustomRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbSendResultCustomRepository.java new file mode 100644 index 0000000..83b7bf8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbSendResultCustomRepository.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.TbSendResult; + +import java.util.List; + + +public interface TbSendResultCustomRepository { + void modifyByTbSendResults(List list); + + Boolean findExistsByLnkInputIdAndPrcsOdr(Long lnkInputId, String prcsOdr); +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbSendResultRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbSendResultRepository.java new file mode 100644 index 0000000..88925fb --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbSendResultRepository.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.TbSendResult; +import org.springframework.data.jpa.repository.JpaRepository; + + +public interface TbSendResultRepository extends JpaRepository, TbSendResultCustomRepository { + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbSendResultRepositoryImpl.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbSendResultRepositoryImpl.java new file mode 100644 index 0000000..e2d02c9 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbSendResultRepositoryImpl.java @@ -0,0 +1,53 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.TbSendResult; +import cokr.xit.ens.core.utils.CmmnUtil; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +import static cokr.xit.ens.biz.iup.domain.QTbSendResult.tbSendResult; + +@RequiredArgsConstructor +public class TbSendResultRepositoryImpl implements TbSendResultCustomRepository { + + private final JPAQueryFactory query; + + @Override + public void modifyByTbSendResults(List list) { + list.forEach(data -> query.update(tbSendResult) + .set(tbSendResult.prcsOdr, data.getPrcsOdr()) + .set(tbSendResult.sendSttusCd, data.getSendSttusCd()) + .set(tbSendResult.sendTrySttusCd, data.getSendTrySttusCd()) + .set(tbSendResult.sendType, data.getSendType()) + .set(tbSendResult.runDt, data.getRunDt()) + .set(tbSendResult.bizSendDt, data.getBizSendDt()) + .set(tbSendResult.bizRecvDt, data.getBizRecvDt()) + .set(tbSendResult.bizReadDt, data.getBizReadDt()) + .set(tbSendResult.bizErrMsg, data.getBizErrMsg()) + .set(tbSendResult.regId, data.getRegId()) +// .set(tbSendResult.regDt, data.getRegDt()) + .set(tbSendResult.lastUpdt, LocalDateTime.now()) + .set(tbSendResult.expiresDt, data.getExpiresDt()) + .set(tbSendResult.prcsYn, data.getPrcsYn()) + .where(tbSendResult.lnkInputId.eq(data.getLnkInputId()) + .and(tbSendResult.dataId.eq(data.getDataId())) + ) + .execute() + ); + + } + + @Override + public Boolean findExistsByLnkInputIdAndPrcsOdr(Long lnkInputId, String prcsOdr) { + Long result = query.select(tbSendResult.lnkInputId) + .from(tbSendResult) + .where(tbSendResult.lnkInputId.eq(lnkInputId) + .and(tbSendResult.prcsOdr.eq(prcsOdr)) + ) + .fetchFirst(); + return CmmnUtil.isEmpty(result) ? false : true; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoRepository.java new file mode 100644 index 0000000..d570022 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoRepository.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.VKakaoNoticeInfo; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface VKakaoNoticeInfoRepository extends JpaRepository { + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoSnRepository.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoSnRepository.java new file mode 100644 index 0000000..f689db7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoSnRepository.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import cokr.xit.ens.biz.iup.domain.VKakaoNoticeInfoSn; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface VKakaoNoticeInfoSnRepository extends JpaRepository { + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/init/IupJpaRunner.java b/src/main/java/cokr/xit/ens/biz/iup/init/IupJpaRunner.java new file mode 100644 index 0000000..c2026fe --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/init/IupJpaRunner.java @@ -0,0 +1,142 @@ +package cokr.xit.ens.biz.iup.init; + +import cokr.xit.ens.core.init.InitJpaRunner; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.OrgMngDTO; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Component +@Transactional +@Profile({"prod-iup", "local-maria", "local-oracle"}) +public class IupJpaRunner extends InitJpaRunner { + ObjectMapper mapper = new ObjectMapper(); + + @Override + protected List createOrgMngDTO() { + List list = new ArrayList<>(); + list.add(createOrgMngDTO("0001", "", "관리지원센터", "N", null, null)); + list.add(createOrgMngDTO("0002", "ThbGXS13oaidCCOk", "경수고속도로", "Y", "http://190.100.100.12/api/kakao/prepay", "http://190.100.100.12/api/kakao/pay-result")); + list.add(createOrgMngDTO("0003", "jTsUoCwm3BSOANcJ", "인천대교", "Y", "http://200.200.22.13:8080/IDTCS/kakao/prepay", "http://200.200.22.13:8080/IDTCS/kakao/pay-result")); + list.add(createOrgMngDTO("0004", "MfhmiR2oif0j5f3C", "인천공항하이웨이", "Y", "http://211.195.163.91:8080/api/kakao/prepay", "http://211.195.163.91:8080/api/kakao/pay-result")); + list.add(createOrgMngDTO("0005", "dtX0rzX4IyPnR0Zw", "서울고속도로", "Y", "http://172.20.11.10:8080/kakao/prepay.jsp", "http://172.20.11.10:8080/kakao/pay-result.jsp")); + return list; + } + + + @Override + protected List> createTmpltMngDTO() { + List> list = new ArrayList<>(); + list.add(mapper.convertValue(createTmpltMngKkoAlimtalk("0001", "A0001", "CEPHIS001", "한국교통연구원 민자도로 관리지원센터 미납통행료 납부고지서", "~~@@!!ORG_NM!!@@~~에서 ~~@@!!TARGET_NAME!!@@~~님께 발송한 미납통행료 고지서가 도착했습니다.\n" + + "\n" + + "민자도로 미납통행료 고지서\n" + + "\n" + + "□ 차량번호 : ~~@@!!CAR_NO!!@@~~\n" + + "□ 미납발생 노선 : ~~@@!!COMPANY!!@@~~\n" + + "□ 미납발생 기간 : ~~@@!!TERM!!@@~~\n" + + "□ 납부금액 : ~~@@!!FEE!!@@~~원(~~@@!!COUNT!!@@~~건)\n" + + "□ 납부기한 : ~~@@!!DEADLINE!!@@~~\n" + + "□ 납부방법 : \n" + + "① 하단의 (납부하기) 클릭\n" + + "② 가상계좌 납부\n" + + "~~@@!!BANK_ACCOUNT!!@@~~\n" + + "\n" + + "※ 알림톡 수신 시 종이고지서는 발송되지 않습니다.\n" + + "\n" + + "문의처 : ~~@@!!REP_CALL_NO!!@@~~", "Y") + , Map.class)); + list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.nvSigntalk, null, "0001", "A0002", "민자도로 미납통행료 독촉장", "소유차량(#{CAR_NO})의 미납통행료 독촉장", "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, "044-211-3377", "문의처", "Y", "Y", "Y") + , createTmpltMngNvSigntalk(null, null, null, null, null, "044-211-3377", "Y", "Y", "N", "{\"data\":[{\"내용\":\"소유차량(#{CAR_NO})의 미납통행료 독촉장\"}]}")) + , Map.class)); + list.add(mapper.convertValue(createTmpltMngKkoAlimtalk("0001", "A0003", "CEPHIS001", "통행료 미납에 따른 예금 압류 예고 안내", "~~@@!!ORG_NM!!@@~~ 에서 ~~@@!!TARGET_NAME!!@@~~ 님께 발송한 통행료 미납에 따른 예금 압류 예고 안내문이 도착했습니다.\n" + + "\n" + + "통행료 미납에 따른 예금 압류 예고 안내\n" + + "\n" + + "민자도로 관리지원센터에서는 ~~@@!!NAME!!@@~~님께서 통행료 납부를 하지 않을 시 유료도로법 제21조 제6항에 따라 예금압류를 진행할 예정입니다.\n" + + "예금이 압류되면 입출금, 계좌이체를 할 수 없어 채무연체 등 불이익을 입을 수 있고, 은행 영업일 기준으로 24시간 이내에 압류해제가 가능하지 않음을 알려드립니다. \n" + + "\n" + + "□ 차량번호 : ~~@@!!CAR_NO!!@@~~\n" + + "□ 미납발생 노선 : ~~@@!!COMPANY!!@@~~\n" + + "□ 미납발생 기간 : ~~@@!!TERM!!@@~~\n" + + "□ 납부금액 : ~~@@!!FEE!!@@~~원(~~@@!!COUNT!!@@~~건)\n" + + "□ 납부방법 : ~~@@!!METHOD!!@@~~\n" + + "~~@@!!BANK_ACCOUNT!!@@~~\n" + + "□ 납부기한 : ~~@@!!DEADLINE!!@@~~까지\n" + + "□ 민자도로 관리지원센터 : ~~@@!!CALL_NO!!@@~~\n" + + "\n" + + "문의처 : ~~@@!!REP_CALL_NO!!@@~~", "Y") + , Map.class)); + list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.nvSigntalk, null, "0002", "B0001", "용인-서울고속도로 미납통행료 1차 안내문", "소유차량(#{CAR_NO})의 미납통행료 1차 안내문", "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, "1599-2509", "문의처", "Y", "Y", "Y") + , createTmpltMngNvSigntalk(null, null, null, null, null, "1599-2509", "Y", "Y", "N", "{\"data\":[{\"내용\":\"소유차량(#{CAR_NO})의 미납통행료 1차 안내문\"}]}")) + , Map.class)); + list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.nvSigntalk, null, "0002", "B0002", "용인-서울고속도로 미납통행료 독촉장", "소유차량(#{CAR_NO})의 미납통행료 독촉장", "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, "1599-2509", "문의처", "Y", "Y", "Y") + , createTmpltMngNvSigntalk(null, null, null, null, null, "1599-2509", "Y", "Y", "N", "{\"data\":[{\"내용\":\"소유차량(#{CAR_NO})의 미납통행료 독촉장\"}]}")) + , Map.class)); + list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.nvSigntalk, null, "0002", "B1001", "용인-서울고속도로 미납통행료 2차 고지서", "소유차량(#{CAR_NO})의 미납통행료 2차 고지서", "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, "1599-2509", "문의처", "Y", "Y", "Y") + , createTmpltMngNvSigntalk(null, null, null, null, null, "1599-2509", "Y", "Y", "N", "{\"data\":[{\"내용\":\"소유차량(#{CAR_NO})의 미납통행료 2차 고지서\"}]}")) + , Map.class)); + list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.nvSigntalk, null, "0003", "C0001", "인천대교 고속도로 미납통행료 1차 안내문", "소유차량(#{CAR_NO})의 미납통행료 1차 안내문", "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, "032-745-8200", "문의처", "Y", "Y", "Y") + , createTmpltMngNvSigntalk(null, null, null, null, null, "032-745-8200", "Y", "Y", "N", "{\"data\":[{\"내용\":\"소유차량(#{CAR_NO})의 미납통행료 1차 안내문\"}]}")) + , Map.class)); + list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.nvSigntalk, null, "0003", "C0002", "인천대교 고속도로 미납통행료 독촉장", "소유차량(#{CAR_NO})의 미납통행료 독촉장", "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, "032-745-8200", "문의처", "Y", "Y", "Y") + , createTmpltMngNvSigntalk(null, null, null, null, null, "032-745-8200", "Y", "Y", "N", "{\"data\":[{\"내용\":\"소유차량(#{CAR_NO})의 미납통행료 독촉장\"}]}")) + , Map.class)); + list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.nvSigntalk, null, "0003", "C1001", "인천대교 고속도로 미납통행료 2차 고지서", "소유차량(#{CAR_NO})의 미납통행료 2차 고지서", "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, "032-745-8200", "문의처", "Y", "Y", "Y") + , createTmpltMngNvSigntalk(null, null, null, null, null, "032-745-8200", "Y", "Y", "N", "{\"data\":[{\"내용\":\"소유차량(#{CAR_NO})의 미납통행료 2차 고지서\"}]}")) + , Map.class)); + list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.nvSigntalk, null, "0004", "D0001", "인천국제공항 고속도로 미납통행료 1차 안내문", "소유차량(#{CAR_NO})의 미납통행료 1차 안내문", "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, "032-560-6200", "문의처", "Y", "Y", "Y") + , createTmpltMngNvSigntalk(null, null, null, null, null, "032-560-6200", "Y", "Y", "N", "{\"data\":[{\"내용\":\"소유차량(#{CAR_NO})의 미납통행료 1차 안내문\"}]}")) + , Map.class)); + list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.nvSigntalk, null, "0004", "D0002", "인천국제공항 고속도로 미납통행료 독촉장", "소유차량(#{CAR_NO})의 미납통행료 독촉장", "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, "032-560-6200", "문의처", "Y", "Y", "Y") + , createTmpltMngNvSigntalk(null, null, null, null, null, "032-560-6200", "Y", "Y", "N", "{\"data\":[{\"내용\":\"소유차량(#{CAR_NO})의 미납통행료 독촉장\"}]}")) + , Map.class)); + list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.nvSigntalk, null, "0004", "D1001", "인천국제공항 고속도로 미납통행료 2차 고지서", "소유차량(#{CAR_NO})의 미납통행료 2차 고지서", "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, "032-560-6200", "문의처", "Y", "Y", "Y") + , createTmpltMngNvSigntalk(null, null, null, null, null, "032-560-6200", "Y", "Y", "N", "{\"data\":[{\"내용\":\"소유차량(#{CAR_NO})의 미납통행료 2차 고지서\"}]}")) + , Map.class)); + list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.nvSigntalk, null, "0005", "E0001", "수도권제1순환 고속도로 미납통행료 1차 안내문", "소유차량(#{CAR_NO})의 미납통행료 1차 안내문", "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, "영업소마다 다름", "문의처", "Y", "Y", "N") + , createTmpltMngNvSigntalk(null, null, null, null, null, "영업소마다 다름", "Y", "Y", "N", "{\"data\":[{\"내용\":\"소유차량(#{CAR_NO})의 미납통행료 1차 안내문\"}]}")) + , Map.class)); + list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.nvSigntalk, null, "0005", "E0002", "수도권제1순환 고속도로 미납통행료 독촉장", "소유차량(#{CAR_NO})의 미납통행료 독촉장", "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, "영업소마다 다름", "문의처", "Y", "Y", "N") + , createTmpltMngNvSigntalk(null, null, null, null, null, "영업소마다 다름", "Y", "Y", "N", "{\"data\":[{\"내용\":\"소유차량(#{CAR_NO})의 미납통행료 독촉장\"}]}")) + , Map.class)); + list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.nvSigntalk, null, "0005", "E1001", "수도권제1순환 고속도로 미납통행료 2차 고지서", "소유차량(#{CAR_NO})의 미납통행료 2차 고지서", "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, "영업소마다 다름", "문의처", "Y", "Y", "N") + , createTmpltMngNvSigntalk(null, null, null, null, null, "영업소마다 다름", "Y", "Y", "N", "{\"data\":[{\"내용\":\"소유차량(#{CAR_NO})의 미납통행료 2차 고지서\"}]}") + ) + , Map.class)); + return list; + } + + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/iup/signtalk/model/IupSigntalkReqVO.java b/src/main/java/cokr/xit/ens/biz/iup/signtalk/model/IupSigntalkReqVO.java new file mode 100644 index 0000000..d696f49 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/model/IupSigntalkReqVO.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.biz.iup.signtalk.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +@Getter +@Schema(name = "IupSigntalkReqVO") +public class IupSigntalkReqVO { + + @Schema(required = true, title = "연계입수 아이디", example = " ") + private Long lnkInputId; +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/signtalk/presentation/IupSigntalkController.java b/src/main/java/cokr/xit/ens/biz/iup/signtalk/presentation/IupSigntalkController.java new file mode 100644 index 0000000..2d45730 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/presentation/IupSigntalkController.java @@ -0,0 +1,66 @@ +package cokr.xit.ens.biz.iup.signtalk.presentation; + +import cokr.xit.ens.biz.iup.signtalk.model.IupSigntalkReqVO; +import cokr.xit.ens.biz.iup.signtalk.service.IupSigntalkService; +import cokr.xit.ens.core.aop.EnsResponseVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "iupSigntalkController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class IupSigntalkController { + + private final IupSigntalkService iupSigntalkService; + + @Operation(summary = "접수") + @PostMapping(value = "/iup/signtalk/accept", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity accept(@RequestBody IupSigntalkReqVO reqDTO){ + EnsResponseVO responseVO = iupSigntalkService.accept(reqDTO.getLnkInputId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + @Operation(summary = "접수(일괄)") + @PostMapping(value = "/iup/signtalk/accept/all", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity acceptAll(){ + EnsResponseVO responseVO = iupSigntalkService.acceptAll(); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + +// @Operation(summary = "제작") +//// @PutMapping(value = "/iup/signtalk/re/make", produces = MediaType.APPLICATION_JSON_VALUE) +// @PostMapping(value = "/iup/signtalk/re/make", produces = MediaType.APPLICATION_JSON_VALUE) +// public ResponseEntity reMake(@RequestBody iupSigntalkReqVO reqDTO){ +// EnsResponseVO responseVO = iupMydocService.reMake(reqDTO.getLnkInputId()); +// return new ResponseEntity(responseVO, HttpStatus.OK); +// } + + @Operation(summary = "전송") +// @PutMapping(value = "/iup/signtalk/re/send", produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/iup/signtalk/re/send", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity reSend(@RequestBody IupSigntalkReqVO reqDTO){ + EnsResponseVO responseVO = iupSigntalkService.reSend(reqDTO.getLnkInputId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "전송결과가져오기") + @PostMapping(value = "/iup/signtalk/fetch", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity fetch(@RequestBody IupSigntalkReqVO reqDTO){ + EnsResponseVO responseVO = iupSigntalkService.fetch(reqDTO.getLnkInputId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + @Operation(summary = "전송결과가져오기(일괄)") + @PostMapping(value = "/iup/signtalk/fetch/all", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity fetchAll(){ + EnsResponseVO responseVO = iupSigntalkService.fetchAll(); + return new ResponseEntity(responseVO, HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/signtalk/sched/IupSigntalkScheduler.java b/src/main/java/cokr/xit/ens/biz/iup/signtalk/sched/IupSigntalkScheduler.java new file mode 100644 index 0000000..b39e3c2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/sched/IupSigntalkScheduler.java @@ -0,0 +1,47 @@ +package cokr.xit.ens.biz.iup.signtalk.sched; + +import cokr.xit.ens.biz.iup.signtalk.service.IupSigntalkService; +import cokr.xit.ens.core.aop.EnsResponseVO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Slf4j +//@Component +//@Profile("prod-iup") +@RequiredArgsConstructor +public class IupSigntalkScheduler { + + private final IupSigntalkService iupMydocService; + + /** + * 인증톡 접수 + * -. 인증톡 전송을 위해 IUP에 등록된 기초데이터를 ENS에 이관 등록 한다. + */ + @Scheduled(cron = "0 */5 * * * *") + public void accepted(){ + EnsResponseVO responseVO = iupMydocService.acceptAll(); + + log.info("======================================================="); + log.info("[IUP] 인증톡 접수처리 결과"); + log.info(responseVO.toString()); + log.info("======================================================="); + } + + + /** + * 인증톡 결과 가져오기 + * -. 전송이 완료된 인증톡 전송결과(성공/실패)를 ENS -> IUP 로 가져온다. + */ + @Scheduled(cron = "0 */15 * * * *") + public void fetched(){ + EnsResponseVO responseVO = iupMydocService.fetchAll(); + + log.info("======================================================="); + log.info("[IUP] 인증톡 요청문서정보 Fetch 결과"); + log.info(responseVO.toString()); + log.info("======================================================="); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/IupBillKkoPaySigntalkService.java b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/IupBillKkoPaySigntalkService.java new file mode 100644 index 0000000..2e0f04e --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/IupBillKkoPaySigntalkService.java @@ -0,0 +1,493 @@ +package cokr.xit.ens.biz.iup.signtalk.service; + +import cokr.xit.ens.biz.iup.billpay.api.IupKkoPayUseSysApiSpec; +import cokr.xit.ens.biz.iup.billpay.service.IupBillKkoPayUseSysService; +import cokr.xit.ens.biz.iup.domain.*; +import cokr.xit.ens.biz.iup.domain.repository.*; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.code.BillKkoErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoPayResultData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.TmpltMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.OrgMngRepository; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.TmpltMngRepository; +import com.google.gson.Gson; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@Service("iupBillKkoPayUseSysService_KP") +@RequiredArgsConstructor +public class IupBillKkoPaySigntalkService extends IupBillKkoPayUseSysService { + + + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + private final TmpltMngRepository sendTmpltMngRepository; + private final OrgMngRepository orgMngRepository; + private final TbInputDataXitRepository tbInputDataXitRepository; + private final VKakaoNoticeInfoRepository vKakaoNoticeInfoRepository; + private final VKakaoNoticeInfoSnRepository vKakaoNoticeInfoSnRepository; + // private final TbEnfrcLevRcivRepository tbEnfrcLevRcivRepository; + private final TbEnfrcLevMastrRepository tbEnfrcLevMastrRepository; + private final TbKakaoPayResultRepository tbKakaoPayResultRepository; + private final IupKkoPayUseSysApiSpec iupKkoPayApi; + private final JPAQueryFactory query; + + + /** + * 청구서 조회 + * + * @param mParam + * @return + */ + @Transactional(propagation = Propagation.NEVER) + public BillKkoApiRespDTO findNoticeInfo(Map mParam) { + Map data = (Map) mParam.get("data"); +// data.get("biller_user_key"); +// data.get("billed_year_month"); +// data.get("ordinal"); +// data.get("biller_notice_key"); + Map parameters = (Map) data.get("parameters"); +// data.get("user_birth"); + + + Map respData = null; + BillKkoApiRespDTO respVO = null; + BillKkoErrCd kkoBillErrCd = BillKkoErrCd.OK; + final String billerUserKey = Optional.ofNullable(data.get("biller_user_key")).isPresent() ? + String.valueOf(data.get("biller_user_key")) : null; + final String userBirth = Optional.ofNullable(data.get("user_birth")).isPresent() ? + String.valueOf(data.get("user_birth")) : null; + final String orgCd = Optional.ofNullable(parameters.get("orgCd")).isPresent() ? + String.valueOf(parameters.get("orgCd")) : null; + final String billUid = Optional.ofNullable(parameters.get("billUid")).isPresent() ? + String.valueOf(parameters.get("billUid")) : null; + + BillHist billHist = null; + try { + billHist = this.addBillHistByReqInfo(BillReqSeCd.NOTICE, billerUserKey, orgCd, billUid, mParam); + + + if (CmmnUtil.isEmpty(billerUserKey)) { + kkoBillErrCd = BillKkoErrCd.E801; + throw new EnsException(EnsErrCd.ERR401, "사용자식별키가 없습니다."); + } + if (CmmnUtil.isEmpty(orgCd)) { + kkoBillErrCd = BillKkoErrCd.E801; + throw new EnsException(EnsErrCd.ERR401, "기관코드가 없습니다."); + } + if (CmmnUtil.isEmpty(userBirth)) { + kkoBillErrCd = BillKkoErrCd.E801; + throw new EnsException(EnsErrCd.ERR401, "생년월일이 없습니다."); + } + + + Optional intgrnSendDetail = intgrnSendDetailRepository.findByLinkedUuid(billerUserKey); + if (!intgrnSendDetail.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR404, "일치하는 발송상세 자료가 없습니다."); + } + if (!orgCd.equals(intgrnSendDetail.get().getIntgrnSendMast().getOrgCd())) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR402, String.format("기관코드가 상이 합니다. ( 요청: %s 실제: %s )", orgCd, intgrnSendDetail.get().getIntgrnSendMast().getOrgCd())); + } + Optional orgMng = orgMngRepository.findById(orgCd); + if (!orgMng.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E801; + throw new EnsException(EnsErrCd.ERR404, "일치하는 기관정보가 없습니다."); + } + Optional sendTmpltMng = sendTmpltMngRepository.findFetchByOrgCdAndTmpltCdAndUseYn(orgCd, intgrnSendDetail.get().getIntgrnSendMast().getTmpltCd(), "Y"); + if (!sendTmpltMng.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E801; + throw new EnsException(EnsErrCd.ERR404, "일치하는 템플릿정보가 없습니다."); + } + Optional tbInputDataXit = tbInputDataXitRepository.findByLinkedUuid(billerUserKey); + if (!tbInputDataXit.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR404, "일치하는 발송상세정보가 없습니다."); + } +// final String dataId = tbInputDataXit.get().getDataId(); + final String dataId = billerUserKey; + + if ("Y".equals(orgMng.get().getKkoBpCsignYn())) { + Optional vKakaoNoticeInfoSn = vKakaoNoticeInfoSnRepository.findById(dataId); + if (!vKakaoNoticeInfoSn.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR404, "일치하는 단순미납부과 자료가 없습니다."); + } + if (!userBirth.equals(vKakaoNoticeInfoSn.get().getUserBirth())) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR402, String.format("생년월일이 일치하지 않습니다. (요청: %s 실제: %s)", userBirth, vKakaoNoticeInfoSn.get().getUserBirth())); + } + + + respData = this.respNoticeSnData(sendTmpltMng.get().getTitle(), orgMng.get(), vKakaoNoticeInfoSn.get()); + + } else if ("N".equals(orgMng.get().getKkoBpCsignYn())) { + if (dataId.length() < 20) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR403, "빌러코드가 20자리 미만 입니다."); + } + Optional vKakaoNoticeInfo = vKakaoNoticeInfoRepository.findById(dataId.substring(0, 20)); + if (!vKakaoNoticeInfo.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR404, "일치하는 강제징수부과 자료가 없습니다."); + } + if (!userBirth.equals(vKakaoNoticeInfo.get().getUserBirth())) { + kkoBillErrCd = BillKkoErrCd.E404; + throw new EnsException(EnsErrCd.ERR402, String.format("생년월일이 일치하지 않습니다. (요청: %s 실제: %s)", userBirth, vKakaoNoticeInfo.get().getUserBirth())); + } + + + respData = this.respNoticeData(sendTmpltMng.get().getTitle(), orgMng.get(), vKakaoNoticeInfo.get()); + + } else { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR999, "위탁업체여부 구분값이 등록되지 않았습니다."); + } + + respVO = BillKkoApiRespDTO.okBuilder() + .data(respData) + .build(); + + + this.modifyBillHistByRespInfo(billHist, respVO, null, null); + + } catch (EnsException e) { + respVO = BillKkoApiRespDTO.errBuilder() + .resCode(kkoBillErrCd.getCode()) + .message(kkoBillErrCd.getCodeNm()) + .build(); + + this.modifyBillHistByRespInfo(billHist, respVO, e.getErrCd(), e.getMessage()); + + } catch (Exception e) { + respVO = BillKkoApiRespDTO.errBuilder() + .resCode(BillKkoErrCd.E801.getCode()) + .message(BillKkoErrCd.E801.getCodeNm()) + .build(); + + this.modifyBillHistByRespInfo(billHist, respVO, EnsErrCd.ERR999, e.getMessage()); + } + + return respVO; + } + + + /** + * 납부 가능 조회 + * + * @param mParam + * @return + */ + @Transactional(propagation = Propagation.NEVER) + public BillKkoApiRespDTO findPrepayInfo(Map mParam) { + Map data = (Map) mParam.get("data"); +// data.get("biller_user_key"); +// data.get("billed_year_month"); +// data.get("ordinal"); +// data.get("biller_notice_key"); + Map parameters = (Map) data.get("parameters"); +// data.get("amount"); + + + BillKkoApiRespDTO respVO = null; + BillKkoErrCd kkoBillErrCd = BillKkoErrCd.OK; + final String billerUserKey = Optional.ofNullable(data.get("biller_user_key")).isPresent() ? + String.valueOf(data.get("biller_user_key")) : null; + final int amount = Optional.ofNullable(data.get("amount")).isPresent() ? + (int) data.get("amount") : 0; + final String orgCd = Optional.ofNullable(parameters.get("orgCd")).isPresent() ? + String.valueOf(parameters.get("orgCd")) : null; + final String billUid = Optional.ofNullable(parameters.get("billUid")).isPresent() ? + String.valueOf(parameters.get("billUid")) : null; + + BillHist billHist = null; + try { + billHist = this.addBillHistByReqInfo(BillReqSeCd.PREPAY, billerUserKey, orgCd, billUid, mParam); + + + if (CmmnUtil.isEmpty(billerUserKey)) { + kkoBillErrCd = BillKkoErrCd.E601; + throw new EnsException(EnsErrCd.ERR401, "사용자식별키가 없습니다."); + } + if (CmmnUtil.isEmpty(orgCd)) { + kkoBillErrCd = BillKkoErrCd.E601; + throw new EnsException(EnsErrCd.ERR401, "기관코드가 없습니다."); + } + + + +// Optional orgMng = orgMngRepository.findById(orgCd); +// if (!orgMng.isPresent()) { +// kkoBillErrCd = BillKkoErrCd.E601; +// throw new EnsException(EnsErrCd.ERR404, "일치하는 기관정보가 없습니다."); +// } +// Optional tbInputDataXit = tbInputDataXitRepository.findByLinkedUuid(billerUserKey); + Optional tbInputDataXit = this.getTbInputDataXitByLinkedUuid(billerUserKey); + if (!tbInputDataXit.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR404, "일치하는 발송상세정보가 없습니다."); + } + final FsJob fsJob = tbInputDataXit.get().getTbInputXit().getFsJob(); + final String dataId = tbInputDataXit.get().getDataId(); + + Optional vKakaoNoticeInfo = Optional.ofNullable(null); +// List tbEnfrcLevRcivs = new ArrayList<>(); + + + if ("Y".equals(fsJob.getBpEntrustYn())) { + Optional vKakaoNoticeInfoSn = vKakaoNoticeInfoSnRepository.findById(dataId); + if (!vKakaoNoticeInfoSn.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E502; + throw new EnsException(EnsErrCd.ERR404, "일치하는 단순미납 자료가 없습니다."); + } + + respVO = iupKkoPayApi.callApiByOrg(fsJob.getBpKkoPrepayApi(), mParam); + + if ("OK".equals(respVO.getRes_code())) + this.modifyBillHistByRespInfo(billHist, respVO, null, null); + else + this.modifyBillHistByRespInfo(billHist, respVO, EnsErrCd.ERR999, String.format("[%s] %s", respVO.getRes_code(), respVO.getMessage())); + + return respVO; + + } else if ("N".equals(fsJob.getBpEntrustYn())) { + if (dataId.length() < 20) { + kkoBillErrCd = BillKkoErrCd.E502; + throw new EnsException(EnsErrCd.ERR403, "빌러코드가 20자리 미만 입니다."); + } + + vKakaoNoticeInfo = vKakaoNoticeInfoRepository.findById(dataId.substring(0, 20)); + if (!vKakaoNoticeInfo.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E502; + throw new EnsException(EnsErrCd.ERR404, "일치하는 강제징수 자료가 없습니다."); + } + + +// tbEnfrcLevRcivs = tbEnfrcLevRcivRepository.findAllByEnfrcLevMastrIdAndDeleteAt(dataId.substring(0, 20), "N"); + Optional tbEnfrcLevMastr = tbEnfrcLevMastrRepository.findByEnfrcLevMastrIdAndEnfrcLevMastrProcessSttusAndDeleteAt(dataId.substring(0, 20), "04", "N"); + if (!tbEnfrcLevMastr.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E601; + throw new EnsException(EnsErrCd.ERR507, "납부가능 상태가 아닙니다."); + } + + } else { + kkoBillErrCd = BillKkoErrCd.E601; + throw new EnsException(EnsErrCd.ERR999, "위탁업체여부 구분값이 등록되지 않았습니다."); + } + + + if (CmmnUtil.isEmpty(vKakaoNoticeInfo.get().getAmount()) + || amount != Integer.parseInt(vKakaoNoticeInfo.get().getAmount())) { + kkoBillErrCd = BillKkoErrCd.E403; + throw new EnsException(EnsErrCd.ERR902 + , String.format("납부 가능 금액이 없거나 일치하지 않습니다. (요청금액:%s, 실제금액:%s)" + , amount + , vKakaoNoticeInfo.get().getAmount())); + } + if (amount > Integer.parseInt(vKakaoNoticeInfo.get().getAmount())) { + kkoBillErrCd = BillKkoErrCd.E501; + throw new EnsException(EnsErrCd.ERR902 + , String.format("납부 가능 금액을 초과했습니다. (요청금액:%s, 실제금액:%s)" + , amount + , vKakaoNoticeInfo.get().getAmount())); + } + if (!vKakaoNoticeInfo.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E502; + throw new EnsException(EnsErrCd.ERR404, "일치하는 청구서자료가 없습니다."); + } + if (CmmnUtil.isEmpty(vKakaoNoticeInfo.get().getPayExpireDate())) { + kkoBillErrCd = BillKkoErrCd.E601; + throw new EnsException(EnsErrCd.ERR401, "납부기한이 값이 없습니다."); + } + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); + if (Integer.parseInt(vKakaoNoticeInfo.get().getPayExpireDate()) < Integer.parseInt(simpleDateFormat.format(new Date()))) { + kkoBillErrCd = BillKkoErrCd.E506; + throw new EnsException(EnsErrCd.ERR902, "납부기한이 경과한 자료 입니다."); + } +// if (tbEnfrcLevRcivs.size() > 0) { +// kkoBillErrCd = BillKkoErrCd.E601; +// throw new EnsException(EnsErrCd.ERR903, "납부가 완료된 자료 입니다."); +// } + + + + respVO = BillKkoApiRespDTO.okBuilder() + .data(null) + .build(); + + this.modifyBillHistByRespInfo(billHist, respVO, null, null); + + } catch (EnsException e) { + respVO = BillKkoApiRespDTO.errBuilder() + .resCode(kkoBillErrCd.getCode()) + .message(kkoBillErrCd.getCodeNm()) + .build(); + + this.modifyBillHistByRespInfo(billHist, respVO, e.getErrCd(), e.getMessage()); + + } catch (Exception e) { + respVO = BillKkoApiRespDTO.errBuilder() + .resCode(BillKkoErrCd.E601.getCode()) + .message(BillKkoErrCd.E601.getCodeNm()) + .build(); + + this.modifyBillHistByRespInfo(billHist, respVO, EnsErrCd.ERR999, e.getMessage()); + } + + return respVO; + } + + /** + * 납부결과 저장 + * + * @param mParam + * @return + */ + @Transactional(propagation = Propagation.NEVER) + public BillKkoApiRespDTO addPayReultIfno(Map mParam) { + Map data = (Map) mParam.get("data"); + + Gson gson = new Gson(); + BillKkoPayResultData kkoBillPayResultVO = gson.fromJson(gson.toJson(data), BillKkoPayResultData.class); + + Map parameters = kkoBillPayResultVO.getParameters(); + + + BillKkoApiRespDTO respVO = null; + BillKkoErrCd kkoBillErrCd = BillKkoErrCd.OK; + final String orgCd = Optional.ofNullable(parameters.get("orgCd")).isPresent() ? + String.valueOf(parameters.get("orgCd")) : null; + final String billUid = Optional.ofNullable(parameters.get("billUid")).isPresent() ? + String.valueOf(parameters.get("billUid")) : null; + + BillHist kkoBillHist = null; + try { + kkoBillHist = this.addBillHistByReqInfo(BillReqSeCd.PAYRSLT, kkoBillPayResultVO.getBiller_user_key(), orgCd, billUid, mParam); + + + if (CmmnUtil.isEmpty(kkoBillPayResultVO.getBiller_user_key())) { + kkoBillErrCd = BillKkoErrCd.E601; + throw new EnsException(EnsErrCd.ERR401, "사용자식별키가 없습니다."); + } + if (CmmnUtil.isEmpty(orgCd)) { + kkoBillErrCd = BillKkoErrCd.E601; + throw new EnsException(EnsErrCd.ERR401, "기관코드가 없습니다."); + } + + + +// Optional orgMng = orgMngRepository.findById(orgCd); +// if (!orgMng.isPresent()) { +// kkoBillErrCd = BillKkoErrCd.E601; +// throw new EnsException(EnsErrCd.ERR404, "일치하는 기관정보가 없습니다."); +// } + Optional tbInputDataXit = this.getTbInputDataXitByLinkedUuid(kkoBillPayResultVO.getBiller_user_key()); + if (!tbInputDataXit.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR404, "일치하는 발송상세정보가 없습니다."); + } + final FsJob fsJob = tbInputDataXit.get().getTbInputXit().getFsJob(); + + if (!tbKakaoPayResultRepository.findById(kkoBillPayResultVO.getBiller_user_key()).isPresent()) + tbKakaoPayResultRepository.save(this.createTbKakaoPayResult(kkoBillPayResultVO)); + + + if ("Y".equals(fsJob.getBpEntrustYn())) { + respVO = iupKkoPayApi.callApiByOrg(fsJob.getBpKkoPayresultApi(), mParam); + + if (!"OK".equals(respVO.getRes_code())) + this.modifyBillHistByRespInfo(kkoBillHist, respVO, EnsErrCd.ERR600, String.format("[%s] %s", respVO.getRes_code(), respVO.getMessage())); + + return respVO; + + } else if ("N".equals(fsJob.getBpEntrustYn())) { + + } else { + kkoBillErrCd = BillKkoErrCd.E601; + throw new EnsException(EnsErrCd.ERR999, "위탁업체여부 구분값이 등록되지 않았습니다."); + } + + + respVO = BillKkoApiRespDTO.okBuilder() + .data(null) + .build(); + + + this.modifyBillHistByRespInfo(kkoBillHist, respVO, null, null); + } catch (EnsException e) { + respVO = BillKkoApiRespDTO.errBuilder() + .resCode(kkoBillErrCd.getCode()) + .message(kkoBillErrCd.getCodeNm()) + .build(); + + this.modifyBillHistByRespInfo(kkoBillHist, respVO, e.getErrCd(), e.getMessage()); + } catch (Exception e) { + respVO = BillKkoApiRespDTO.errBuilder() + .resCode(BillKkoErrCd.E601.getCode()) + .message(BillKkoErrCd.E601.getCodeNm()) + .build(); + + this.modifyBillHistByRespInfo(kkoBillHist, respVO, EnsErrCd.ERR999, e.getMessage()); + } + + return respVO; + } + + + private TbKakaoPayResult createTbKakaoPayResult(BillKkoPayResultData kkoBillPayResultVO) { + + + final String jobSe = "EL".equals(kkoBillPayResultVO.getBiller_user_key().substring(0, 2)) ? "2" : "1"; + + + return TbKakaoPayResult.builder() + .dataId(kkoBillPayResultVO.getBiller_user_key()) + .jobSe(jobSe) + .payMn(kkoBillPayResultVO.getPay_by()) + .payTy(kkoBillPayResultVO.getPay_type()) + .payDetail1(kkoBillPayResultVO.getPay_detail1()) + .payDetail2(kkoBillPayResultVO.getPay_detail2()) + .payDetail3(kkoBillPayResultVO.getPay_detail3()) + .payAmount(kkoBillPayResultVO.getPay_amount()) + .payFeeTy(kkoBillPayResultVO.getPay_fee_type()) + .payFeeAmount(kkoBillPayResultVO.getPay_fee()) + .payFeeVat(kkoBillPayResultVO.getPay_fee_tax()) + .excclcPrearngeDe(kkoBillPayResultVO.getAdjust_date()) + .payDt(kkoBillPayResultVO.getPaid_at()) + .payId(kkoBillPayResultVO.getPay_id()) + .payResultProcessSttus("0") +// .creatDt() + .crtr("ENS_SYS") +// .updtDt() +// .updusr() + .build(); + + } + + private Optional getTbInputDataXitByLinkedUuid(String linkedUuid) { + return Optional.ofNullable(query.select(QTbInputDataXit.tbInputDataXit) + .from(QTbInputDataXit.tbInputDataXit) + .innerJoin(QTbInputDataXit.tbInputDataXit.tbInputXit, QTbInputXit.tbInputXit) + .innerJoin(QTbInputDataXit.tbInputDataXit.tbInputXit.fsJob, QFsJob.fsJob) + .where(QTbInputDataXit.tbInputDataXit.linkedUuid.eq(linkedUuid)) + .fetchOne()); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/IupSigntalkService.java b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/IupSigntalkService.java new file mode 100644 index 0000000..a86936f --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/IupSigntalkService.java @@ -0,0 +1,167 @@ +package cokr.xit.ens.biz.iup.signtalk.service; + +import cokr.xit.ens.biz.iup.code.IupPrcsCd; +import cokr.xit.ens.biz.iup.code.IupSendTypeCd; +import cokr.xit.ens.biz.iup.domain.TbInputXit; +import cokr.xit.ens.biz.iup.domain.repository.TbInputXitRepository; +import cokr.xit.ens.biz.iup.signtalk.service.support.IupSigntalkAcceptor; +import cokr.xit.ens.biz.iup.signtalk.service.support.IupSigntalkFetcher; +import cokr.xit.ens.biz.iup.signtalk.service.support.IupSigntalkSender; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.event.IntgrnNotiSendReserveEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class IupSigntalkService { + + + private final TbInputXitRepository tbInputXitRepository; + + private final IupSigntalkAcceptor iupSigntalkAcceptor; + private final IupSigntalkSender iupSigntalkSender; + private final IupSigntalkFetcher iupSigntalkFetcher; + + private final ApplicationEventPublisher applicationEventPublisher; + + + /** + * 인증톡 접수(IUP -> ENS) + */ + @Transactional + public EnsResponseVO accept(Long lnkInputId) { + + try { + + TbInputXit tbInputXit = tbInputXitRepository.findByPrcsCdAndSendTypeAndId(IupPrcsCd.TGRG, IupSendTypeCd.KP, lnkInputId) + .orElseThrow(() -> new EnsException(EnsErrCd.ACPT404, "일치하는 자료가 없거나 \"등록(TGRG)\" 상태가 아닙니다.")); + + return this.accept(Arrays.asList(tbInputXit)).getResultInfo().get(0); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + } + + /** + * 인증톡 접수(IUP -> ENS) + */ + @Transactional + public EnsResponseVO> acceptAll() { + try { + + List tbInputXits = tbInputXitRepository.findAllByPrcsCdInAndSendType(Arrays.asList(IupPrcsCd.TGRG), IupSendTypeCd.KP); + if (CmmnUtil.isEmpty(tbInputXits)) + throw new EnsException(EnsErrCd.ACPT404, "\"등록(TGRG)\" 상태의 자료가 없습니다."); + + return this.accept(tbInputXits); + } catch (EnsException e) { + return EnsResponseVO.>errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + } + + private EnsResponseVO> accept(List tbInputXits) { + iupSigntalkAcceptor.statReady(tbInputXits.stream().map(row -> row.getLnkInputId()).collect(Collectors.toList())); + + List resultInfo = tbInputXits.stream() + .map(row -> iupSigntalkAcceptor.execute(row.getLnkInputId())) + .collect(Collectors.toList()); + + + List sendMastIds = resultInfo.stream() + .filter(ensResponseVO -> EnsErrCd.OK.equals(ensResponseVO.getErrCode())) + .map(ensResponseVO -> (Long) ((Map) ensResponseVO.getResultInfo()).get("intSendMastId")) + .collect(Collectors.toList()); + IntgrnNotiSendReserveEvent event = IntgrnNotiSendReserveEvent.builder() + .sendMastIds(sendMastIds) + .callback(() -> this.fetch(tbInputXits)) + .build(); + applicationEventPublisher.publishEvent(event); + + return EnsResponseVO.>okBuilder().resultInfo(resultInfo).build(); + } + +// /** +// * 인증톡 제작 재요청 +// * @param lnkInputId +// * @return +// */ +// public EnsResponseVO reMake(Long lnkInputId){ +// return iupSigntalkMaker.execute(lnkInputId); +// } + + + /** + * 인증톡 전송 재요청 + * + * @param lnkInputId + * @return + */ + public EnsResponseVO reSend(Long lnkInputId) { + return iupSigntalkSender.execute(lnkInputId); + } + + + /** + * 인증톡 전송(성공/실패) 결과 가져오기 + */ + @Transactional + public EnsResponseVO fetch(Long lnkInputId) { + TbInputXit tbInputXit = null; + try { + tbInputXit = tbInputXitRepository.findById(lnkInputId) + .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("[ lnkInputId %s ]와 일치하는 자료가 없습니다.", lnkInputId))); + if (!IupSendTypeCd.KP.equals(tbInputXit.getSendType())) + new EnsException(EnsErrCd.ERR404, String.format("[ lnkInputId %s ]는 인증톡 자료가 아닙니다.", lnkInputId)); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + + return this.fetch(Arrays.asList(tbInputXit)); + } + + /** + * 인증톡 전송(성공/실패) 결과 모두 가져오기 + */ + public EnsResponseVO fetchAll() { + List tbInputXits = tbInputXitRepository.findAllByPrcsCdInAndSendType(Arrays.asList(IupPrcsCd.TGRC, IupPrcsCd.CICV, IupPrcsCd.CICC, IupPrcsCd.COMP, IupPrcsCd.INCM), IupSendTypeCd.KP); + + return this.fetch(tbInputXits); + } + + private EnsResponseVO fetch(List tbInputXits) { + iupSigntalkFetcher.statReady(tbInputXits.stream().map(row -> row.getLnkInputId()).collect(Collectors.toList())); + + return EnsResponseVO.okBuilder() + .resultInfo( + tbInputXits.stream() + .map(row -> iupSigntalkFetcher.execute(row.getLnkInputId())) + .collect(Collectors.toList() + ) + ) + .build(); + } + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/IupSigntalkAcceptor.java b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/IupSigntalkAcceptor.java new file mode 100644 index 0000000..84084bd --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/IupSigntalkAcceptor.java @@ -0,0 +1,260 @@ +package cokr.xit.ens.biz.iup.signtalk.service.support; + +import cokr.xit.ens.biz.iup.code.IupPrcsCd; +import cokr.xit.ens.biz.iup.code.IupSendTypeCd; +import cokr.xit.ens.biz.iup.domain.TbInputDataXit; +import cokr.xit.ens.biz.iup.domain.TbInputXit; +import cokr.xit.ens.biz.iup.domain.repository.TbInputDataXitRepository; +import cokr.xit.ens.biz.iup.domain.repository.TbInputXitRepository; +import cokr.xit.ens.biz.iup.signtalk.service.support.accept.AcptDocKkoMd; +import cokr.xit.ens.biz.iup.signtalk.service.support.accept.AcptDocNvSt; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.common.code.VenderCd; +import cokr.xit.ens.core.model.EnsBillAcptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnNotiAcceptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config.AcptData; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config.Document; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config.Receiver; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config.XitProperty; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.IntgrnNotiService; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.utility.RandomString; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class IupSigntalkAcceptor implements EnsPhaseProcSupport { + + private final TbInputXitRepository tbInputXitRepository; + private final TbInputDataXitRepository tbInputDataXitRepository; + + private final IntgrnNotiService intgrnNotiService; + + + @Value("${xit.mblpage.postse.intgrn.url}") + private String MBLPAGE_URL; + @Value("${xit.mblpage.postse.intgrn.path}") + private String MBLPAGE_PATH; + + + /** + * Accept 준비 + * + * @param lnkInputIds + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List lnkInputIds) { + + + try { + AtomicInteger index = new AtomicInteger(); + String prefixLinkedUuid = String.format("B-ST%s%s", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")), RandomString.make(5)); + lnkInputIds.stream() + .map(lnkInputId -> tbInputXitRepository.findById(lnkInputId).get()) + .map(tbinput -> tbInputDataXitRepository.findAllByTbInputXit(tbinput)) + .forEach(list -> { + list.stream() + .forEach(row -> { + log.info(row.toString()); + +// row.setLinkedUuid(String.format("%s%05d", prefixLinkedUuid, index.getAndIncrement() + 1)); + row.setLinkedUuid(row.getDataId()); + }); + tbInputDataXitRepository.saveAll(list); + + } + + ); + } catch (Exception e) { + return EnsResponseVO.errBuilder() + .errCode(EnsErrCd.ACPT500) + .errMsg(String.format("연계식별UUID 생성에 실패 했습니다. %s", e.getMessage())) + .build(); + } + + + EnsResponseVO respVO = null; + try { + /** + * 필수값 확인 + */ + if (CmmnUtil.isEmpty(lnkInputIds)) + throw new EnsException(EnsErrCd.ACPT410, "연계입수아이디(은)는 필수조건 입니다."); + + /** + * 저장 + * -. 발송마스터의 상태를 "대상이관등록(TGRI)" 으로 변경 한다. + */ + + List resultInfo = tbInputXitRepository.findAllByLnkInputIdIn(lnkInputIds).stream() + .map(row -> { + row.setUpdId("ENS_SYS"); + row.setPrcsCd(IupPrcsCd.TGRI); + return row.getLnkInputId(); + }) + .collect(Collectors.toList()); + + + respVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } catch (EnsException e) { + + respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(); + } catch (Exception e) { + + respVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.ACPT999).errMsg(e.getMessage()).build(); + } + + return respVO; + } + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(Long arg) { + log.info("no process"); + return null; + } + + + /** + * 인증톡 전자고지 접수 + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(Long lnkInputId) { + Map resultInfo = new HashMap<>(); + resultInfo.put("lnkInputId", lnkInputId); + + EnsResponseVO responseVO = null; + TbInputXit tbInputXit = null; + try { + tbInputXit = tbInputXitRepository.findById(lnkInputId) + .orElseThrow(() -> new EnsException(EnsErrCd.ACPT404, String.format("일치하는 TB_INPUT_XIT 데이터가 없습니다. [ lnkInputId %s ]", lnkInputId))); + + IntgrnNotiAcceptReqDTO reqDTO = this.convertTbInputDataToAcceptReqDTO(tbInputDataXitRepository.findAllFetchByLnkInputId(tbInputXit.getLnkInputId())); + + EnsResponseVO reqResp = intgrnNotiService.accept(reqDTO); + + + if (EnsErrCd.OK.equals(reqResp.getErrCode())) { + resultInfo.put("intSendMastId", (Long) ((Map) reqResp.getResultInfo()).get("intSendMastId")); + responseVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } else { + responseVO = EnsResponseVO.errRsltBuilder() + .errCode(reqResp.getErrCode()) + .errMsg(reqResp.getErrMsg()) + .resultInfo(reqResp.getResultInfo()) + .build(); + } + } catch (EnsException e) { + responseVO = EnsResponseVO.errRsltBuilder() + .errCode(e.getErrCd()) + .errMsg(String.format("인증톡 \"접수\" 처리 실패. [%s] %s", e.getErrCd().getCode(), e.getMessage())) + .resultInfo(resultInfo) + .build(); + + } catch (Exception e) { + responseVO = EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ACPT500) + .errMsg(String.format("인증톡 \"접수\" 처리 실패. %s", e.getMessage())) + .resultInfo(resultInfo) + .build(); + + } finally { + if (EnsErrCd.OK.equals(responseVO.getErrCode())) { + tbInputXit.setUpdId("ENS_SYS"); + tbInputXit.setPrcsCd(IupPrcsCd.TGRC); + tbInputXit.setErrMsg(null); + } else { + tbInputXit.setUpdId("ENS_SYS"); + tbInputXit.setPrcsCd(IupPrcsCd.TGRF); + tbInputXit.setErrMsg(responseVO.getErrMsg()); + } + } + + return responseVO; + } + + + private IntgrnNotiAcceptReqDTO convertTbInputDataToAcceptReqDTO(List list) { + + return IntgrnNotiAcceptReqDTO.builder() + .vender(VenderCd.none.getCode()) + .org_cd(list.get(0).getTbInputXit().getOrgCd()) + .tmplt_cd(list.get(0).getTbInputXit().getFsJob().getJobCd()) + .post_bundle_title( + String.format("%s(%s건)-%s" + , IupSendTypeCd.KP.getCodeNm() + , list.get(0).getTbInputXit().getTotCnt() + , LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ) + ) + .send_dt(list.get(0).getTbInputXit().getRunDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .close_dt(list.get(0).getTbInputXit().getExpiresDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .documents( + list.stream() + .map(row -> createDocument(row)) + .collect(Collectors.toList()) + ) + .build(); + } + + private Document createDocument(TbInputDataXit data) throws EnsException { + + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + + return Document.builder() + .linked_uuid(data.getLinkedUuid()) + .receiver(Receiver.builder() + .ci(null) + .jid(data.getSid()) + .mblphon_no(data.getMoblphonNo()) + .build()) + .acpt_data(AcptData.builder() + .kko_md(new AcptDocKkoMd(data, MBLPAGE_URL + MBLPAGE_PATH).createDocument()) + .kko_at(null) + +// .nv_st(new AcptDocNvSt(data, NV_ST_ORG_ID, MBLPAGE_URL + MBLPAGE_PATH).createDocument()) + .nv_st(new AcptDocNvSt(data, null, MBLPAGE_URL + MBLPAGE_PATH).createDocument()) + .build()) + .xit_property(XitProperty.builder() + .bill_acpt_data(this.createBillAcptData(data)) + .tmplt_msg_data(CmmnUtil.isEmpty(data.getMsgData()) ? null : gson.fromJson(data.getMsgData().replace("~~@@!!", "#{").replace("!!@@~~", "}"), Map.class)) + .mbl_page_data(CmmnUtil.isEmpty(data.getMsgDtlData()) ? null : gson.fromJson(data.getMsgDtlData(), Map.class)) + .build()) + .build(); + } + + + private EnsBillAcptReqDTO createBillAcptData(TbInputDataXit data) { + return EnsBillAcptReqDTO.builder() + .billUid(null) + .billerUserKey(data.getLinkedUuid()) + .billSe(BillSeCd.privt) + .build(); + } + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/IupSigntalkFetcher.java b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/IupSigntalkFetcher.java new file mode 100644 index 0000000..ae26b7b --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/IupSigntalkFetcher.java @@ -0,0 +1,276 @@ +package cokr.xit.ens.biz.iup.signtalk.service.support; + +import cokr.xit.ens.biz.iup.code.IupPrcsCd; +import cokr.xit.ens.biz.iup.code.IupSendSttusCd; +import cokr.xit.ens.biz.iup.code.IupSendTrySttusCd; +import cokr.xit.ens.biz.iup.code.IupSendTypeCd; +import cokr.xit.ens.biz.iup.domain.TbInputXit; +import cokr.xit.ens.biz.iup.domain.TbSendResult; +import cokr.xit.ens.biz.iup.domain.repository.TbInputDataXitRepository; +import cokr.xit.ens.biz.iup.domain.repository.TbInputXitRepository; +import cokr.xit.ens.biz.iup.domain.repository.TbSendResultRepository; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.utils.DateUtil; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.code.TryStatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnDetailStatVO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnNotiRsltRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.IntgrnNotiService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class IupSigntalkFetcher implements EnsPhaseProcSupport { + + private final TbInputXitRepository tbInputXitRepository; + private final TbInputDataXitRepository tbInputDataXitRepository; + + private final TbSendResultRepository tbSendResultRepository; + + private final IntgrnNotiService intgrnNotiService; + + + /** + * Fetch 준비 + * + * @param lnkInputIds + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List lnkInputIds) { + + EnsResponseVO respVO = null; + try { + /** + * 필수값 확인 + */ + if (CmmnUtil.isEmpty(lnkInputIds)) + throw new EnsException(EnsErrCd.RSLT410, "연계입수아이디(은)는 필수조건 입니다."); + + /** + * 저장 + * -. 발송마스터의 상태를 "입수중(INCM)" 으로 변경 한다. + */ + + List resultInfo = tbInputXitRepository.findAllByLnkInputIdIn(lnkInputIds).stream() + .map(row -> { + row.setUpdId("ENS_SYS"); + row.setPrcsCd(IupPrcsCd.INCM); + return row.getLnkInputId(); + }) + .collect(Collectors.toList()); + ; + + respVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } catch (EnsException e) { + + respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(); + } catch (Exception e) { + + respVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.RSLT999).errMsg(e.getMessage()).build(); + } + + return respVO; + } + + + @Override + public EnsResponseVO statBegin(Long arg) { + log.info("no process"); + return null; + } + + + /** + * 인증톡 발송(성공/실패) 자료에 대한 결과 가져오기 + * + * @param lnkInputId + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(Long lnkInputId) { + EnsResponseVO responseVO = null; + Map resultInfo = new HashMap<>(); + resultInfo.put("lnkInputId", lnkInputId); + IntgrnNotiRsltRespDTO respDTO = null; + try { + Long intSendMastId = tbInputDataXitRepository.findLastSendMastIdByLnkInputIdAndSendType(lnkInputId, IupSendTypeCd.KP) + .orElseThrow(() -> new EnsException(EnsErrCd.RSLT404, "일치하는 ENS 접수자료가 없습니다.")); + resultInfo.put("intSendMastId", intSendMastId); + + + EnsResponseVO apiRespVO = intgrnNotiService.sendResultProvide(intSendMastId); + respDTO = (IntgrnNotiRsltRespDTO) apiRespVO.getResultInfo(); + + + IntgrnNotiRsltRespDTO finalRespDTO = respDTO; + List tbSendResults = respDTO.getDocuments().stream() + .map(row -> { + return TbSendResult.builder() + .lnkInputId(lnkInputId) + .dataId(row.getLinkedUuid()) +// .dataId(tbInputDataXitRepository.findByLinkedUuid(row.getLinkedUuid()) +// .orElse(new TbInputDataXit()) +// .getDataId()) +// .prcsOdr(StatCd.close.equals(finalRespDTO.getStatCd()) ? "2" : "1") + .prcsOdr(finalRespDTO.getCloseAt() ? "2" : "1") +// .sendSttusCd(iupSendSttusCd) + .sendSttusCd(this.sendSttusCd(row, finalRespDTO)) + .sendTrySttusCd(TryStatCd.cmplt.equals(finalRespDTO.getTryStatCd()) ? IupSendTrySttusCd.CMPLT : IupSendTrySttusCd.TRYING) + .sendType(IupSendTypeCd.KP) + .runDt(DateUtil.toLocalDateTime(finalRespDTO.getSendDt())) + .bizSendDt(DateUtil.toLocalDateTime(row.getDocSentDt())) + .bizRecvDt(DateUtil.toLocalDateTime(row.getDocReceivedDt())) + .bizReadDt(DateUtil.toLocalDateTime(row.getDocReadFrstDt())) + .bizErrMsg(CmmnUtil.isEmpty(row.getErrorMessage()) ? null : String.format("%s %s", row.getErrorCode(), row.getErrorMessage())) + .regId("ENS_SYS") + .regDt(LocalDateTime.now()) + .expiresDt(DateUtil.toLocalDateTime(finalRespDTO.getCloseDt())) + .prcsYn("N") + .build(); + }) + .collect(Collectors.toList()); +// if (tbSendResultRepository.findExistsByLnkInputIdAndPrcsOdr(lnkInputId, StatCd.close.equals(finalRespDTO.getStatCd()) ? "2" : "1")) + if (tbSendResultRepository.findExistsByLnkInputIdAndPrcsOdr(lnkInputId, finalRespDTO.getCloseAt() ? "2" : "1")) + tbSendResultRepository.modifyByTbSendResults(tbSendResults); + else + tbSendResultRepository.saveAll(tbSendResults); + + responseVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } catch (EnsException e) { + responseVO = EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } catch (Exception e) { + responseVO = EnsResponseVO.errBuilder() + .errCode(EnsErrCd.RSLT999) + .errMsg(String.format("[lnkInputId %s]에 대한 전송결과 FETCH 처리 실패. %s", lnkInputId, e.getMessage())) + .build(); + } finally { + TbInputXit tbInputXit = tbInputXitRepository.findById(lnkInputId).orElseThrow(() -> new EnsException(EnsErrCd.RSLT404, "일치하는 tbInputXit 자료가 없습니다.")); + if (EnsErrCd.OK.equals(responseVO.getErrCode())) { + tbInputXit.setUpdId("ENS_SYS"); +// tbInputXit.setPrcsCd(IupPrcsCd.IPCP); + tbInputXit.setPrcsCd(this.prcsCd(respDTO, tbInputXit.getPrcsCd())); + tbInputXit.setErrMsg(null); + } else { + tbInputXit.setUpdId("ENS_SYS"); + tbInputXit.setPrcsCd(IupPrcsCd.FAIL); + tbInputXit.setErrMsg(responseVO.getErrMsg()); + } + } + + return responseVO; + } + + + private IupPrcsCd prcsCd(IntgrnNotiRsltRespDTO respDTO, IupPrcsCd prcsCd) { + switch (respDTO.getStatCd()) { + case makefail: + return IupPrcsCd.FAIL; + case sendfail: + if (TryStatCd.cmplt.equals(respDTO.getTryStatCd())) + return IupPrcsCd.FAIL; + case makerdy: + return IupPrcsCd.CICV; + case making: + return IupPrcsCd.CICC; + case makeok: + return IupPrcsCd.COMP; + case sendok: + case sendcmplt: + case open: + return IupPrcsCd.INCM; + case close: + return IupPrcsCd.IPCP; + default: + return prcsCd; + } + } + + + private IupSendSttusCd sendSttusCd(IntgrnDetailStatVO row, IntgrnNotiRsltRespDTO respDTO) { + + + IupSendSttusCd iupSendSttusCd = null; + try { + switch (row.getCurStatCd().getIntgrnDtlStatCd()) { + case UNIDENTIFIED_USER: + if (PostSeCd.nvSigntalk.equals(row.getCurPostSe())) + iupSendSttusCd = IupSendSttusCd.NV_NOMB; + else + iupSendSttusCd = IupSendSttusCd.NOMB; + break; + case FORBIDDEN: + if (PostSeCd.nvSigntalk.equals(row.getCurPostSe())) + iupSendSttusCd = IupSendSttusCd.NV_DENY; + else + iupSendSttusCd = IupSendSttusCd.DENY; + break; + case SENT: + if (PostSeCd.nvSigntalk.equals(row.getCurPostSe())) + iupSendSttusCd = IupSendSttusCd.NV_SEND; + else + iupSendSttusCd = IupSendSttusCd.SEND; + break; + case RECEIVED: + case EXPIRED: + if (PostSeCd.nvSigntalk.equals(row.getCurPostSe())) + iupSendSttusCd = IupSendSttusCd.NV_RECV; + else + iupSendSttusCd = IupSendSttusCd.RECV; + break; + case READ: + if (PostSeCd.nvSigntalk.equals(row.getCurPostSe())) + iupSendSttusCd = IupSendSttusCd.NV_SIGN; + else + iupSendSttusCd = IupSendSttusCd.SIGN; + break; + case REG: + case MAKING: + case ACPT_OK: + case ACPT_CMPLT: + if (StatCd.makefail.equals(respDTO.getStatCd()) + || StatCd.sendfail.equals(respDTO.getStatCd())) + iupSendSttusCd = IupSendSttusCd.FAIL; + else + iupSendSttusCd = IupSendSttusCd.READY; + break; + case ACPT_FAIL: + case INVALID_VALUE: + case INTERNAL_ERROR: + case INVALID_REQUEST: + case FORBIDDEN_USER: + case FAIL: + iupSendSttusCd = IupSendSttusCd.FAIL; + break; + default: + break; + } + } catch (Exception e) { + log.info("IupSendSttusCd와 일치하는 값 없음. [ dataId {} IntgrnDtlStatCd {} ]", row.getLinkedUuid(), row.getCurStatCd().getIntgrnDtlStatCd()); + } + return iupSendSttusCd; + + + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/IupSigntalkSender.java b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/IupSigntalkSender.java new file mode 100644 index 0000000..da409a9 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/IupSigntalkSender.java @@ -0,0 +1,66 @@ +package cokr.xit.ens.biz.iup.signtalk.service.support; + +import cokr.xit.ens.biz.iup.code.IupSendTypeCd; +import cokr.xit.ens.biz.iup.domain.repository.TbInputDataXitRepository; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.IntgrnNotiService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Slf4j +@Component +@RequiredArgsConstructor +public class IupSigntalkSender implements EnsPhaseProcSupport { + + private final TbInputDataXitRepository tbInputDataXitRepository; + + private final IntgrnNotiService intgrnNotiService; + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List lnkInputIds) { + log.info("no process"); + return null; + } + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(Long arg) { + log.info("no process"); + return null; + } + + + + /** + * 인증톡 전자고지 전송요청 + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(Long lnkInputId){ + EnsResponseVO responseVO = null; + try { + Long sendMastId = tbInputDataXitRepository.findLastSendMastIdByLnkInputIdAndSendType(lnkInputId, IupSendTypeCd.KP) + .orElseThrow(() -> new EnsException(EnsErrCd.SEND404, "일치하는 ENS 접수자료가 없습니다.")); + + responseVO = intgrnNotiService.sendBulk(sendMastId); + } catch (EnsException e){ + responseVO = EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + return responseVO; + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/accept/Accept.java b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/accept/Accept.java new file mode 100644 index 0000000..e5328b2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/accept/Accept.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.biz.iup.signtalk.service.support.accept; + +public interface Accept { + T createDocument(); +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/accept/AcptDocKkoAt.java b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/accept/AcptDocKkoAt.java new file mode 100644 index 0000000..bd6255a --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/accept/AcptDocKkoAt.java @@ -0,0 +1,17 @@ +package cokr.xit.ens.biz.iup.signtalk.service.support.accept; + +import cokr.xit.ens.biz.iup.domain.TbInputDataXit; +import cokr.xit.ens.modules.kkoalimtalk.model.config.DocumentConfKkoAt; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class AcptDocKkoAt implements Accept { + + private final TbInputDataXit tbInputDataXit; + + @Override + public DocumentConfKkoAt createDocument() { + return DocumentConfKkoAt.builder() + .build(); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/accept/AcptDocKkoMd.java b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/accept/AcptDocKkoMd.java new file mode 100644 index 0000000..398e9e1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/accept/AcptDocKkoMd.java @@ -0,0 +1,44 @@ +package cokr.xit.ens.biz.iup.signtalk.service.support.accept; + +import cokr.xit.ens.biz.iup.domain.TbInputDataXit; +import cokr.xit.ens.core.utils.DateUtil; +import cokr.xit.ens.modules.kkomydoc.model.config.DocumentConfKkoMd; +import cokr.xit.ens.modules.kkomydoc.model.config.Property; +import lombok.RequiredArgsConstructor; + +import java.time.format.DateTimeFormatter; +import java.util.Arrays; + +@RequiredArgsConstructor +public class AcptDocKkoMd implements Accept { + + private final TbInputDataXit tbInputDataXit; + private final String redirectUrl; + + @Override + public DocumentConfKkoMd createDocument() { + return DocumentConfKkoMd.builder() + .hash(null) + .common_categories(Arrays.asList("NOTICE")) + .read_expired_at(DateUtil.dateToAbsTimeSec(tbInputDataXit.getTbInputXit().getPayExpiresDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")))) +// .read_expired_sec() + .property(this.createProperty(tbInputDataXit)) + .bridge(null) + .build(); + } + + + private Property createProperty(TbInputDataXit data) { + return Property.builder() +// .link(data.getPayUrl()) + .link(redirectUrl) + .payload(null) + .message(null) + .cs_name("문의처") + .cs_number(data.getCallCenterNo()) +// .external_document_uuid(data.getDataId()) +// .external_document_uuid(data.getLinkedUuid()) + .build(); + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/accept/AcptDocNvSt.java b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/accept/AcptDocNvSt.java new file mode 100644 index 0000000..cb92e2b --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/accept/AcptDocNvSt.java @@ -0,0 +1,38 @@ +package cokr.xit.ens.biz.iup.signtalk.service.support.accept; + +import cokr.xit.ens.biz.iup.domain.TbInputDataXit; +import cokr.xit.ens.core.utils.DateUtil; +import cokr.xit.ens.modules.nvsigntalk.model.config.DocumentConfNvSt; +import lombok.RequiredArgsConstructor; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; + +@RequiredArgsConstructor +public class AcptDocNvSt implements Accept { + + private final TbInputDataXit tbInputDataXit; + private final String orgId; + private final String redirectUrl; + + @Override + public DocumentConfNvSt createDocument() { +// int days = DateUtil.daysByFromBetweenTo(LocalDateTime.now(), tbInputDataXit.getTbInputXit().getPayExpiresDt()); + return DocumentConfNvSt.builder() +// .valid_duration(DateUtil.daysToRelTime(days) / 1000) + .valid_duration_at(DateUtil.dateToAbsTimeSec(tbInputDataXit.getTbInputXit().getPayExpiresDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")))) +// .redirect_url(tbInputDataXit.getPayUrl()) + .redirect_url(redirectUrl) + .publish_document_yn("y") + .document_hash(null) + .call_center_no(tbInputDataXit.getCallCenterNo()) + .org_id(orgId) + .auth_require_yn("y") + .notification(null) + .calculation_key(null) + .category_key(null) + .document_key(null) + .build(); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/code/SndngProcessSttusCd.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/code/SndngProcessSttusCd.java new file mode 100644 index 0000000..dcf8688 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/code/SndngProcessSttusCd.java @@ -0,0 +1,40 @@ +package cokr.xit.ens.biz.traffic.cheonan.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + + +/** + * 주정차웹 전자고지 발송처리상태 코드 + */ +public enum SndngProcessSttusCd implements CodeMapperType { + + accept("접수") + , acptok("접수성공") + , acptfail("접수실패") + + , ensmake("제작") + , ensstart("전송시작") + , ensok("전송성공") + , ensfail("전송실패") + , ensopen("열람중") + , ensclose("조회기간마감") + ; + + private final String code; + private final String codeNm; + SndngProcessSttusCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/code/SndngResultSttusCd.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/code/SndngResultSttusCd.java new file mode 100644 index 0000000..0cd07a9 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/code/SndngResultSttusCd.java @@ -0,0 +1,66 @@ +package cokr.xit.ens.biz.traffic.cheonan.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + * 주정차웹 전자고지 발송결과상태 코드 + */ +public enum SndngResultSttusCd implements CodeMapperType { + + UNKNOWN("알수없음") + + , REG("등록") + , MAKING("제작") + + , ACPT_OK("접수요청성공") + , ACPT_FAIL("접수실패") + , ACPT_CMPLT("접수완료") + + + , UNIDENTIFIED_USER("비회원") + , FORBIDDEN("수신거부") + , INVALID_VALUE("파라미터 오류") + , INTERNAL_ERROR("API 서버 내부 오류") + , INVALID_REQUEST("유효하지 않은 요청") + , FORBIDDEN_USER("허용되지 않은 사용자") + + , FAIL("전송실패") + , SENT("송신") + , RECEIVED("수신") + , READ("열람") + , EXPIRED("만료") + ; + + private final String code; + private final String codeNm; + + SndngResultSttusCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } + + + public static SndngResultSttusCd valueOfEnum(String statCd) { + if (statCd == null) + return SndngResultSttusCd.UNKNOWN; + + SndngResultSttusCd sndngResultSttusCd = null; + try { + sndngResultSttusCd = SndngResultSttusCd.valueOf(statCd); + } catch (IllegalArgumentException e) { + sndngResultSttusCd = SndngResultSttusCd.UNKNOWN; + } + return sndngResultSttusCd; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/code/SndngSeCd.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/code/SndngSeCd.java new file mode 100644 index 0000000..6af68d3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/code/SndngSeCd.java @@ -0,0 +1,49 @@ +package cokr.xit.ens.biz.traffic.cheonan.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + * 주정차웹 전자고지 발송구분 코드 + */ +public enum SndngSeCd implements CodeMapperType { + + UNKNOWN("알수없음") + ,intgrnNoti("통합 전자고지") + ,kkoMydoc("카카오페이 내문서함(인증톡)") + ,kkoAlimtalk("카카오페이 알림톡") + ,nvSigntalk("네이버 고지서(인증톡)") + ,ktSigntalk("KT 인증톡") + ,ktGibis("KT 인증톡(지비스)"); + ; + + private final String code; + private final String codeNm; + SndngSeCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } + + public static SndngSeCd valueOfEnum(String statCd) { + if (statCd == null) + return SndngSeCd.UNKNOWN; + + SndngSeCd SndngSeCd = null; + try { + SndngSeCd = SndngSeCd.valueOf(statCd); + } catch (IllegalArgumentException e) { + SndngSeCd = SndngSeCd.UNKNOWN; + } + return SndngSeCd; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/init/TrafficCaJpaRunner.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/init/TrafficCaJpaRunner.java new file mode 100644 index 0000000..d02c00c --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/init/TrafficCaJpaRunner.java @@ -0,0 +1,130 @@ +package cokr.xit.ens.biz.traffic.cheonan.init; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository.TcaNhtTmplatManageRepository; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository.TcaRlaybsnmManageRepository; +import cokr.xit.ens.core.init.InitJpaRunner; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.OrgMngDTO; +import cokr.xit.ens.modules.ktsigntalk.common.code.MTypeCd; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +/** + * 주정차웹-천안 + */ +//TODO: 데이터초기화 목적으로 사용. ex) 최초 배포 시 +//@Component +@Transactional +@Profile({"prod-traffic-cheonan", "local-test"}) +public class TrafficCaJpaRunner extends InitJpaRunner { + ObjectMapper mapper = new ObjectMapper(); + +// @Value("${contract.custom.dng.nice.dici.rest.client-id}") +// private String DNG_NICE_CD_CLIENT_ID; +// @Value("${contract.custom.dng.nice.dici.rest.client-secret}") +// private String DNG_NICE_CD_CLIENT_SECRET; +// @Value("${contract.custom.dng.kakao.pay.mydoc.access-token}") +// private String DNG_KKO_MD_ACCESS_TOKEN; +// @Value("${contract.custom.dng.kakao.pay.mydoc.contract-uuid}") +// private String DNG_KKO_MD_CONTRACT_UUID; +// +// @Value("${contract.custom.sbg.nice.dici.rest.client-id}") +// private String SBG_NICE_CD_CLIENT_ID; +// @Value("${contract.custom.sbg.nice.dici.rest.client-secret}") +// private String SBG_NICE_CD_CLIENT_SECRET; +// @Value("${contract.custom.sbg.kakao.pay.mydoc.access-token}") +// private String SBG_KKO_MD_ACCESS_TOKEN; +// @Value("${contract.custom.sbg.kakao.pay.mydoc.contract-uuid}") +// private String SBG_KKO_MD_CONTRACT_UUID; + + @Autowired + private TcaRlaybsnmManageRepository tcaRlaybsnmManageRepository; + @Autowired + private TcaNhtTmplatManageRepository tcaNhtTmplatManageRepository; + + @Override + protected List createOrgMngDTO() { +// List list = new ArrayList<>(); +// list.add(createOrgMngDTO("TCA01", "", "천안-동남구", "N", null, null, DNG_NICE_CD_CLIENT_ID, DNG_NICE_CD_CLIENT_SECRET, DNG_KKO_MD_ACCESS_TOKEN, DNG_KKO_MD_CONTRACT_UUID)); +// list.add(createOrgMngDTO("TCA02", "", "천안-서북구", "N", null, null, SBG_NICE_CD_CLIENT_ID, SBG_NICE_CD_CLIENT_SECRET, SBG_KKO_MD_ACCESS_TOKEN, SBG_KKO_MD_CONTRACT_UUID)); +// return list; + return tcaRlaybsnmManageRepository.findAll().stream() + .map(entity -> OrgMngDTO.builder() + .orgCd(entity.getSignguCode()) + .orgNm(entity.getSignguNm()) + + .kkoMdAccessToken(entity.getKakaoAccessToken()) + .kkoMdContractUuid(entity.getKakaoContractUuid()) + + .kkoBpCsignYn("N") +// .kkoBpBillerCode(KKO_BP_BILLER_CODE) +// .kkoBpAuthorization(KKO_BP_AUTHORIZATION) +// .kkoBpCsignPrepayApi(kkoBpPrepayApi) +// .kkoBpCsignPayResultApi(kkoBpPayResultApi) + +// .kkoAtBsid(KKO_AT_BSID) +// .kkoAtPasswd(KKO_AT_PASSWD) +// .kkoAtSenderKey(KKO_AT_SENDER_KEY) + + .niceCdSiteCode(null) + .niceCdSitePw(entity.getNiceSiteCode()) + .niceCdClientId(entity.getNiceClientId()) + .niceCdClientSercet(entity.getNiceClientSecret()) + +// .nvStXNaverClientId(NV_ST_X_NAVER_CLIENT_ID) +// .nvStXNaverClientSecret(NV_ST_X_NAVER_CLIENT_SECRET) +// .nvStOrgId(nvOrgId) + +// .ktStAccessToken(null) +// .ktStServiceCd(null) +// .ktStServiceKey(null) + .ktStClientId(entity.getKtClientId()) + .ktStClientSecret(entity.getKtClientSecret()) + .build()) + .collect(Collectors.toList()); + } + + @Override + protected List> createTmpltMngDTO() { +// List> list = new ArrayList<>(); +// list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.ktGibis, null, "TCA01", "TCA0001", "주정차단속-천안-동남구", "[천안-동남구] 소유차량(#{CAR_NO})의 주정차과태료", "Y" +// , null +// , createTmpltMngKkoMydoc(null, null, null, null, null, "044-211-3377", "문의처", "Y", "Y", "Y") +// , null +// , null +// , createTmpltMngKtGibis(null, null, null, null, null, "MC001", MTypeCd.mms, 1, "044-211-3377", "044-211-3377", "Y", "Y", "Y") +// ) +// , Map.class)); +// list.add(mapper.convertValue(createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.ktGibis, null, "TCA02", "TCA0001", "주정차단속-천안-서북구", "[천안-서북구] 소유차량(#{CAR_NO})의 주정차과태료", "Y" +// , null +// , createTmpltMngKkoMydoc(null, null, null, null, null, "044-211-3377", "문의처", "Y", "Y", "Y") +// , null +// , null +// , createTmpltMngKtGibis(null, null, null, null, null, "MC001", MTypeCd.mms, 1, "044-211-3377", "044-211-3377", "Y", "Y", "Y") +// ) +// , Map.class)); +// return list; + + + return tcaNhtTmplatManageRepository.findAll().stream() + .map(entity -> createTmpltMngIntgrn(PostSeCd.kkoMydoc, PostSeCd.ktGibis, null, entity.getSignguCode(), entity.getNhtTmplatId(), entity.getNhtSj(), entity.getNhtCn(), "Y" + , null + , createTmpltMngKkoMydoc(null, null, null, null, null, entity.getCstmrCnterTlphonNo(), entity.getCstmrCnterNm() == null ? "문의처" : entity.getCstmrCnterNm(), "Y", "Y", "Y") + , null + , null + , createTmpltMngKtGibis(null, null, null, null, null, "?????", MTypeCd.mms, "2", 1, entity.getCstmrCnterTlphonNo(), entity.getCstmrCnterTlphonNo(), "Y", "Y", "Y") + )) + .map(tmpltMngIntgrnDTO -> (Map) mapper.convertValue(tmpltMngIntgrnDTO, Map.class)) + .collect(Collectors.toList()); + } + + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaElctrnNticSndng.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaElctrnNticSndng.java new file mode 100644 index 0000000..60120e8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaElctrnNticSndng.java @@ -0,0 +1,70 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain; + +import cokr.xit.ens.biz.traffic.cheonan.code.SndngProcessSttusCd; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldCreate; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldUpdate; +import lombok.*; + +import javax.persistence.*; + +/** + * 전자고지 발송 + */ +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "tb_elctrn_ntic_sndng") +public class TcaElctrnNticSndng { + + @Id + @Column(name = "elctrn_ntic_sndng_id", length = 20) + private String elctrnNticSndngId; + + @Column(name = "signgu_code", length = 5) + private String signguCode; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "nht_tmplat_id") + private TcaNhtTmplatManage tcaNhtTmplatManage; + + @Column(name = "sndng_ty_code", length = 5) + private String sndngTyCode; + + @Column(name = "sndng_co", length = 10) + private Integer sndngCo; + + @Column(name = "sndng_process_sttus", length = 2) + @Setter + @Enumerated(EnumType.STRING) + private SndngProcessSttusCd sndngProcessSttus; + + @Column(name = "sndng_dt", length = 14) + private String sndngDt; + + @Column(name = "clos_dt", length = 14) + private String closDt; + + @Embedded + private FieldCreate create; + + @Embedded + @Setter + private FieldUpdate update; + + @Column(name = "error_cn", length = 1000) + @Setter + private String errorCn; + + @Lob + @Setter + @Column(name = "error_dtls") + private String errorDtls; + + + @Column(name = "ffnlg_code", length = 2) + private String ffnlgCode; + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaElctrnNticSndngDetail.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaElctrnNticSndngDetail.java new file mode 100644 index 0000000..cceb70e --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaElctrnNticSndngDetail.java @@ -0,0 +1,82 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldCreate; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldUpdate; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.annotations.DynamicUpdate; + +import javax.persistence.*; + +/** + * 전자고지 발송상세 + */ +@Getter +@ToString +@Builder +@DynamicUpdate +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "tb_elctrn_ntic_sndng_detail", schema = "", catalog = "", indexes = { + @Index(name = "idx_tca_ens_detail_01", columnList = "main_code"), +// @Index(name = "idx_tca_ens_detail_02", columnList = "external_document_uuid"), +}) +public class TcaElctrnNticSndngDetail { + + + @Id + @Column(name = "elctrn_ntic_sndng_detail_id", length = 20) + private String elctrnNticSndngDetailId; + + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "elctrn_ntic_sndng_id") + private TcaElctrnNticSndng elctrnNticSndng; + + + @Column(name = "signgu_code", length = 5) + private String signguCode; + + + @Column(name = "main_code", length = 20) + private String mainCode; + + + @Column(name = "ihidnum", length = 100, updatable = false) + private String ihidnum; + + +// @Lob +// @Column(name = "cn_detail") +// private String cnDetail; + + + @Lob + @Column(name = "tmplt_msg_data") + private String tmpltMsgData; + + + @Lob + @Column(name = "mobile_page_cn") + private String mobilePageCn; + + @Embedded + private FieldCreate create; + + @Embedded + private FieldUpdate update; + + + @Column(name = "external_document_uuid", length = 40) + @Setter + private String externalDocumentUuid; + + + + @Column(name = "ffnlg_code", length = 2) + private String ffnlgCode; + + @Column(name = "use_instt_idntfc_id") + private Integer useInsttIdntfcId; +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaElctrnNticSndngResult.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaElctrnNticSndngResult.java new file mode 100644 index 0000000..96672f8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaElctrnNticSndngResult.java @@ -0,0 +1,65 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain; + +import cokr.xit.ens.biz.traffic.cheonan.code.SndngResultSttusCd; +import cokr.xit.ens.biz.traffic.cheonan.code.SndngSeCd; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldCreate; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.annotations.UpdateTimestamp; + +import javax.persistence.*; +import java.time.LocalDateTime; + +/** + * 전자고지 발송결과 + */ +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "tb_elctrn_ntic_sndng_result") +public class TcaElctrnNticSndngResult { + + + + @Id + @Column(name = "elctrn_ntic_sndng_detail_id", length = 20) + private String elctrnNticSndngDetailId; + + + @Column(name = "sndng_result_sttus", length = 20) + @Enumerated(EnumType.STRING) + private SndngResultSttusCd sndngResultSttus; + + + @Column(name = "requst_dt", length = 14) + private String requstDt; + + + @Column(name = "inqire_dt", length = 14) + private String inqireDt; + + + @Column(name = "readng_dt", length = 14) + private String readngDt; + + + @Column(name = "error_cn", length = 1000) + private String errorCn; + + @Embedded + private FieldCreate create; + + + @UpdateTimestamp + @Column(name = "last_updt_dt", nullable = true) + private LocalDateTime lastUpdtDt; + + + + @Column(name = "sndng_se", length = 10) + @Enumerated(EnumType.STRING) + private SndngSeCd sndngSe; +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaNhtTmplatManage.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaNhtTmplatManage.java new file mode 100644 index 0000000..2c4eef6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaNhtTmplatManage.java @@ -0,0 +1,69 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldCreate; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldUpdate; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.persistence.*; + +/** + * 전자고지 템플릿관리 + */ +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "tb_nht_tmplat_manage") +public class TcaNhtTmplatManage { + + + @Id + @Column(name = "nht_tmplat_id", length = 5) + private String nhtTmplatId; + + + @Column(name = "signgu_code", length = 5) + private String signguCode; + + + @Column(name = "sndng_ty_code", length = 1) + private String sndngTyCode; + + + @Column(name = "nht_nm", length = 1000) + private String nhtNm; + + + @Column(name = "nht_sj", length = 1000) + private String nhtSj; + + @Column(name = "nhtCn", length = 4000) + private String nhtCn; + + + @Column(name = "cstmr_cnter_nm", length = 100) + private String cstmrCnterNm; + + + @Column(name = "cstmr_cnter_tlphon_no", length = 14) + private String cstmrCnterTlphonNo; + + + @Column(name = "redirect_url", length = 255) + private String redirectUrl; + + + @Column(name = "use_at", length = 1) + private String useAt; + + @Embedded + private FieldCreate create; + + @Embedded + private FieldUpdate update; + + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaRlaybsnmManage.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaRlaybsnmManage.java new file mode 100644 index 0000000..1623975 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/TcaRlaybsnmManage.java @@ -0,0 +1,70 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldCreate; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldUpdate; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.persistence.*; + +/** + * 전자고지 기관관리 + */ +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "tb_rlaybsnm_manage") +public class TcaRlaybsnmManage { + + + @Id + @Column(name = "signgu_code", length = 5) + private String signguCode; + + + @Column(name = "ffnlg_code") + private String ffnlgCode; + + + @Column(name = "signgu_nm") + private String signguNm; + + + @Column(name = "kakao_access_token") + private String kakaoAccessToken; + + + @Column(name = "kakao_contract_uuid") + private String kakaoContractUuid; + + + @Column(name = "nice_site_code") + private String niceSiteCode; + + + @Column(name = "nice_client_id") + private String niceClientId; + + + @Column(name = "nice_client_secret") + private String niceClientSecret; + + + @Column(name = "kt_client_id") + private String ktClientId; + + + @Column(name = "kt_client_secret") + private String ktClientSecret; + + @Embedded + private FieldCreate create; + + @Embedded + private FieldUpdate update; + + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/embeded/FieldCreate.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/embeded/FieldCreate.java new file mode 100644 index 0000000..de2418b --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/embeded/FieldCreate.java @@ -0,0 +1,37 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded; + +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.PrePersist; +import java.time.LocalDateTime; + + +@Embeddable +@Getter +@RequiredArgsConstructor +public class FieldCreate { + +// @CreationTimestamp +// @Temporal(TemporalType.TIMESTAMP) + @Column(name = "regist_dt") + private LocalDateTime registDt; + @Column(name = "register", length = 50) + private String register; + + + @PrePersist + public void preUpdate() { + this.registDt = LocalDateTime.now(); + } + + + @Builder(builderMethodName = "builder") + public FieldCreate(String register, LocalDateTime registDt) { + this.register = register; + this.registDt = registDt; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/embeded/FieldUpdate.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/embeded/FieldUpdate.java new file mode 100644 index 0000000..1e035f9 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/embeded/FieldUpdate.java @@ -0,0 +1,34 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded; + +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.PreUpdate; +import java.time.LocalDateTime; + +@Embeddable +@Getter +@RequiredArgsConstructor +public class FieldUpdate { + +// @UpdateTimestamp +// @Temporal(TemporalType.TIMESTAMP) + @Column(name = "updt_dt") + private LocalDateTime updtDt; + @Column(name = "updusr", length = 50) + private String updusr; + + @PreUpdate + public void preUpdate() { + this.updtDt = LocalDateTime.now(); + } + + @Builder(builderMethodName = "builder") + public FieldUpdate(String updusr, LocalDateTime updtDt) { + this.updusr = updusr; + this.updtDt = updtDt; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngDetailRepository.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngDetailRepository.java new file mode 100644 index 0000000..0109063 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngDetailRepository.java @@ -0,0 +1,13 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndngDetail; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + + +public interface TcaElctrnNticSndngDetailRepository extends JpaRepository, TcaElctrnNticSndngDetailRepositoryCustom { + + Optional findByExternalDocumentUuid(String externalDocumentUuid); + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngDetailRepositoryCustom.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngDetailRepositoryCustom.java new file mode 100644 index 0000000..479561c --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngDetailRepositoryCustom.java @@ -0,0 +1,20 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndng; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndngDetail; + +import java.util.List; +import java.util.Optional; + +public interface TcaElctrnNticSndngDetailRepositoryCustom { + + + List findAllDecByElctrnNticSndng(TcaElctrnNticSndng elctrnNticSndng); + + + List findAllFetchByElctrnNticSndngId(String elctrnNticSndngId); + + Optional findLastSendMastIdByElctrnNticSndngId(String elctrnNticSndngId); + + String findIhidnumDecByElctrnNticSndngDetailId(String elctrnNticSndngDetailId); +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngDetailRepositoryImpl.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngDetailRepositoryImpl.java new file mode 100644 index 0000000..609e88a --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngDetailRepositoryImpl.java @@ -0,0 +1,86 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndng; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndngDetail; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.util.List; +import java.util.Optional; + +import static cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.QTcaElctrnNticSndng.tcaElctrnNticSndng; +import static cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.QTcaElctrnNticSndngDetail.tcaElctrnNticSndngDetail; +import static cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.QTcaNhtTmplatManage.tcaNhtTmplatManage; +import static cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.QIntgrnSendDetail.intgrnSendDetail; + +@RequiredArgsConstructor +public class TcaElctrnNticSndngDetailRepositoryImpl implements TcaElctrnNticSndngDetailRepositoryCustom { + + private final JPAQueryFactory query; + + @Override + public List findAllDecByElctrnNticSndng(TcaElctrnNticSndng elctrnNticSndng) { + + return query.select(Projections.fields(TcaElctrnNticSndngDetail.class + , tcaElctrnNticSndngDetail.elctrnNticSndngDetailId + , tcaElctrnNticSndngDetail.elctrnNticSndng + , tcaElctrnNticSndngDetail.signguCode + , tcaElctrnNticSndngDetail.mainCode + , Expressions.stringTemplate("ECL_DECRYPT({0})", tcaElctrnNticSndngDetail.ihidnum).as("ihidnum") + , tcaElctrnNticSndngDetail.tmpltMsgData + , tcaElctrnNticSndngDetail.mobilePageCn + , tcaElctrnNticSndngDetail.create + , tcaElctrnNticSndngDetail.update + , tcaElctrnNticSndngDetail.externalDocumentUuid + , tcaElctrnNticSndngDetail.ffnlgCode + , tcaElctrnNticSndngDetail.useInsttIdntfcId + )) + .from(tcaElctrnNticSndngDetail) + .where(tcaElctrnNticSndngDetail.elctrnNticSndng.eq(elctrnNticSndng)) + .fetch(); + } + + + @Override + public List findAllFetchByElctrnNticSndngId(String elctrnNticSndngId) { + return query.selectFrom(tcaElctrnNticSndngDetail) + .innerJoin(tcaElctrnNticSndngDetail.elctrnNticSndng, tcaElctrnNticSndng) + .fetchJoin() + .innerJoin(tcaElctrnNticSndng.tcaNhtTmplatManage, tcaNhtTmplatManage) + .fetchJoin() + .where(tcaElctrnNticSndngDetail.elctrnNticSndng.elctrnNticSndngId.eq(elctrnNticSndngId)) + .fetch(); + + } + + + @Override + public Optional findLastSendMastIdByElctrnNticSndngId(String elctrnNticSndngId) { + return Optional.ofNullable(query.select(intgrnSendDetail.intgrnSendMast.intSendMastId) + .from(intgrnSendDetail) +// .where(intgrnSendDetail.linkedUuid.in(findExternalDocumentUuidsByLnkInputId(elctrnNticSndngId))) + .innerJoin(tcaElctrnNticSndngDetail).on(intgrnSendDetail.linkedUuid.eq(tcaElctrnNticSndngDetail.externalDocumentUuid)) + .where(tcaElctrnNticSndngDetail.elctrnNticSndng.elctrnNticSndngId.eq(elctrnNticSndngId)) + .groupBy(intgrnSendDetail.intgrnSendMast.intSendMastId) + .orderBy(intgrnSendDetail.intgrnSendMast.intSendMastId.desc()) + .fetchFirst()); + } + + private List findExternalDocumentUuidsByLnkInputId(String elctrnNticSndngId) { + return query.select(tcaElctrnNticSndngDetail.externalDocumentUuid) + .from(tcaElctrnNticSndngDetail) + .where(tcaElctrnNticSndngDetail.elctrnNticSndng.elctrnNticSndngId.eq(elctrnNticSndngId)) + .fetch(); + } + + + @Override + public String findIhidnumDecByElctrnNticSndngDetailId(String tcaElctrnNticSndngDetailId) { + return query.select(Expressions.stringTemplate("ECL_DECRYPT({0})", tcaElctrnNticSndngDetail.ihidnum).as("ihidnum")) + .from(tcaElctrnNticSndngDetail) + .where(tcaElctrnNticSndngDetail.elctrnNticSndngDetailId.eq(tcaElctrnNticSndngDetailId)) + .fetchOne(); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngRepository.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngRepository.java new file mode 100644 index 0000000..947e2a7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngRepository.java @@ -0,0 +1,16 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository; + +import cokr.xit.ens.biz.traffic.cheonan.code.SndngProcessSttusCd; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndng; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface TcaElctrnNticSndngRepository extends JpaRepository { + + + List findAllBySndngProcessSttus(SndngProcessSttusCd sndngProcessSttus); + + List findAllBySndngProcessSttusIn(List sndngProcessSttuss); + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngResultRepository.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngResultRepository.java new file mode 100644 index 0000000..be3fd5c --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngResultRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndngResult; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TcaElctrnNticSndngResultRepository extends JpaRepository, TcaElctrnNticSndngResultRepositoryCustom { + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngResultRepositoryCustom.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngResultRepositoryCustom.java new file mode 100644 index 0000000..1820718 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngResultRepositoryCustom.java @@ -0,0 +1,11 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndngResult; + +import java.util.List; + +public interface TcaElctrnNticSndngResultRepositoryCustom { + + + void modifyByElctrnNticSndngResults(List tcaElctrnNticSndngResults); +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngResultRepositoryImpl.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngResultRepositoryImpl.java new file mode 100644 index 0000000..3d31d04 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaElctrnNticSndngResultRepositoryImpl.java @@ -0,0 +1,35 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndngResult; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +import static cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.QTcaElctrnNticSndngResult.tcaElctrnNticSndngResult; + +@RequiredArgsConstructor +public class TcaElctrnNticSndngResultRepositoryImpl implements TcaElctrnNticSndngResultRepositoryCustom { + + private final JPAQueryFactory query; + + @Override + public void modifyByElctrnNticSndngResults(List tcaElctrnNticSndngResults) { + tcaElctrnNticSndngResults.forEach(data -> + query.update(tcaElctrnNticSndngResult) + .set(tcaElctrnNticSndngResult.sndngSe, data.getSndngSe()) + .set(tcaElctrnNticSndngResult.sndngResultSttus, data.getSndngResultSttus()) + .set(tcaElctrnNticSndngResult.requstDt, data.getRequstDt()) + .set(tcaElctrnNticSndngResult.inqireDt, data.getInqireDt()) + .set(tcaElctrnNticSndngResult.readngDt, data.getReadngDt()) + .set(tcaElctrnNticSndngResult.errorCn, data.getErrorCn()) +// .set(tcaElctrnNticSndngResult.create, FieldCreate.builder().build()) + .set(tcaElctrnNticSndngResult.lastUpdtDt, LocalDateTime.now()) + .where(tcaElctrnNticSndngResult.elctrnNticSndngDetailId.eq(data.getElctrnNticSndngDetailId())) + .execute() + ); + } + + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaNhtTmplatManageRepository.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaNhtTmplatManageRepository.java new file mode 100644 index 0000000..505ab9b --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaNhtTmplatManageRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaNhtTmplatManage; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TcaNhtTmplatManageRepository extends JpaRepository { + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaRlaybsnmManageRepository.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaRlaybsnmManageRepository.java new file mode 100644 index 0000000..d2a6042 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/domain/repository/TcaRlaybsnmManageRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaRlaybsnmManage; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TcaRlaybsnmManageRepository extends JpaRepository { + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/model/TrafficCaSigntalkReqDTO.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/model/TrafficCaSigntalkReqDTO.java new file mode 100644 index 0000000..1384c97 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/model/TrafficCaSigntalkReqDTO.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +@Getter +@Schema(name = "TrafficCaSigntalkReqDTO") +public class TrafficCaSigntalkReqDTO { + + @Schema(required = true, title = "전자 고지 발송 Id", example = " ") + private String elctrnNticSndngId; +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/presentation/TrafficCaSigntalkController.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/presentation/TrafficCaSigntalkController.java new file mode 100644 index 0000000..9a4dfec --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/presentation/TrafficCaSigntalkController.java @@ -0,0 +1,53 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.presentation; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.model.TrafficCaSigntalkReqDTO; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.service.TrafficCaSigntalkService; +import cokr.xit.ens.core.aop.EnsResponseVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; + +@Tag(name = "TrafficCaSigntalkController") +@Slf4j +@Controller +@RequiredArgsConstructor +public class TrafficCaSigntalkController { + + private final TrafficCaSigntalkService trafficCaSigntalkService; + + @Operation(summary = "접수") + @PostMapping(value = "/traffic/ca/signtalk/accept", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity accept(@RequestBody TrafficCaSigntalkReqDTO reqDTO) { + EnsResponseVO responseVO = trafficCaSigntalkService.accept(reqDTO.getElctrnNticSndngId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "제작") + @PutMapping(value = "/traffic/ca/signtalk/re/make", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity reMake(@RequestBody TrafficCaSigntalkReqDTO reqDTO) { + EnsResponseVO responseVO = trafficCaSigntalkService.reMake(reqDTO.getElctrnNticSndngId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "전송") + @PutMapping(value = "/traffic/ca/signtalk/re/send", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity reSend(@RequestBody TrafficCaSigntalkReqDTO reqDTO) { + EnsResponseVO responseVO = trafficCaSigntalkService.reSend(reqDTO.getElctrnNticSndngId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "전송결과가져오기") + @PostMapping(value = "/traffic/ca/signtalk/fetch", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity fetch(@RequestBody TrafficCaSigntalkReqDTO reqDTO) { + EnsResponseVO responseVO = trafficCaSigntalkService.fetch(reqDTO.getElctrnNticSndngId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/sched/TrafficCaSigntalkScheduler.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/sched/TrafficCaSigntalkScheduler.java new file mode 100644 index 0000000..b5279fa --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/sched/TrafficCaSigntalkScheduler.java @@ -0,0 +1,46 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.sched; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.service.TrafficCaSigntalkService; +import cokr.xit.ens.core.aop.EnsResponseVO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@Profile("prod-traffic-cheonan") +@RequiredArgsConstructor +public class TrafficCaSigntalkScheduler { + + private final TrafficCaSigntalkService trafficCaSigntalkService; + + /** + * 인증톡 접수 + * -. 인증톡 전송을 위해 TRAFFIC에 등록된 기초데이터를 ENS에 이관 등록 한다. + */ + @Scheduled(cron = "0 */1 7-22 * * *") + public void accepted(){ + EnsResponseVO responseVO = trafficCaSigntalkService.acceptAll(); + log.info("======================================================="); + log.info("[TRAFFIC] 인증톡 접수처리 결과"); + log.info(responseVO.toString()); + log.info("======================================================="); + } + + + /** + * 인증톡 결과 가져오기 + * -. 전송이 완료된 인증톡 전송결과(성공/실패)를 ENS -> TRAFFIC 로 가져와 DB에 저장한다. + */ + @Scheduled(cron = "0 */15 7-22 * * *") + public void fetched(){ + EnsResponseVO responseVO = trafficCaSigntalkService.fetchAll(); + + log.info("======================================================="); + log.info("[TRAFFIC] 인증톡 요청문서정보 Fetch 결과"); + log.info(responseVO.toString()); + log.info("======================================================="); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/TrafficCaSigntalkService.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/TrafficCaSigntalkService.java new file mode 100644 index 0000000..a58e762 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/TrafficCaSigntalkService.java @@ -0,0 +1,169 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.service; + +import cokr.xit.ens.biz.traffic.cheonan.code.SndngProcessSttusCd; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndng; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository.TcaElctrnNticSndngRepository; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support.TrafficCaSigntalkAcceptor; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support.TrafficCaSigntalkFetcher; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support.TrafficCaSigntalkMaker; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support.TrafficCaSigntalkSender; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.event.IntgrnNotiSendReserveEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional +public class TrafficCaSigntalkService { + + private final TcaElctrnNticSndngRepository tcaElctrnNticSndngRepository; + + private final TrafficCaSigntalkAcceptor trafficCaSigntalkAcceptor; + private final TrafficCaSigntalkMaker trafficCaSigntalkMaker; + private final TrafficCaSigntalkSender trafficCaSigntalkSender; + private final TrafficCaSigntalkFetcher trafficCaSigntalkFetcher; + + private final ApplicationEventPublisher applicationEventPublisher; + + + /** + * 인증톡 접수(TRAFFIC -> ENS) + */ + public EnsResponseVO accept(String elctrnNticSndngId) { + + try { + + TcaElctrnNticSndng elctrnNticSndng = tcaElctrnNticSndngRepository.findById(elctrnNticSndngId) + .orElseThrow(() -> new EnsException(EnsErrCd.ACPT404, "일치하는 자료가 없습니다.")); + if (!SndngProcessSttusCd.accept.equals(elctrnNticSndng.getSndngProcessSttus())) + throw new EnsException(EnsErrCd.ACPT405, String.format("\"%s(%s)\" 상태가 아닙니다.", SndngProcessSttusCd.accept.getCodeNm(), SndngProcessSttusCd.accept)); + + return this.accept(Arrays.asList(elctrnNticSndng)).getResultInfo().get(0); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + } + + /** + * 인증톡 접수(TRAFFIC -> ENS) + */ + public EnsResponseVO> acceptAll() { + try { + + List tcaElctrnNticSndngs = tcaElctrnNticSndngRepository.findAllBySndngProcessSttus(SndngProcessSttusCd.accept); + if (CmmnUtil.isEmpty(tcaElctrnNticSndngs)) + throw new EnsException(EnsErrCd.ACPT404, String.format("\"%s(%s)\" 상태의 자료가 없습니다.", SndngProcessSttusCd.accept.getCodeNm(), SndngProcessSttusCd.accept)); + + return this.accept(tcaElctrnNticSndngs); + } catch (EnsException e) { + return EnsResponseVO.>errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + } + + private EnsResponseVO> accept(List tcaElctrnNticSndngs) { + EnsResponseVO responseVO = trafficCaSigntalkAcceptor.statReady(tcaElctrnNticSndngs.stream() + .map(row -> row.getElctrnNticSndngId()) + .collect(Collectors.toList())); + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) + return responseVO; + + List resultInfo = tcaElctrnNticSndngs.stream() + .map(row -> trafficCaSigntalkAcceptor.execute(row.getElctrnNticSndngId())) + .collect(Collectors.toList()); + + + List sendMastIds = resultInfo.stream() + .filter(ensResponseVO -> EnsErrCd.OK.equals(ensResponseVO.getErrCode())) + .map(ensResponseVO -> (Long) ((Map) ensResponseVO.getResultInfo()).get("intSendMastId")) + .collect(Collectors.toList()); + IntgrnNotiSendReserveEvent event = IntgrnNotiSendReserveEvent.builder() + .sendMastIds(sendMastIds) + .callback(() -> this.fetch(tcaElctrnNticSndngs)) + .build(); + applicationEventPublisher.publishEvent(event); + + return EnsResponseVO.>okBuilder().resultInfo(resultInfo).build(); + } + + + /** + * 인증톡 제작 재요청 + * + * @param elctrnNticSndngId + * @return + */ + public EnsResponseVO reMake(String elctrnNticSndngId) { + return trafficCaSigntalkMaker.execute(elctrnNticSndngId); + } + + + /** + * 인증톡 전송 재요청 + * + * @param elctrnNticSndngId + * @return + */ + public EnsResponseVO reSend(String elctrnNticSndngId) { + return trafficCaSigntalkSender.execute(elctrnNticSndngId); + } + + + /** + * 인증톡 전송(성공/실패) 결과 가져오기 + */ + public EnsResponseVO fetch(String elctrnNticSndngId) { + TcaElctrnNticSndng elctrnNticSndng = null; + try { + elctrnNticSndng = tcaElctrnNticSndngRepository.findById(elctrnNticSndngId) + .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("[ elctrnNticSndngId %s ]와 일치하는 자료가 없습니다.", elctrnNticSndngId))); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + + return this.fetch(Arrays.asList(elctrnNticSndng)); + } + + /** + * 인증톡 전송(성공/실패) 결과 모두 가져오기 + */ + public EnsResponseVO fetchAll() { + List tcaElctrnNticSndngs = tcaElctrnNticSndngRepository.findAllBySndngProcessSttusIn(Arrays.asList(SndngProcessSttusCd.acptok, SndngProcessSttusCd.ensmake, SndngProcessSttusCd.ensstart, SndngProcessSttusCd.ensok, SndngProcessSttusCd.ensopen)); + + return this.fetch(tcaElctrnNticSndngs); + } + + private EnsResponseVO fetch(List tcaElctrnNticSndngs) { + + return EnsResponseVO.okBuilder() + .resultInfo( + tcaElctrnNticSndngs.stream() + .map(row -> trafficCaSigntalkFetcher.execute(row.getElctrnNticSndngId())) + .collect(Collectors.toList()) + ) + .build(); + } + + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/TrafficCaSigntalkAcceptor.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/TrafficCaSigntalkAcceptor.java new file mode 100644 index 0000000..87adc6a --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/TrafficCaSigntalkAcceptor.java @@ -0,0 +1,247 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support; + +import cokr.xit.ens.biz.traffic.cheonan.code.SndngProcessSttusCd; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndng; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndngDetail; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldUpdate; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository.TcaElctrnNticSndngDetailRepository; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository.TcaElctrnNticSndngRepository; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support.accept.AcptDocKkoMd; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support.accept.AcptDocKtGbs; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.Checks; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.utils.MapDeserailizer; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.common.code.VenderCd; +import cokr.xit.ens.core.model.EnsBillAcptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnNotiAcceptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config.AcptData; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config.Document; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config.Receiver; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config.XitProperty; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.IntgrnNotiService; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.utility.RandomString; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class TrafficCaSigntalkAcceptor implements EnsPhaseProcSupport { + + private final TcaElctrnNticSndngRepository tcaElctrnNticSndngRepository; + private final TcaElctrnNticSndngDetailRepository elctrnNticSndngDetailRepository; + + private final IntgrnNotiService intgrnNotiService; + + private Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).serializeNulls().create(); + + + @Value("${xit.mblpage.postse.intgrn.url}") + private String MBLPAGE_URL; + @Value("${xit.mblpage.postse.intgrn.path}") + private String MBLPAGE_PATH; + + /** + * Accept 준비 + * + * @param elctrnNticSndngIds + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List elctrnNticSndngIds) { + try { + AtomicInteger index = new AtomicInteger(); + String prefixExternalDocumentUuid = String.format("B-%s%s", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")), RandomString.make(5)); + elctrnNticSndngIds.stream() + .map(elctrnNticSndngId -> tcaElctrnNticSndngRepository.findById(elctrnNticSndngId).get()) + .map(elctrnNticSndng -> elctrnNticSndngDetailRepository.findAllDecByElctrnNticSndng(elctrnNticSndng)) + .forEach(list -> { + list.stream() + .forEach(row -> { + row.setExternalDocumentUuid(String.format("%s%09d", prefixExternalDocumentUuid, index.getAndIncrement() + 1)); + }); + elctrnNticSndngDetailRepository.saveAll(list); + + } + + ); + return EnsResponseVO.okBuilder().build(); + } catch (Exception e) { + return EnsResponseVO.errBuilder() + .errCode(EnsErrCd.ACPT500) + .errMsg(String.format("문서식별번호(외부) 생성에 실패 했습니다. %s", e.getMessage())) + .build(); + } + + } + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(String elctrnNticSndngId) { + log.info("no process"); + return null; + } + + + /** + * 인증톡 전자고지 접수 + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(String elctrnNticSndngId) { + Map resultInfo = new HashMap<>(); + resultInfo.put("elctrnNticSndngId", elctrnNticSndngId); + + EnsResponseVO responseVO = null; + TcaElctrnNticSndng elctrnNticSndng = null; + try { + elctrnNticSndng = tcaElctrnNticSndngRepository.findById(elctrnNticSndngId) + .orElseThrow(() -> new EnsException(EnsErrCd.ACPT404, String.format("일치하는 TB_ELCTRN_NTIC_SNDNG 데이터가 없습니다. [ elctrnNticSndngId %s ]", elctrnNticSndngId))); + + IntgrnNotiAcceptReqDTO reqDTO = this.convertTbInputDataToAcceptReqDTO(elctrnNticSndngDetailRepository.findAllFetchByElctrnNticSndngId(elctrnNticSndng.getElctrnNticSndngId())); + + EnsResponseVO reqResp = intgrnNotiService.accept(reqDTO); + + + if (EnsErrCd.OK.equals(reqResp.getErrCode())) { + resultInfo.put("intSendMastId", (Long) ((Map) reqResp.getResultInfo()).get("intSendMastId")); + responseVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } else { + responseVO = EnsResponseVO.errRsltBuilder() + .errCode(reqResp.getErrCode()) + .errMsg(reqResp.getErrMsg()) + .resultInfo(reqResp.getResultInfo()) + .build(); + } + } catch (EnsException e) { + responseVO = EnsResponseVO.errRsltBuilder() + .errCode(e.getErrCd()) + .errMsg(String.format("인증톡 \"접수\" 처리 실패. [%s] %s", e.getErrCd().getCode(), e.getMessage())) + .resultInfo(resultInfo) + .build(); + + } catch (Exception e) { + responseVO = EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ACPT500) + .errMsg(String.format("인증톡 \"접수\" 처리 실패. %s", e.getMessage())) + .resultInfo(resultInfo) + .build(); + + } finally { + if (EnsErrCd.OK.equals(responseVO.getErrCode())) { + elctrnNticSndng.setUpdate(FieldUpdate.builder() + .updusr("ENS_SYS") + .updtDt(LocalDateTime.now()) + .build()); + elctrnNticSndng.setSndngProcessSttus(SndngProcessSttusCd.acptok); + elctrnNticSndng.setErrorCn(null); + } else { + elctrnNticSndng.setUpdate(FieldUpdate.builder() + .updusr("ENS_SYS") + .updtDt(LocalDateTime.now()) + .build()); + elctrnNticSndng.setSndngProcessSttus(SndngProcessSttusCd.acptfail); + elctrnNticSndng.setErrorCn(responseVO.getErrMsg()); + if (responseVO.getResultInfo() != null && (responseVO.getResultInfo() instanceof List || responseVO.getResultInfo() instanceof Map)) + elctrnNticSndng.setErrorDtls(gson.toJson(responseVO.getResultInfo())); + } + } + + return responseVO; + } + + + private IntgrnNotiAcceptReqDTO convertTbInputDataToAcceptReqDTO(List list) { + + return IntgrnNotiAcceptReqDTO.builder() + .vender(VenderCd.none.getCode()) + .org_cd(list.get(0).getElctrnNticSndng().getSignguCode()) + .tmplt_cd(list.get(0).getElctrnNticSndng().getTcaNhtTmplatManage().getNhtTmplatId()) + .post_bundle_title( + String.format("%s(%s건)-%s" + , list.get(0).getElctrnNticSndng().getTcaNhtTmplatManage().getNhtNm() + , list.get(0).getElctrnNticSndng().getSndngCo() + , LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ) + ) + .send_dt(list.get(0).getElctrnNticSndng().getSndngDt()) + .close_dt(list.get(0).getElctrnNticSndng().getClosDt()) + .documents( + list.stream() + .map(row -> this.createDocument(row)) + .collect(Collectors.toList()) + ) + .build(); + } + + private Document createDocument(TcaElctrnNticSndngDetail data) throws EnsException { + + String jid = elctrnNticSndngDetailRepository.findIhidnumDecByElctrnNticSndngDetailId(data.getElctrnNticSndngDetailId()); + jid = Checks.isCheckJid(jid) ? jid : "1111111111111"; + + Map tmpltMsgData = null; + if (!CmmnUtil.isEmpty(data.getTmpltMsgData())) + try { + tmpltMsgData = gson.fromJson(data.getTmpltMsgData(), Map.class); + } catch (Exception e) { + throw new EnsException(EnsErrCd.ACPT411, "템플릿메시지데이터의 값은 JSON 포맷만 가능 합니다."); + } + + return Document.builder() + .linked_uuid(data.getExternalDocumentUuid()) + .receiver(Receiver.builder() + .ci(null) +// .jid(data.getIhidnum()) + .jid(jid) + .mblphon_no(null) + .build()) + .acpt_data(AcptData.builder() + .kko_md(new AcptDocKkoMd(data, MBLPAGE_URL + MBLPAGE_PATH).createDocument()) + .kko_at(null) + .nv_st(null) + .kt_gbs(new AcptDocKtGbs(data, MBLPAGE_URL + MBLPAGE_PATH).createDocument()) + .build()) + .xit_property(XitProperty.builder() + .bill_acpt_data(this.createBillAcptData(data)) + .tmplt_msg_data(tmpltMsgData) + .mbl_page_data(this.createDetails(data)) + .build()) + .build(); + } + + private EnsBillAcptReqDTO createBillAcptData(TcaElctrnNticSndngDetail data) { + return null; + } + + private Map>> createDetails(TcaElctrnNticSndngDetail data) { + try { + Map>> m = gson.fromJson(data.getMobilePageCn(), Map.class); + return m; + } catch (Exception e) { + log.error("\"mobilePageCn\" Json Parse 실패. {}", data.getMobilePageCn()); + return null; + } + } + + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/TrafficCaSigntalkFetcher.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/TrafficCaSigntalkFetcher.java new file mode 100644 index 0000000..71b9416 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/TrafficCaSigntalkFetcher.java @@ -0,0 +1,179 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support; + +import cokr.xit.ens.biz.traffic.cheonan.code.SndngProcessSttusCd; +import cokr.xit.ens.biz.traffic.cheonan.code.SndngResultSttusCd; +import cokr.xit.ens.biz.traffic.cheonan.code.SndngSeCd; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndng; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndngDetail; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndngResult; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldCreate; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldUpdate; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository.TcaElctrnNticSndngDetailRepository; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository.TcaElctrnNticSndngRepository; +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository.TcaElctrnNticSndngResultRepository; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnDetailStatVO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnNotiRsltRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.IntgrnNotiService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class TrafficCaSigntalkFetcher implements EnsPhaseProcSupport { + + private final TcaElctrnNticSndngRepository tcaElctrnNticSndngRepository; + private final TcaElctrnNticSndngDetailRepository elctrnNticSndngDetailRepository; + + private final TcaElctrnNticSndngResultRepository tcaElctrnNticSndngResultRepository; + + private final IntgrnNotiService intgrnNotiService; + + + /** + * Fetch 준비 + * + * @param elctrnNticSndngIds + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List elctrnNticSndngIds) { + log.info("no process"); + return null; + } + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(String elctrnNticSndngId) { + log.info("no process"); + return null; + } + + + /** + * 인증톡 발송(성공/실패) 자료에 대한 결과 가져오기 + * + * @param elctrnNticSndngId + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(String elctrnNticSndngId) { + EnsResponseVO responseVO = null; + Map resultInfo = new HashMap<>(); + resultInfo.put("elctrnNticSndngId", elctrnNticSndngId); + + IntgrnNotiRsltRespDTO respDTO = null; + try { + Long intSendMastId = elctrnNticSndngDetailRepository.findLastSendMastIdByElctrnNticSndngId(elctrnNticSndngId) + .orElseThrow(() -> new EnsException(EnsErrCd.RSLT404, "일치하는 ENS 접수자료가 없습니다.")); + resultInfo.put("intSendMastId", intSendMastId); + + + EnsResponseVO apiRespVO = intgrnNotiService.sendResultProvide(intSendMastId); + respDTO = (IntgrnNotiRsltRespDTO) apiRespVO.getResultInfo(); + + + List tcaElctrnNticSndngResults = respDTO.getDocuments().stream() + .map(row -> { + return TcaElctrnNticSndngResult.builder() + .sndngSe(SndngSeCd.valueOfEnum(row.getCurPostSe().getCode())) + .elctrnNticSndngDetailId(elctrnNticSndngDetailRepository.findByExternalDocumentUuid(row.getLinkedUuid()) + .orElse(new TcaElctrnNticSndngDetail()) + .getElctrnNticSndngDetailId()) + .sndngResultSttus(this.sndngResultSttus(row)) + .requstDt(row.getDocSentDt()) + .inqireDt(row.getDocReceivedDt()) + .readngDt(row.getDocReadFrstDt()) + .errorCn(CmmnUtil.isEmpty(row.getErrorMessage()) ? null : row.getErrorMessage()) + .create(FieldCreate.builder() + .register("ENS_SYS") + .registDt(LocalDateTime.now()) + .build()) + .build(); + }) + .collect(Collectors.toList()); + if (tcaElctrnNticSndngResultRepository.findById(tcaElctrnNticSndngResults.get(0).getElctrnNticSndngDetailId()).isPresent()) + tcaElctrnNticSndngResultRepository.modifyByElctrnNticSndngResults(tcaElctrnNticSndngResults); + else + tcaElctrnNticSndngResultRepository.saveAll(tcaElctrnNticSndngResults); + + responseVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } catch (EnsException e) { + responseVO = EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } catch (Exception e) { + responseVO = EnsResponseVO.errBuilder() + .errCode(EnsErrCd.RSLT999) + .errMsg(String.format("[elctrnNticSndngId %s]에 대한 전송결과 FETCH 처리 실패. %s", elctrnNticSndngId, e.getMessage())) + .build(); + } finally { + TcaElctrnNticSndng elctrnNticSndng = tcaElctrnNticSndngRepository.findById(elctrnNticSndngId).orElseThrow(() -> new EnsException(EnsErrCd.RSLT404, "일치하는 tbInputXit 자료가 없습니다.")); + if (EnsErrCd.OK.equals(responseVO.getErrCode())) { + elctrnNticSndng.setUpdate(FieldUpdate.builder() + .updusr("ENS_SYS") + .updtDt(LocalDateTime.now()) + .build()); + elctrnNticSndng.setSndngProcessSttus(this.sndngProcessSttus(respDTO, elctrnNticSndng.getSndngProcessSttus())); + elctrnNticSndng.setErrorCn(null); + } else { + elctrnNticSndng.setUpdate(FieldUpdate.builder() + .updusr("ENS_SYS") + .updtDt(LocalDateTime.now()) + .build()); + elctrnNticSndng.setSndngProcessSttus(SndngProcessSttusCd.ensfail); + elctrnNticSndng.setErrorCn(responseVO.getErrMsg()); + } + } + + return responseVO; + } + + private SndngProcessSttusCd sndngProcessSttus(IntgrnNotiRsltRespDTO respDTO, SndngProcessSttusCd sndngProcessSttus) { + switch (respDTO.getStatCd()) { + case accept: + return sndngProcessSttus; + case makefail: + case sendfail: + return SndngProcessSttusCd.ensfail; + case makerdy: + case making: + case makeok: + return SndngProcessSttusCd.ensmake; + case sendrdy: + case sending: + return SndngProcessSttusCd.ensstart; + case sendok: + case sendcmplt: + return SndngProcessSttusCd.ensok; + case open: + return SndngProcessSttusCd.ensopen; + case close: + return SndngProcessSttusCd.ensclose; + default: + return sndngProcessSttus; + } + } + + private SndngResultSttusCd sndngResultSttus(IntgrnDetailStatVO row) { + return SndngResultSttusCd.valueOfEnum(row.getCurStatCd().getIntgrnDtlStatCd().getCode()); + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/TrafficCaSigntalkMaker.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/TrafficCaSigntalkMaker.java new file mode 100644 index 0000000..7e98b6c --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/TrafficCaSigntalkMaker.java @@ -0,0 +1,64 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository.TcaElctrnNticSndngDetailRepository; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.IntgrnNotiService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Slf4j +@Component +@RequiredArgsConstructor +public class TrafficCaSigntalkMaker implements EnsPhaseProcSupport { + + private final TcaElctrnNticSndngDetailRepository elctrnNticSndngDetailRepository; + + private final IntgrnNotiService intgrnNotiService; + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List elctrnNticSndngIds) { + log.info("no process"); + return null; + } + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(String elctrnNticSndngId) { + log.info("no process"); + return null; + } + + + /** + * 인증톡 전자고지 제작 + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(String elctrnNticSndngId) { + EnsResponseVO responseVO = null; + try { + Long intSendMastId = elctrnNticSndngDetailRepository.findLastSendMastIdByElctrnNticSndngId(elctrnNticSndngId) + .orElseThrow(() -> new EnsException(EnsErrCd.MAKE404, "일치하는 ENS 접수자료가 없습니다.")); + + responseVO = intgrnNotiService.remake(intSendMastId); + } catch (EnsException e) { + responseVO = EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + return responseVO; + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/TrafficCaSigntalkSender.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/TrafficCaSigntalkSender.java new file mode 100644 index 0000000..e131c2e --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/TrafficCaSigntalkSender.java @@ -0,0 +1,64 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository.TcaElctrnNticSndngDetailRepository; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.IntgrnNotiService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Slf4j +@Component +@RequiredArgsConstructor +public class TrafficCaSigntalkSender implements EnsPhaseProcSupport { + + private final TcaElctrnNticSndngDetailRepository elctrnNticSndngDetailRepository; + + private final IntgrnNotiService intgrnNotiService; + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List elctrnNticSndngIds) { + log.info("no process"); + return null; + } + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(String elctrnNticSndngId) { + log.info("no process"); + return null; + } + + + /** + * 인증톡 전자고지 전송요청 + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(String elctrnNticSndngId) { + EnsResponseVO responseVO = null; + try { + Long intSendMastId = elctrnNticSndngDetailRepository.findLastSendMastIdByElctrnNticSndngId(elctrnNticSndngId) + .orElseThrow(() -> new EnsException(EnsErrCd.SEND404, "일치하는 ENS 접수자료가 없습니다.")); + + responseVO = intgrnNotiService.sendBulk(intSendMastId); + } catch (EnsException e) { + responseVO = EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + return responseVO; + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/accept/Accept.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/accept/Accept.java new file mode 100644 index 0000000..b146796 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/accept/Accept.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support.accept; + +public interface Accept { + T createDocument(); +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/accept/AcptDocKkoMd.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/accept/AcptDocKkoMd.java new file mode 100644 index 0000000..e1a23f7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/accept/AcptDocKkoMd.java @@ -0,0 +1,40 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support.accept; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndngDetail; +import cokr.xit.ens.core.utils.DateUtil; +import cokr.xit.ens.modules.kkomydoc.model.config.DocumentConfKkoMd; +import cokr.xit.ens.modules.kkomydoc.model.config.Property; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +@RequiredArgsConstructor +public class AcptDocKkoMd implements Accept { + + private final TcaElctrnNticSndngDetail tcaElctrnNticSndngDetail; + private final String redirectUrl; + + @Override + public DocumentConfKkoMd createDocument() { + return DocumentConfKkoMd.builder() + .hash(null) + .common_categories(Arrays.asList("NOTICE")) + .read_expired_at(DateUtil.dateToAbsTimeSec(tcaElctrnNticSndngDetail.getElctrnNticSndng().getClosDt())) +// .read_expired_sec() + .property(this.createProperty()) + .bridge(null) + .build(); + } + + + private Property createProperty() { + return Property.builder() + .link(this.redirectUrl) + .payload(null) + .message(null) + .cs_name(null) + .cs_number(null) + .build(); + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/accept/AcptDocKtGbs.java b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/accept/AcptDocKtGbs.java new file mode 100644 index 0000000..f3d3d4c --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/cheonan/signtalk/service/support/accept/AcptDocKtGbs.java @@ -0,0 +1,26 @@ +package cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support.accept; + +import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndngDetail; +import cokr.xit.ens.modules.ktsigntalk.gibis.model.config.DocumentConfKtGbs; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class AcptDocKtGbs implements Accept { + + private final TcaElctrnNticSndngDetail tcaElctrnNticSndngDetail; + private final String redirectUrl; + + @Override + public DocumentConfKtGbs createDocument() { + return DocumentConfKtGbs.builder() + .hash(null) + .srcSeq(null) + .mmsDtlCnts(null) +// .mmsTitle() + .rcsDtlCnts(null) + .url(redirectUrl) + .mdn(null) + .build(); + + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/init/TrafficCcJpaRunner.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/init/TrafficCcJpaRunner.java new file mode 100644 index 0000000..e1e7a79 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/init/TrafficCcJpaRunner.java @@ -0,0 +1,125 @@ +package cokr.xit.ens.biz.traffic.chuncheon.init; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.NhtTmplatManageRepository; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.OrgMngDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.service.OrgMngService; +import cokr.xit.ens.modules.common.ctgy.sys.mng.service.TmpltMngService; +import cokr.xit.ens.modules.kkomydoc.model.TmpltMngKkoMydocDTO; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +/** + * 주정차웹-춘천 + */ +@Component +@Transactional +@Profile({"prod-traffic"}) +public class TrafficCcJpaRunner implements ApplicationRunner { + + @Autowired + private OrgMngService orgMngService; + @Autowired + private TmpltMngService tmpltMngService; + + ObjectMapper mapper = new ObjectMapper(); + @Value("${contract.kakao.pay.mydoc.access-token}") + private String KKO_MD_ACCESS_TOKEN = "b40d3c623d1011ecbceae6cf4630da62"; + @Value("${contract.kakao.pay.mydoc.contract-uuid}") + private String KKO_MD_CONTRACT_UUID = "CON-b4126c833d1011ecbceae6cf4630da62"; + private String KKO_BP_BILLER_CODE = null; + private String KKO_BP_AUTHORIZATION = null; + private String KKO_AT_BSID = null; + private String KKO_AT_PASSWD = null; + private String KKO_AT_SENDER_KEY = null; + @Value("${contract.nice.dici.socket.site-code}") + private final String NICE_CD_SITE_CODE = "EQ00"; + @Value("${contract.nice.dici.socket.site-pw}") + private String NICE_CD_SITE_PW = "76646885"; + private String NV_ST_X_NAVER_CLIENT_ID = null; + private String NV_ST_X_NAVER_CLIENT_SECRET = null; + + @Autowired + private NhtTmplatManageRepository nhtTmplatManageRepository; + + @Override + public void run(ApplicationArguments args) throws Exception { + List orgMngResult = createOrgMngDTO().stream().map(dto -> orgMngService.add(dto)).collect(Collectors.toList()); + List tmpltMngResult = createTmpltMngDTO().stream().map(map -> tmpltMngService.add(map, (String) map.get("dtype"))).collect(Collectors.toList()); + System.out.println("============================================================================================================"); + System.out.println("======== Initailize Information [OrgMng & TmpltMng] :: active profiles - " + System.getProperty("spring.profiles.active") + " ========"); + System.out.println(orgMngResult.toString()); + System.out.println(tmpltMngResult.toString()); + System.out.println("============================================================================================================"); + + } + + + private List createOrgMngDTO() { + List list = nhtTmplatManageRepository.findAll() + .stream() + .map(data -> createOrgMngDTO(data.getSignguCode(), "주정차웹CC-" + data.getSignguCode())) + .collect(Collectors.toList()); + return list; + } + + + private List> createTmpltMngDTO() { + List> list = nhtTmplatManageRepository.findAll() + .stream() + .map(data -> createTmpltMngKkoMydoc(data.getSignguCode(), data.getNhtTmplatId(), data.getNhtSj(), data.getNhtCn(), "Y", data.getCstmrCnterTlphonNo(), data.getCstmrCnterNm(), "Y", "Y", "Y")) + .collect(Collectors.toList()); + return list; + } + + final private OrgMngDTO createOrgMngDTO(String orgCd, String orgNm) { + return OrgMngDTO.builder() + .orgCd(orgCd) + .orgNm(orgNm) + .kkoMdAccessToken(KKO_MD_ACCESS_TOKEN) + .kkoMdContractUuid(KKO_MD_CONTRACT_UUID) + .kkoBpBillerCode(KKO_BP_BILLER_CODE) + .kkoBpAuthorization(KKO_BP_AUTHORIZATION) + .kkoBpCsignYn("N") + .kkoBpPrepayApi(null) + .kkoBpPayResultApi(null) + .kkoAtBsid(KKO_AT_BSID) + .kkoAtPasswd(KKO_AT_PASSWD) + .kkoAtSenderKey(KKO_AT_SENDER_KEY) + .niceCdSiteCode(NICE_CD_SITE_CODE) + .niceCdSitePw(NICE_CD_SITE_PW) + .nvStXNaverClientId(NV_ST_X_NAVER_CLIENT_ID) + .nvStXNaverClientSecret(NV_ST_X_NAVER_CLIENT_SECRET) + .nvStOrgId(null) + .build(); + } + + final private Map createTmpltMngKkoMydoc(String orgCd, String tmpltCd, String title, String message, String useYn, String csNumber, String csName, String ciTransUseYn, String tmpltMsgUseYn, String tmpltCsInfoUseYn) { + return mapper.convertValue(TmpltMngKkoMydocDTO.builder() + .dtype("kkomd") + .orgCd(orgCd) + .tmpltCd(tmpltCd) + .title(title) + .message(message) + .useYn(useYn == null ? "Y" : useYn) + .csNumber(csNumber) + .csName(csName) + .ciTransUseYn(ciTransUseYn) + .tmpltMsgUseYn(tmpltMsgUseYn) + .tmpltCsInfoUseYn(tmpltCsInfoUseYn) + .build(), Map.class); + } + + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/ElctrnNticSndng.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/ElctrnNticSndng.java new file mode 100644 index 0000000..697161e --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/ElctrnNticSndng.java @@ -0,0 +1,73 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded.FieldCreate; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded.FieldUpdate; +import lombok.*; +import org.springframework.context.annotation.Profile; + +import javax.persistence.*; + +/** + *
    + *
  • 업무 그룹명: 전자고지발송 테이블
  • + *
  • 설 명:
  • + *
  • 작성일: 2021. 12. 22. 오후 5:44:32 + *
+ * + * @author 박민규 + */ +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "tb_elctrn_ntic_sndng") +@Profile("prod-traffic") +public class ElctrnNticSndng { + + + @Id + @Column(name = "elctrn_ntic_sndng_id", length = 20) + private String elctrnNticSndngId; + + @Column(name = "signgu_code", length = 5) + private String signguCode; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "nht_tmplat_id") + private NhtTmplatManage nhtTmplatManage; + + @Column(name = "sndng_ty_code", length = 5) + private String sndngTyCode; + + @Column(name = "sndng_co", length = 10) + private Integer sndngCo; + + @Column(name = "sndng_process_sttus", length = 2) + @Setter + private String sndngProcessSttus; + + @Column(name = "sndng_dt", length = 14) + private String sndngDt; + + @Column(name = "clos_dt", length = 14) + private String closDt; + + @Embedded + private FieldCreate create; + + @Embedded + @Setter + private FieldUpdate update; + + @Column(name = "error_cn", length = 1000) + @Setter + private String errorCn; + @Lob + @Setter + @Column(name = "error_dtls") + private String errorDtls; + + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/ElctrnNticSndngDetail.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/ElctrnNticSndngDetail.java new file mode 100644 index 0000000..1be1d57 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/ElctrnNticSndngDetail.java @@ -0,0 +1,68 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded.FieldCreate; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded.FieldUpdate; +import lombok.*; +import org.hibernate.annotations.DynamicUpdate; +import org.springframework.context.annotation.Profile; + +import javax.persistence.*; + +/** + *
    + *
  • 업무 그룹명: 전자고지발송상세 테이블
  • + *
  • 설 명:
  • + *
  • 작성일: 2021. 12. 22. 오후 5:45:01 + *
+ * + * @author mk1126sj + */ +@Getter +@ToString +@Builder +@DynamicUpdate +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "tb_elctrn_ntic_sndng_detail", schema = "", catalog = "", indexes = { + @Index(name = "idx_tcc_ens_detail_01", columnList = "external_document_uuid") +}) +@Profile("prod-traffic") +public class ElctrnNticSndngDetail { + + + @Id + @Column(name = "elctrn_ntic_sndng_detail_id", length = 20) + private String elctrnNticSndngDetailId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "elctrn_ntic_sndng_id") + private ElctrnNticSndng elctrnNticSndng; + + @Column(name = "signgu_code", length = 5, columnDefinition = "char") + private String signguCode; + + @Column(name = "main_code", length = 20) + private String mainCode; + + @Column(name = "ihidnum", length = 100, updatable = false) + private String ihidnum; + + @Lob + @Column(name = "cn_detail") + private String cnDetail; + + @Lob + @Column(name = "mobile_page_cn") + private String mobilePageCn; + + @Embedded + private FieldCreate create; + + @Embedded + private FieldUpdate update; + + @Column(name = "external_document_uuid", length = 40) + @Setter + private String externalDocumentUuid; +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/ElctrnNticSndngResult.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/ElctrnNticSndngResult.java new file mode 100644 index 0000000..b3cabe4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/ElctrnNticSndngResult.java @@ -0,0 +1,52 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded.FieldCreate; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.annotations.UpdateTimestamp; +import org.springframework.context.annotation.Profile; + +import javax.persistence.*; +import java.time.LocalDateTime; + +/** + *
    + *
  • 업무 그룹명: 전자고지발송결과 테이블
  • + *
  • 설 명:
  • + *
  • 작성일: 2021. 12. 22. 오후 5:45:14 + *
+ * + * @author mk1126sj + */ +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "tb_elctrn_ntic_sndng_result") +@Profile("prod-traffic") +public class ElctrnNticSndngResult { + + + @Id + @Column(name = "elctrn_ntic_sndng_detail_id", length = 20) + private String elctrnNticSndngDetailId; + @Column(name = "sndng_result_code", length = 4) + private String sndngResultCode; + @Column(name = "requst_dt", length = 14) + private String requstDt; + @Column(name = "inqire_dt", length = 14) + private String inqireDt; + @Column(name = "readng_dt", length = 14) + private String readngDt; + @Column(name = "error_cn", length = 1000) + private String errorCn; + @Embedded + private FieldCreate create; + + + @UpdateTimestamp + @Column(name = "last_updt_dt", nullable = true) + private LocalDateTime lastUpdtDt; +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/NhtTmplatManage.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/NhtTmplatManage.java new file mode 100644 index 0000000..bb41cf5 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/NhtTmplatManage.java @@ -0,0 +1,68 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded.FieldCreate; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded.FieldUpdate; +import lombok.*; +import org.springframework.context.annotation.Profile; + +import javax.persistence.*; + +/** + *
    + *
  • 업무 그룹명: 고지서템플릿관리 테이블
  • + *
  • 설 명:
  • + *
  • 작성일: 2021. 12. 22. 오후 5:44:32 + *
+ * + * @author 박민규 + */ +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "tb_nht_tmplat_manage") +@Profile("prod-traffic") +public class NhtTmplatManage { + + + @Id + @Column(name = "nht_tmplat_id", length = 5) + private String nhtTmplatId; + + @Column(name = "signgu_code", columnDefinition = "char(5)") + private String signguCode; + + @Column(name = "sndng_ty_code", length = 1) + private String sndngTyCode; + + @Column(name = "nht_nm", length = 1000) + private String nhtNm; + + @Column(name = "nht_sj", length = 1000) + private String nhtSj; + + @Column(name = "nhtCn", length = 4000) + private String nhtCn; + + @Column(name = "cstmr_cnter_nm", length = 100) + private String cstmrCnterNm; + + @Column(name = "cstmr_cnter_tlphon_no", length = 14) + private String cstmrCnterTlphonNo; + + @Column(name = "redirect_url", length = 255) + private String redirectUrl; + + @Column(name = "use_at", length = 1) + private String useAt; + + @Embedded + private FieldCreate create; + + @Embedded + private FieldUpdate update; + + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/embeded/FieldCreate.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/embeded/FieldCreate.java new file mode 100644 index 0000000..4562563 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/embeded/FieldCreate.java @@ -0,0 +1,35 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded; + +import lombok.*; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.PrePersist; +import java.time.LocalDateTime; + + +@Embeddable +@Getter +@RequiredArgsConstructor +public class FieldCreate { + +// @CreationTimestamp +// @Temporal(TemporalType.TIMESTAMP) + @Column(name = "regist_dt") + private LocalDateTime registDt; + @Column(name = "register", length = 50) + private String register; + + + @PrePersist + public void preUpdate() { + this.registDt = LocalDateTime.now(); + } + + + @Builder(builderMethodName = "builder") + public FieldCreate(String register, LocalDateTime registDt) { + this.register = register; + this.registDt = registDt; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/embeded/FieldUpdate.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/embeded/FieldUpdate.java new file mode 100644 index 0000000..57a1078 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/embeded/FieldUpdate.java @@ -0,0 +1,34 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded; + +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.PreUpdate; +import java.time.LocalDateTime; + +@Embeddable +@Getter +@RequiredArgsConstructor +public class FieldUpdate { + +// @UpdateTimestamp +// @Temporal(TemporalType.TIMESTAMP) + @Column(name = "updt_dt") + private LocalDateTime updtDt; + @Column(name = "updusr", length = 50) + private String updusr; + + @PreUpdate + public void preUpdate() { + this.updtDt = LocalDateTime.now(); + } + + @Builder(builderMethodName = "builder") + public FieldUpdate(String updusr, LocalDateTime updtDt) { + this.updusr = updusr; + this.updtDt = updtDt; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngDetailRepository.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngDetailRepository.java new file mode 100644 index 0000000..9362b08 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngDetailRepository.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndngDetail; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface ElctrnNticSndngDetailRepository extends JpaRepository, ElctrnNticSndngDetailRepositoryCustom { + + Optional findByExternalDocumentUuid(String externalDocumentUuid); + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngDetailRepositoryCustom.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngDetailRepositoryCustom.java new file mode 100644 index 0000000..df814f8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngDetailRepositoryCustom.java @@ -0,0 +1,20 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndng; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndngDetail; + +import java.util.List; +import java.util.Optional; + +public interface ElctrnNticSndngDetailRepositoryCustom { + + + List findAllDecByElctrnNticSndng(ElctrnNticSndng elctrnNticSndng); + + + List findAllFetchByElctrnNticSndngId(String elctrnNticSndngId); + + Optional findLastSendMastIdByElctrnNticSndngId(String elctrnNticSndngId); + + String findIhidnumDecByElctrnNticSndngDetailId(String elctrnNticSndngDetailId); +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngDetailRepositoryImpl.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngDetailRepositoryImpl.java new file mode 100644 index 0000000..33c70c1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngDetailRepositoryImpl.java @@ -0,0 +1,83 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndng; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndngDetail; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.util.List; +import java.util.Optional; + +import static cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.QElctrnNticSndng.elctrnNticSndng; +import static cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.QElctrnNticSndngDetail.elctrnNticSndngDetail; +import static cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.QNhtTmplatManage.nhtTmplatManage; +import static cokr.xit.ens.modules.kkomydoc.domain.QSendDetailKkoMydoc.sendDetailKkoMydoc; + +@RequiredArgsConstructor +public class ElctrnNticSndngDetailRepositoryImpl implements ElctrnNticSndngDetailRepositoryCustom { + + private final JPAQueryFactory query; + + @Override + public List findAllDecByElctrnNticSndng(ElctrnNticSndng elctrnNticSndng) { + + return query.select(Projections.fields(ElctrnNticSndngDetail.class + , elctrnNticSndngDetail.elctrnNticSndngDetailId + , elctrnNticSndngDetail.elctrnNticSndng + , elctrnNticSndngDetail.signguCode + , elctrnNticSndngDetail.mainCode + , Expressions.stringTemplate("ECL_DECRYPT({0})", elctrnNticSndngDetail.ihidnum).as("ihidnum") + , elctrnNticSndngDetail.cnDetail + , elctrnNticSndngDetail.mobilePageCn + , elctrnNticSndngDetail.create + , elctrnNticSndngDetail.update + , elctrnNticSndngDetail.externalDocumentUuid)) + .from(elctrnNticSndngDetail) + .where(elctrnNticSndngDetail.elctrnNticSndng.eq(elctrnNticSndng)) + .fetch(); + } + + + @Override + public List findAllFetchByElctrnNticSndngId(String elctrnNticSndngId) { + return query.selectFrom(elctrnNticSndngDetail) + .innerJoin(elctrnNticSndngDetail.elctrnNticSndng, elctrnNticSndng) + .fetchJoin() + .innerJoin(elctrnNticSndng.nhtTmplatManage, nhtTmplatManage) + .fetchJoin() + .where(elctrnNticSndngDetail.elctrnNticSndng.elctrnNticSndngId.eq(elctrnNticSndngId)) + .fetch(); + + } + + + @Override + public Optional findLastSendMastIdByElctrnNticSndngId(String elctrnNticSndngId) { + return Optional.ofNullable(query.select(sendDetailKkoMydoc.sendMast.sendMastId) + .from(sendDetailKkoMydoc) +// .where(sendDetailKkoMydoc.propExternalDocumentUuid.in(findExternalDocumentUuidsByLnkInputId(elctrnNticSndngId))) + .innerJoin(elctrnNticSndngDetail).on(sendDetailKkoMydoc.propExternalDocumentUuid.eq(elctrnNticSndngDetail.externalDocumentUuid)) + .where(elctrnNticSndngDetail.elctrnNticSndng.elctrnNticSndngId.eq(elctrnNticSndngId)) + .groupBy(sendDetailKkoMydoc.sendMast.sendMastId) + .orderBy(sendDetailKkoMydoc.sendMast.sendMastId.desc()) + .fetchFirst()); + } + + private List findExternalDocumentUuidsByLnkInputId(String elctrnNticSndngId) { + return query.select(elctrnNticSndngDetail.externalDocumentUuid) + .from(elctrnNticSndngDetail) + .where(elctrnNticSndngDetail.elctrnNticSndng.elctrnNticSndngId.eq(elctrnNticSndngId)) + .fetch(); + } + + + @Override + public String findIhidnumDecByElctrnNticSndngDetailId(String elctrnNticSndngDetailId) { + return query.select(Expressions.stringTemplate("ECL_DECRYPT({0})", elctrnNticSndngDetail.ihidnum).as("ihidnum")) + .from(elctrnNticSndngDetail) + .where(elctrnNticSndngDetail.elctrnNticSndngDetailId.eq(elctrnNticSndngDetailId)) + .fetchOne(); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngRepository.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngRepository.java new file mode 100644 index 0000000..252728b --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngRepository.java @@ -0,0 +1,15 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndng; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface ElctrnNticSndngRepository extends JpaRepository { + + + List findAllBySndngProcessSttus(String sndngProcessSttus); + + List findAllBySndngProcessSttusIn(List sndngProcessSttuss); + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngResultRepository.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngResultRepository.java new file mode 100644 index 0000000..6e14c2d --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngResultRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndngResult; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ElctrnNticSndngResultRepository extends JpaRepository, ElctrnNticSndngResultRepositoryCustom { + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngResultRepositoryCustom.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngResultRepositoryCustom.java new file mode 100644 index 0000000..3069fab --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngResultRepositoryCustom.java @@ -0,0 +1,13 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndngResult; + +import java.util.List; + +public interface ElctrnNticSndngResultRepositoryCustom { + + + + + void modifyByElctrnNticSndngResults(List elctrnNticSndngResults); +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngResultRepositoryImpl.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngResultRepositoryImpl.java new file mode 100644 index 0000000..2631832 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/ElctrnNticSndngResultRepositoryImpl.java @@ -0,0 +1,34 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndngResult; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +import static cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.QElctrnNticSndngResult.elctrnNticSndngResult; + +@RequiredArgsConstructor +public class ElctrnNticSndngResultRepositoryImpl implements ElctrnNticSndngResultRepositoryCustom { + + private final JPAQueryFactory query; + + @Override + public void modifyByElctrnNticSndngResults(List elctrnNticSndngResults) { + elctrnNticSndngResults.forEach(data -> + query.update(elctrnNticSndngResult) + .set(elctrnNticSndngResult.sndngResultCode, data.getSndngResultCode()) + .set(elctrnNticSndngResult.requstDt, data.getRequstDt()) + .set(elctrnNticSndngResult.inqireDt, data.getInqireDt()) + .set(elctrnNticSndngResult.readngDt, data.getReadngDt()) + .set(elctrnNticSndngResult.errorCn, data.getErrorCn()) +// .set(elctrnNticSndngResult.create, FieldCreate.builder().build()) + .set(elctrnNticSndngResult.lastUpdtDt, LocalDateTime.now()) + .where(elctrnNticSndngResult.elctrnNticSndngDetailId.eq(data.getElctrnNticSndngDetailId())) + .execute() + ); + } + + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/NhtTmplatManageRepository.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/NhtTmplatManageRepository.java new file mode 100644 index 0000000..20c9cce --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/domain/repository/NhtTmplatManageRepository.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.NhtTmplatManage; +import org.springframework.data.jpa.repository.JpaRepository; + + +public interface NhtTmplatManageRepository extends JpaRepository { + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v1/mq/UserElctrnNticProducer.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v1/mq/UserElctrnNticProducer.java new file mode 100644 index 0000000..43d38bc --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v1/mq/UserElctrnNticProducer.java @@ -0,0 +1,32 @@ +//package cokr.xit.ens.biz.traffic.chuncheon.mydoc.v1.mq; +// +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.kafka.core.KafkaTemplate; +//import org.springframework.stereotype.Component; +// +//import lombok.extern.slf4j.Slf4j; +// +//@Slf4j +//@Component +//public class UserElctrnNticProducer { +// +// @Autowired +// private KafkaTemplate kafkaTemplate; +// +// +// public void pubBulkSend(String message) { +// final String topicName = "kkomydoc-send-bulk"; +// +// log.info(String.format("[%s] pub message : %s", topicName, message)); +// +// this.kafkaTemplate.send(topicName, message); +// } +// +// public void pubBulkStatus(String message) { +// final String topicName = "kkomydoc-status-bulk"; +// +// log.info(String.format("[%s] pub message : %s", topicName, message)); +// +// this.kafkaTemplate.send(topicName, message); +// } +//} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v1/sched/TrafficKkoMydocScheduler.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v1/sched/TrafficKkoMydocScheduler.java new file mode 100644 index 0000000..75e8917 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v1/sched/TrafficKkoMydocScheduler.java @@ -0,0 +1,55 @@ +//package cokr.xit.ens.biz.traffic.chuncheon.mydoc.v1.sched; +// +//import cokr.xit.ens.biz.traffic.chuncheon.mydoc.v1.service.UserElctrnNticService; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.context.annotation.Profile; +//import org.springframework.scheduling.annotation.Scheduled; +//import org.springframework.stereotype.Component; +// +//import javax.annotation.Resource; +// +//@Slf4j +//@Component +////@Profile("!local") +//@Profile("prod-traffic") +//public class TrafficKkoMydocScheduler { +// +// @Resource +// private UserElctrnNticService service; +// +// /** +// * 인증톡 전송요청 +// */ +// @Scheduled(cron = "0 */1 * * * *") +// public void runSend() { +// log.info("[Schduler]KkoMydoc \"send\" run..."); +// service.send(); +// } +// +// /** +// * 인증톡 전송결과 갱신 +// */ +// @Scheduled(cron = "0 */3 * * * *") +// public void runResult() { +// log.info("[Schduler]KkoMydoc \"result\" run..."); +// service.result(); +// } +// +// /** +// * 인증톡 상태 갱신 +// */ +// @Scheduled(cron = "0 0 */1 * * *") +// public void runStatus() { +// log.info("[Schduler]KkoMydoc \"status\" run..."); +// service.status(); +// } +// +// /** +// * 인증톡 상태 가져오기 +// */ +// @Scheduled(cron = "0 */30 * * * *") +// public void runFetchStatus() { +// log.info("[Schduler]KkoMydoc \"fetchStatus\" run..."); +// service.fetchStatus(); +// } +//} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v1/service/UserElctrnNticService.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v1/service/UserElctrnNticService.java new file mode 100644 index 0000000..b219f01 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v1/service/UserElctrnNticService.java @@ -0,0 +1,296 @@ +//package cokr.xit.ens.biz.traffic.chuncheon.mydoc.v1.service; +// +//import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndng; +//import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndngDetail; +//import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndngResult; +//import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngDetailRepository; +//import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngRepository; +//import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngResultRepository; +//import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.NhtTmplatManageRepository; +//import cokr.xit.ens.biz.traffic.chuncheon.mydoc.v1.mq.UserElctrnNticProducer; +//import cokr.xit.ens.core.aop.EnsResponseVO; +//import cokr.xit.ens.core.exception.EnsException; +//import cokr.xit.ens.core.exception.code.EnsErrCd; +//import cokr.xit.ens.core.utils.CmmnUtil; +//import cokr.xit.ens.core.utils.crypto.SHA256; +//import cokr.xit.ens.modules.kkomydoc.v1.domain.repository.SendDetailKkoMydocRepository; +//import cokr.xit.ens.modules.kkomydoc.v1.model.BulkSendReqDTO; +//import cokr.xit.ens.modules.kkomydoc.v1.model.child.Document; +//import cokr.xit.ens.modules.kkomydoc.v1.model.child.NotiDocument; +//import cokr.xit.ens.modules.kkomydoc.v1.model.child.Property; +//import cokr.xit.ens.modules.kkomydoc.v1.model.child.Receiver; +//import cokr.xit.ens.modules.nicedici.service.NiceDiCiService; +//import com.fasterxml.jackson.databind.ObjectMapper; +//import lombok.RequiredArgsConstructor; +//import lombok.extern.slf4j.Slf4j; +//import net.bytebuddy.utility.RandomString; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.stereotype.Service; +//import org.springframework.transaction.annotation.Transactional; +//import org.springframework.util.StringUtils; +// +//import java.text.SimpleDateFormat; +//import java.util.*; +// +//@Slf4j +//@Service +//@RequiredArgsConstructor +//public class UserElctrnNticService { +// private final ElctrnNticSndngRepository elctrnNticSndngRepository; +// private final ElctrnNticSndngDetailRepository elctrnNticSndngDetailRepository; +// private final ElctrnNticSndngResultRepository elctrnNticSndngResultRepository; +// private final NhtTmplatManageRepository nhtTmplatManageRepository; +// private final SendDetailKkoMydocRepository sendDetailKkoMydocRepository; +// private final NiceDiCiService nicedDiCiService; +// +// +// @Autowired +// private UserElctrnNticProducer userElctrnNticProducer; +// +// @Value("${contract.nice.dici.socket.site-code}") +// private String SITE_CODE; +// @Value("${contract.nice.dici.socket.site-pw}") +// private String SITE_PW; +// @Value("${contract.kakao.pay.mydoc.access-token}") +// private String ACCESS_TOKEN; +// @Value("${contract.kakao.pay.mydoc.contract-uuid}") +// private String CONTRACT_UUID; +// +// +// /** +// * 발송 +// */ +// @Transactional +// public void send() { +// +// SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmm"); +// String yyyyMMddHHmm = dateFormat.format(new Date()); +// String beginSndngDt = String.format("%s00", yyyyMMddHHmm); +// String endSndngDt = String.format("%s59", yyyyMMddHHmm); +// this.send(beginSndngDt, endSndngDt); +// } +// /** +// * 발송 +// */ +// @Transactional +// public void send(String beginSndngDt, String endSndngDt) { +// +// List list = elctrnNticSndngRepository.findAllBySndngProcessSttusAndSndngDtBetween("01", beginSndngDt, endSndngDt); +// for(ElctrnNticSndng row : list) { +// List detailList = elctrnNticSndngDetailRepository.findAllDecByElctrnNticSndng(row); +// +// List jsonStrList = new ArrayList<>(); +// try { +// jsonStrList = makeMessage(row, detailList); +// } catch (Exception e) { +// row.setSndngProcessSttus("99"); +// row.setErrorCn(e.getMessage()); +// elctrnNticSndngRepository.save(row); +// continue; +// } +// +// for(String jsonStr : jsonStrList) { +// Map m = new HashMap<>(); +// m.put("accessToken", ACCESS_TOKEN); +// m.put("contractUuid", CONTRACT_UUID); +// m.put("jsonStr", jsonStr); +// userElctrnNticProducer.pubBulkSend(CmmnUtil.toJsonString(m)); +// } +// +// +// elctrnNticSndngDetailRepository.saveAll(detailList); +// } +// +// +// } +// +// +// /** +// * 메시지포맷 작성 +// */ +// @SuppressWarnings("deprecation") +// private List makeMessage(ElctrnNticSndng sndng, List sndngDetails) throws EnsException { +// List jsonStrList = new ArrayList<>(); +// +// List documents = new ArrayList<>(); +// List notidocuments = new ArrayList<>(); +// SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS"); +// String prefixExternalDocumentUuid = String.format("B-%s%s", simpleDateFormat.format(new Date()), RandomString.make(5)); +// int seq = 0; +// for(ElctrnNticSndngDetail row : sndngDetails) { +// +// String siteCode = SITE_CODE; +// String sitePw = SITE_PW; +// String payload = row.getMainCode(); +// String hash = null; +// try { +// if(StringUtils.isEmpty(row.getCnDetail())) +// hash = SHA256.encrypt(row.getMainCode()); +// else +// hash = SHA256.encrypt(row.getCnDetail()); +//// } catch (NoSuchAlgorithmException e) { +// } catch (Exception e) { +// log.error(String.format("Hash 값 생성에 실패 하였습니다. [%s]. ", row.getCnDetail()), e); +// } +// +// EnsResponseVO ensResponseVO = nicedDiCiService.ci(siteCode, sitePw, row.getIhidnum()); +// String ci = ((Map)ensResponseVO.getResultInfo()).get("ci"); +// Document document = new Document(); +// document.setTitle(sndng.getNhtTmplatManage().getNhtSj()); +// document.setCommon_categories(new String[] {"NOTICE"}); +// document.setHash(hash); +// Receiver receiver = new Receiver(); +// if(ci==null) { +// receiver.setPhone_number(null); +// receiver.setName(null); +// receiver.setBirthday(null); +// receiver.setIs_required_verify_name(true); +// }else { +// receiver.setCi(ci); +// } +// document.setReceiver(receiver); +// Property property = new Property(); +// String externalDocumentUuid = String.format("%s%09d", prefixExternalDocumentUuid, ++seq); +// row.setLinkedUuid(externalDocumentUuid); +// property.setLink(sndng.getNhtTmplatManage().getRedirectUrl()); +// property.setPayload(payload); +// property.setMessage(sndng.getNhtTmplatManage().getNhtCn()); +// property.setCs_number(sndng.getNhtTmplatManage().getCstmrCnterTlphonNo()); +// property.setCs_name(StringUtils.isEmpty(sndng.getNhtTmplatManage().getCstmrCnterNm())?"문의처":sndng.getNhtTmplatManage().getCstmrCnterNm()); +// property.setExternal_document_uuid(externalDocumentUuid); +// document.setProperty(property); +// documents.add(document); +// +// +// +// if(!StringUtils.isEmpty(row.getElctrnNticSndng())) { +// if(!StringUtils.isEmpty(row.getMobilePageCn())) +// try { +// +//// NotiDocument notiDocument = (NotiDocument) CmmnUtil.jsonStringtoObj(NotiDocument.class, row.getMobilePageCn()); +// ObjectMapper mapper = new ObjectMapper(); +// NotiDocument notiDocument = mapper.readValue(row.getMobilePageCn(), NotiDocument.class); +// notiDocument.setPayload``(payload); +// notidocuments.add(notiDocument); +// } catch (Exception e) { +// // log.error(String.format("고지정보 변환에 실패 했습니다. [%s]", row.getMobilePageCn()), e); +// throw new EnsException(EnsErrCd.ERR405, String.format("고지정보 변환에 실패 했습니다. [%s]. %s", row.getMobilePageCn(), e.getMessage())); +// } +// } +// +// +// +// if(documents.size()==100) { +// BulkSendReqDTO bulkSendReqDTO = new BulkSendReqDTO(); +// bulkSendReqDTO.setDocuments(documents); +// bulkSendReqDTO.setNotidocuments(notidocuments); +// jsonStrList.add(CmmnUtil.toJsonString(bulkSendReqDTO)); +// documents = new ArrayList<>(); +// notidocuments = new ArrayList<>(); +// } +// +// } +// +// +// +// BulkSendReqDTO bulkSendReqDTO = new BulkSendReqDTO(); +// bulkSendReqDTO.setDocuments(documents); +// bulkSendReqDTO.setNotidocuments(notidocuments); +// jsonStrList.add(CmmnUtil.toJsonString(bulkSendReqDTO)); +// +// +// +// return jsonStrList; +// } +// +// +// +// /** +// * 발송결과 업데이트 +// */ +// @Transactional +// public void result() { +// +// SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmm"); +// Calendar cal = Calendar.getInstance(); +// Date date = new Date(); +// cal.setTime(date); +// cal.add(Calendar.MINUTE, -3); +// String beginSndngDt = String.format("%s00", dateFormat.format(cal.getTime())); +// cal.setTime(date); +// cal.add(Calendar.MINUTE, -1); +// String endSndngDt = String.format("%s59", dateFormat.format(new Date())); +// +// this.result(beginSndngDt, endSndngDt); +// } +// /** +// * 발송결과 업데이트 +// */ +// @SuppressWarnings("deprecation") +// @Transactional +// public void result(String beginSndngDt, String endSndngDt) { +// List list = elctrnNticSndngRepository.findAllBySndngProcessSttusAndSndngDtBetween("01", beginSndngDt, endSndngDt); +// +// +// for(ElctrnNticSndng row : list) { +// List sndngResultList = elctrnNticSndngResultRepository.findAllByElctrnNticSndngId(row.getElctrnNticSndngId()); +// elctrnNticSndngResultRepository.saveAll(sndngResultList); +// row.setSndngProcessSttus("99"); +// for(ElctrnNticSndngResult sndngResult : sndngResultList) { +// if(StringUtils.isEmpty(sndngResult.getErrorCn())) { +// row.setSndngProcessSttus("02"); +// break; +// } +// } +// elctrnNticSndngRepository.save(row); +// +// } +// +// } +// +// /** +// * +// * 메소드 설명: 상태변경 +// * @author: mk1126sj +// * @date: 2021. 12. 29. +// */ +// @Transactional +// public void status() { +// +// List list = elctrnNticSndngRepository.findAllBySndngProcessSttus("02"); +// +// for(ElctrnNticSndng row : list) { +// List externalDocumentUuidList = elctrnNticSndngDetailRepository.findExternalDocumentUuidByElctrnNticSndng(row); +// +// Map m = new HashMap<>(); +// m.put("accessToken", ACCESS_TOKEN); +// m.put("contractUuid", CONTRACT_UUID); +// m.put("externalDocumentUuidList", externalDocumentUuidList); +// userElctrnNticProducer.pubBulkStatus(CmmnUtil.toJsonString(m)); +// } +// +// } +// +// +// /** +// * +// * 메소드 설명: 발송마스터 및 발송상세 상태정보 fetch +// * void 요청처리 후 응답객체 +// * @author: mk1126sj +// * @date: 2021. 12. 29. +// */ +// public void fetchStatus() { +// +// List list = elctrnNticSndngRepository.findAllBySndngProcessSttus("02"); +// +// for(ElctrnNticSndng row : list) { +// elctrnNticSndngResultRepository.saveFetchStatus(row); +// } +// +// } +// +// +// +// +//} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/model/TrafficCcMydocReqDTO.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/model/TrafficCcMydocReqDTO.java new file mode 100644 index 0000000..b42ce0f --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/model/TrafficCcMydocReqDTO.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +@Getter +@Schema(name = "TrafficCcMydocReqDTO") +public class TrafficCcMydocReqDTO { + + @Schema(required = true, title = "전자 고지 발송 Id", example = " ") + private String elctrnNticSndngId; +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/presentation/TrafficCcMydocController.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/presentation/TrafficCcMydocController.java new file mode 100644 index 0000000..c6b79d2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/presentation/TrafficCcMydocController.java @@ -0,0 +1,53 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.presentation; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.model.TrafficCcMydocReqDTO; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.TrafficCcMydocService; +import cokr.xit.ens.core.aop.EnsResponseVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; + +@Tag(name = "TrafficCcSigntalkController") +@Slf4j +@Controller +@RequiredArgsConstructor +public class TrafficCcMydocController { + + private final TrafficCcMydocService trafficCcMydocService; + + @Operation(summary = "접수") + @PostMapping(value = "/traffic/cc/mydoc/accept", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity accept(@RequestBody TrafficCcMydocReqDTO reqDTO){ + EnsResponseVO responseVO = trafficCcMydocService.accept(reqDTO.getElctrnNticSndngId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "제작") + @PutMapping(value = "/traffic/cc/mydoc/re/make", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity reMake(@RequestBody TrafficCcMydocReqDTO reqDTO){ + EnsResponseVO responseVO = trafficCcMydocService.reMake(reqDTO.getElctrnNticSndngId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "전송") + @PutMapping(value = "/traffic/cc/mydoc/re/send", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity reSend(@RequestBody TrafficCcMydocReqDTO reqDTO){ + EnsResponseVO responseVO = trafficCcMydocService.reSend(reqDTO.getElctrnNticSndngId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "전송결과가져오기") + @PostMapping(value = "/traffic/cc/mydoc/fetch", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity fetch(@RequestBody TrafficCcMydocReqDTO reqDTO){ + EnsResponseVO responseVO = trafficCcMydocService.fetch(reqDTO.getElctrnNticSndngId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/sched/TrafficCcMydocScheduler.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/sched/TrafficCcMydocScheduler.java new file mode 100644 index 0000000..c6575bc --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/sched/TrafficCcMydocScheduler.java @@ -0,0 +1,46 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.sched; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.TrafficCcMydocService; +import cokr.xit.ens.core.aop.EnsResponseVO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@Profile("prod-traffic") +@RequiredArgsConstructor +public class TrafficCcMydocScheduler { + + private final TrafficCcMydocService trafficCcMydocService; + + /** + * 인증톡 접수 + * -. 인증톡 전송을 위해 TRAFFIC에 등록된 기초데이터를 ENS에 이관 등록 한다. + */ + @Scheduled(cron = "0 */1 7-22 * * *") + public void accepted(){ + EnsResponseVO responseVO = trafficCcMydocService.acceptAll(); + log.info("======================================================="); + log.info("[TRAFFIC] 인증톡 접수처리 결과"); + log.info(responseVO.toString()); + log.info("======================================================="); + } + + + /** + * 인증톡 결과 가져오기 + * -. 전송이 완료된 인증톡 전송결과(성공/실패)를 ENS -> TRAFFIC 로 가져와 DB에 저장한다. + */ + @Scheduled(cron = "0 */15 7-22 * * *") + public void fetched(){ + EnsResponseVO responseVO = trafficCcMydocService.fetchAll(); + + log.info("======================================================="); + log.info("[TRAFFIC] 인증톡 요청문서정보 Fetch 결과"); + log.info(responseVO.toString()); + log.info("======================================================="); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/TrafficCcMydocService.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/TrafficCcMydocService.java new file mode 100644 index 0000000..28bb58c --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/TrafficCcMydocService.java @@ -0,0 +1,167 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndng; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngRepository; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.support.TrafficCcMydocAcceptor; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.support.TrafficCcMydocFetcher; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.support.TrafficCcMydocMaker; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.support.TrafficCcMydocSender; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.kkomydoc.service.event.KkoMydocSendReserveEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional +public class TrafficCcMydocService { + + private final ElctrnNticSndngRepository elctrnNticSndngRepository; + + private final TrafficCcMydocAcceptor trafficCcMydocAcceptor; + private final TrafficCcMydocMaker trafficCcMydocMaker; + private final TrafficCcMydocSender trafficCcMydocSender; + private final TrafficCcMydocFetcher trafficCcMydocFetcher; + + private final ApplicationEventPublisher applicationEventPublisher; + + + + /** + * 인증톡 접수(TRAFFIC -> ENS) + */ + public EnsResponseVO accept(String elctrnNticSndngId){ + + try { + + ElctrnNticSndng elctrnNticSndng = elctrnNticSndngRepository.findById(elctrnNticSndngId) + .orElseThrow(()->new EnsException(EnsErrCd.ACPT404, "일치하는 자료가 없거나 \"요청(01)\" 상태가 아닙니다.")); + + return this.accept(Arrays.asList(elctrnNticSndng)).getResultInfo().get(0); + } catch (EnsException e){ + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + } + /** + * 인증톡 접수(TRAFFIC -> ENS) + */ + public EnsResponseVO> acceptAll(){ + try { + + List elctrnNticSndngs = elctrnNticSndngRepository.findAllBySndngProcessSttus("01"); + if(CmmnUtil.isEmpty(elctrnNticSndngs)) + throw new EnsException(EnsErrCd.ACPT404, "\"요청(01)\" 상태의 자료가 없습니다."); + + return this.accept(elctrnNticSndngs); + } catch (EnsException e){ + return EnsResponseVO.>errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + } + private EnsResponseVO> accept(List elctrnNticSndngs){ + EnsResponseVO responseVO = trafficCcMydocAcceptor.statReady(elctrnNticSndngs.stream() + .map(row -> row.getElctrnNticSndngId()) + .collect(Collectors.toList())); + if(!EnsErrCd.OK.equals(responseVO.getErrCode())) + return responseVO; + + List resultInfo = elctrnNticSndngs.stream() + .map(row -> trafficCcMydocAcceptor.execute(row.getElctrnNticSndngId())) + .collect(Collectors.toList()); + + + List sendMastIds = resultInfo.stream() + .filter(ensResponseVO -> EnsErrCd.OK.equals(ensResponseVO.getErrCode())) + .map(ensResponseVO -> (Long)((Map)ensResponseVO.getResultInfo()).get("sendMastId")) + .collect(Collectors.toList()); + KkoMydocSendReserveEvent event = KkoMydocSendReserveEvent.builder() + .sendMastIds(sendMastIds) + .callback(() -> this.fetch(elctrnNticSndngs)) + .build(); + applicationEventPublisher.publishEvent(event); + + return EnsResponseVO.>okBuilder().resultInfo(resultInfo).build(); + } + + + + + + /** + * 인증톡 제작 재요청 + * @param elctrnNticSndngId + * @return + */ + public EnsResponseVO reMake(String elctrnNticSndngId){ + return trafficCcMydocMaker.execute(elctrnNticSndngId); + } + + + /** + * 인증톡 전송 재요청 + * @param elctrnNticSndngId + * @return + */ + public EnsResponseVO reSend(String elctrnNticSndngId){ + return trafficCcMydocSender.execute(elctrnNticSndngId); + } + + + /** + * 인증톡 전송(성공/실패) 결과 가져오기 + */ + public EnsResponseVO fetch(String elctrnNticSndngId){ + ElctrnNticSndng elctrnNticSndng = null; + try { + elctrnNticSndng = elctrnNticSndngRepository.findById(elctrnNticSndngId) + .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("[ elctrnNticSndngId %s ]와 일치하는 자료가 없습니다.", elctrnNticSndngId))); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + + return this.fetch(Arrays.asList(elctrnNticSndng)); + } + + /** + * 인증톡 전송(성공/실패) 결과 모두 가져오기 + */ + public EnsResponseVO fetchAll(){ + List elctrnNticSndngs = elctrnNticSndngRepository.findAllBySndngProcessSttusIn(Arrays.asList("02", "08")); + + return this.fetch(elctrnNticSndngs); + } + + private EnsResponseVO fetch(List elctrnNticSndngs){ + + return EnsResponseVO.okBuilder() + .resultInfo( + elctrnNticSndngs.stream() + .map(row -> trafficCcMydocFetcher.execute(row.getElctrnNticSndngId())) + .collect(Collectors.toList() + ) + ) + .build(); + } + + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/support/TrafficCcMydocAcceptor.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/support/TrafficCcMydocAcceptor.java new file mode 100644 index 0000000..ddea2f1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/support/TrafficCcMydocAcceptor.java @@ -0,0 +1,245 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.support; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndng; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndngDetail; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded.FieldUpdate; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngDetailRepository; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngRepository; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.Checks; +import cokr.xit.ens.core.utils.DateUtil; +import cokr.xit.ens.core.utils.MapDeserailizer; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.common.code.VenderCd; +import cokr.xit.ens.modules.kkomydoc.model.KkoMydocAcceptReqDTO; +import cokr.xit.ens.modules.kkomydoc.model.config.Document; +import cokr.xit.ens.modules.kkomydoc.model.config.Property; +import cokr.xit.ens.modules.kkomydoc.model.config.Receiver; +import cokr.xit.ens.modules.kkomydoc.model.config.XitProperty; +import cokr.xit.ens.modules.kkomydoc.service.KkoMydocService; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.utility.RandomString; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class TrafficCcMydocAcceptor implements EnsPhaseProcSupport { + + private final ElctrnNticSndngRepository elctrnNticSndngRepository; + private final ElctrnNticSndngDetailRepository elctrnNticSndngDetailRepository; + + private final KkoMydocService kkoMydocService; + + private Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).serializeNulls().create(); + + /** + * Accept 준비 + * + * @param elctrnNticSndngIds + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List elctrnNticSndngIds) { + try { + AtomicInteger index = new AtomicInteger(); + String prefixExternalDocumentUuid = String.format("B-%s%s", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")), RandomString.make(5)); + elctrnNticSndngIds.stream() + .map(elctrnNticSndngId -> elctrnNticSndngRepository.findById(elctrnNticSndngId).get()) + .map(elctrnNticSndng -> elctrnNticSndngDetailRepository.findAllDecByElctrnNticSndng(elctrnNticSndng)) + .forEach(list -> { + list.stream() + .forEach(row -> { + row.setExternalDocumentUuid(String.format("%s%09d", prefixExternalDocumentUuid, index.getAndIncrement() + 1)); + }); + elctrnNticSndngDetailRepository.saveAll(list); + + } + + ); + return EnsResponseVO.okBuilder().build(); + } catch (Exception e) { + return EnsResponseVO.errBuilder() + .errCode(EnsErrCd.ACPT500) + .errMsg(String.format("문서식별번호(외부) 생성에 실패 했습니다. %s", e.getMessage())) + .build(); + } + + } + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(String elctrnNticSndngId) { + log.info("no process"); + return null; + } + + + /** + * 인증톡 전자고지 접수 + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(String elctrnNticSndngId) { + Map resultInfo = new HashMap<>(); + resultInfo.put("elctrnNticSndngId", elctrnNticSndngId); + + EnsResponseVO responseVO = null; + ElctrnNticSndng elctrnNticSndng = null; + try { + elctrnNticSndng = elctrnNticSndngRepository.findById(elctrnNticSndngId) + .orElseThrow(() -> new EnsException(EnsErrCd.ACPT404, String.format("일치하는 TB_ELCTRN_NTIC_SNDNG 데이터가 없습니다. [ elctrnNticSndngId %s ]", elctrnNticSndngId))); + + KkoMydocAcceptReqDTO reqDTO = this.convertTbInputDataToAcceptReqDTO(elctrnNticSndngDetailRepository.findAllFetchByElctrnNticSndngId(elctrnNticSndng.getElctrnNticSndngId())); + + EnsResponseVO reqResp = kkoMydocService.accept(reqDTO); + + + if (EnsErrCd.OK.equals(reqResp.getErrCode())) { + resultInfo.put("sendMastId", (Long) ((Map) reqResp.getResultInfo()).get("sendMastId")); + responseVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } else { + responseVO = EnsResponseVO.errRsltBuilder() + .errCode(reqResp.getErrCode()) + .errMsg(reqResp.getErrMsg()) + .resultInfo(reqResp.getResultInfo()) + .build(); + } + } catch (EnsException e) { + responseVO = EnsResponseVO.errRsltBuilder() + .errCode(e.getErrCd()) + .errMsg(String.format("인증톡 \"접수\" 처리 실패. [%s] %s", e.getErrCd().getCode(), e.getMessage())) + .resultInfo(resultInfo) + .build(); + + } catch (Exception e) { + responseVO = EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ACPT500) + .errMsg(String.format("인증톡 \"접수\" 처리 실패. %s", e.getMessage())) + .resultInfo(resultInfo) + .build(); + + } finally { + if (EnsErrCd.OK.equals(responseVO.getErrCode())) { + elctrnNticSndng.setUpdate(FieldUpdate.builder() + .updusr("ENS_SYS") + .updtDt(LocalDateTime.now()) + .build()); + elctrnNticSndng.setSndngProcessSttus("02"); + elctrnNticSndng.setErrorCn(null); + } else { + elctrnNticSndng.setUpdate(FieldUpdate.builder() + .updusr("ENS_SYS") + .updtDt(LocalDateTime.now()) + .build()); + elctrnNticSndng.setSndngProcessSttus("99"); + elctrnNticSndng.setErrorCn(responseVO.getErrMsg()); + if (responseVO.getResultInfo() != null && (responseVO.getResultInfo() instanceof List || responseVO.getResultInfo() instanceof Map)) + elctrnNticSndng.setErrorDtls(gson.toJson(responseVO.getResultInfo())); + } + } + + return responseVO; + } + + + private KkoMydocAcceptReqDTO convertTbInputDataToAcceptReqDTO(List list) { + + return KkoMydocAcceptReqDTO.builder() + .vender(VenderCd.intech.getCode()) + .org_cd(list.get(0).getElctrnNticSndng().getSignguCode()) + .tmplt_cd(list.get(0).getElctrnNticSndng().getNhtTmplatManage().getNhtTmplatId()) + .post_bundle_title( + String.format("%s(%s건)-%s" + , list.get(0).getElctrnNticSndng().getNhtTmplatManage().getNhtNm() + , list.get(0).getElctrnNticSndng().getSndngCo() + , LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ) + ) + .send_dt(list.get(0).getElctrnNticSndng().getSndngDt()) + .close_dt(list.get(0).getElctrnNticSndng().getClosDt()) + .documents( + list.stream() + .map(row -> createDocument(row)) + .collect(Collectors.toList()) + ) + .build(); + } + + private Document createDocument(ElctrnNticSndngDetail data) throws EnsException { + + return Document.builder() + .external_document_uuid(data.getExternalDocumentUuid()) + .hash(null) + .common_categories(Arrays.asList("NOTICE")) + .read_expired_at(DateUtil.dateToAbsTimeSec(data.getElctrnNticSndng().getClosDt())) +// .read_expired_sec() + .receiver(this.createReceiver(data)) + .property(this.createProperty(data)) + .bridge(null) + .xit_property(this.createXitProperty(data)) + .build(); + } + + private Receiver createReceiver(ElctrnNticSndngDetail data) { + return Receiver.builder() + .ci(null) + .phone_number(null) + .name(null) + .birthday(null) + .is_required_verify_name(null) + .build(); + } + + private Property createProperty(ElctrnNticSndngDetail data) { + return Property.builder() + .link(data.getElctrnNticSndng().getNhtTmplatManage().getRedirectUrl()) + .payload(null) +// .external_document_uuid(data.getExternalDocumentUuid()) + .build(); + } + + private XitProperty createXitProperty(ElctrnNticSndngDetail data) { + Map>> mobilePage = new HashMap<>(); + mobilePage.put("details", this.createDetails(data)); + + String jid = elctrnNticSndngDetailRepository.findIhidnumDecByElctrnNticSndngDetailId(data.getElctrnNticSndngDetailId()); + return XitProperty.builder() + .mbl_page_data(mobilePage) +// .ci_trans_use_yn("Y") +// .jid(data.getIhidnum()) + .jid(Checks.isCheckJid(jid) ? jid : "1111111111111") + .tmplt_msg_data(null) + .build(); + } + + private List> createDetails(ElctrnNticSndngDetail data) { + try { + Map>> m = gson.fromJson(data.getMobilePageCn(), Map.class); + return m.get("details"); + } catch (Exception e) { + log.error("\"mobilePageCn\" Json Parse 실패. {}", data.getMobilePageCn()); + return null; + } + } + + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/support/TrafficCcMydocFetcher.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/support/TrafficCcMydocFetcher.java new file mode 100644 index 0000000..e84db66 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/support/TrafficCcMydocFetcher.java @@ -0,0 +1,213 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.support; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndng; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndngDetail; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndngResult; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded.FieldCreate; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded.FieldUpdate; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngDetailRepository; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngRepository; +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngResultRepository; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.kkomydoc.model.KkoMydocRsltRespDTO; +import cokr.xit.ens.modules.kkomydoc.model.config.KkoMydocStat; +import cokr.xit.ens.modules.kkomydoc.service.KkoMydocService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class TrafficCcMydocFetcher implements EnsPhaseProcSupport { + + private final ElctrnNticSndngRepository elctrnNticSndngRepository; + private final ElctrnNticSndngDetailRepository elctrnNticSndngDetailRepository; + + private final ElctrnNticSndngResultRepository elctrnNticSndngResultRepository; + + private final KkoMydocService kkoMydocService; + + + /** + * Fetch 준비 + * + * @param elctrnNticSndngIds + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List elctrnNticSndngIds) { + log.info("no process"); + return null; + } + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(String elctrnNticSndngId) { + log.info("no process"); + return null; + } + + + /** + * 인증톡 발송(성공/실패) 자료에 대한 결과 가져오기 + * + * @param elctrnNticSndngId + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(String elctrnNticSndngId) { + EnsResponseVO responseVO = null; + Map resultInfo = new HashMap<>(); + resultInfo.put("elctrnNticSndngId", elctrnNticSndngId); + + KkoMydocRsltRespDTO respDTO = null; + try { + Long sendMastId = elctrnNticSndngDetailRepository.findLastSendMastIdByElctrnNticSndngId(elctrnNticSndngId) + .orElseThrow(() -> new EnsException(EnsErrCd.RSLT404, "일치하는 ENS 접수자료가 없습니다.")); + resultInfo.put("sendMastId", sendMastId); + + + EnsResponseVO apiRespVO = kkoMydocService.sendResultProvide(sendMastId); + respDTO = (KkoMydocRsltRespDTO) apiRespVO.getResultInfo(); + + +// elctrnNticSndngResultRepository.saveAll(respDTO.getDocuments().stream() +// .map(row -> { +// return ElctrnNticSndngResult.builder() +// .elctrnNticSndngDetailId(elctrnNticSndngDetailRepository.findByExternalDocumentUuid(row.getExternalDocumentUuid()) +// .orElse(new ElctrnNticSndngDetail()) +// .getElctrnNticSndngDetailId()) +// .sndngResultCode(this.sndngResultCode(row)) +// .requstDt(row.getKkoDocSentDt()) +// .inqireDt(row.getKkoDocReceivedDt()) +// .readngDt(row.getKkoDocReadFrstDt()) +// .errorCn(CmmnUtil.isEmpty(row.getErrorMessage()) ? null : row.getErrorMessage()) +// .create(FieldCreate.builder() +// .REGISTER("ENS_SYS") +// .REGIST_DT(LocalDateTime.now()) +// .build()) +// .build(); +// }) +// .collect(Collectors.toList()) +// ); + List elctrnNticSndngResults = respDTO.getDocuments().stream() + .map(row -> { + return ElctrnNticSndngResult.builder() + .elctrnNticSndngDetailId(elctrnNticSndngDetailRepository.findByExternalDocumentUuid(row.getExternalDocumentUuid()) + .orElse(new ElctrnNticSndngDetail()) + .getElctrnNticSndngDetailId()) + .sndngResultCode(this.sndngResultCode(row)) + .requstDt(row.getKkoDocSentDt()) + .inqireDt(row.getKkoDocReceivedDt()) + .readngDt(row.getKkoDocReadFrstDt()) + .errorCn(CmmnUtil.isEmpty(row.getErrorMessage()) ? null : row.getErrorMessage()) + .create(FieldCreate.builder() + .register("ENS_SYS") + .registDt(LocalDateTime.now()) + .build()) + .build(); + }) + .collect(Collectors.toList()); + if (elctrnNticSndngResultRepository.findById(elctrnNticSndngResults.get(0).getElctrnNticSndngDetailId()).isPresent()) + elctrnNticSndngResultRepository.modifyByElctrnNticSndngResults(elctrnNticSndngResults); + else + elctrnNticSndngResultRepository.saveAll(elctrnNticSndngResults); + + responseVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } catch (EnsException e) { + responseVO = EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } catch (Exception e) { + responseVO = EnsResponseVO.errBuilder() + .errCode(EnsErrCd.RSLT999) + .errMsg(String.format("[elctrnNticSndngId %s]에 대한 전송결과 FETCH 처리 실패. %s", elctrnNticSndngId, e.getMessage())) + .build(); + } finally { + ElctrnNticSndng elctrnNticSndng = elctrnNticSndngRepository.findById(elctrnNticSndngId).orElseThrow(() -> new EnsException(EnsErrCd.RSLT404, "일치하는 tbInputXit 자료가 없습니다.")); + if (EnsErrCd.OK.equals(responseVO.getErrCode())) { + elctrnNticSndng.setUpdate(FieldUpdate.builder() + .updusr("ENS_SYS") + .updtDt(LocalDateTime.now()) + .build()); + elctrnNticSndng.setSndngProcessSttus(this.sndngProcessSttus(respDTO, elctrnNticSndng.getSndngProcessSttus())); + elctrnNticSndng.setErrorCn(null); + } else { + elctrnNticSndng.setUpdate(FieldUpdate.builder() + .updusr("ENS_SYS") + .updtDt(LocalDateTime.now()) + .build()); + elctrnNticSndng.setSndngProcessSttus("99"); + elctrnNticSndng.setErrorCn(responseVO.getErrMsg()); + } + } + + return responseVO; + } + + private String sndngProcessSttus(KkoMydocRsltRespDTO respDTO, String sndngProcessSttus) { + + switch (respDTO.getStatCd()) { + case makefail: + case sendfail: + return "99"; + case sendok: + case sendcmplt: + return "02"; + case open: + return "08"; + case close: + return "09"; + default: + return sndngProcessSttus; + } + } + + private String sndngResultCode(KkoMydocStat row) { + + + String sndngResultCode = null; + try { + switch (row.getKkoDocStat()) { + case SENT: + case RECEIVED: + case EXPIRED: + sndngResultCode = "1"; + break; + case READ: + sndngResultCode = "2"; + break; + case UNIDENTIFIED_USER: + case FORBIDDEN: + case INVALID_VALUE: + case INTERNAL_ERROR: + case INVALID_REQUEST: + case INTERNAL_SENT_ERR: + sndngResultCode = "3"; + break; + default: + break; + } + } catch (Exception e) { + log.info("IupSendSttusCd와 일치하는 값 없음. [ dataId {} KkoDocStat {} ]", row.getExternalDocumentUuid(), row.getKkoDocStat()); + } + return sndngResultCode; + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/support/TrafficCcMydocMaker.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/support/TrafficCcMydocMaker.java new file mode 100644 index 0000000..059c13e --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/support/TrafficCcMydocMaker.java @@ -0,0 +1,65 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.support; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngDetailRepository; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.kkomydoc.service.KkoMydocService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Slf4j +@Component +@RequiredArgsConstructor +public class TrafficCcMydocMaker implements EnsPhaseProcSupport { + + private final ElctrnNticSndngDetailRepository elctrnNticSndngDetailRepository; + + private final KkoMydocService kkoMydocService; + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List elctrnNticSndngIds) { + log.info("no process"); + return null; + } + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(String elctrnNticSndngId) { + log.info("no process"); + return null; + } + + + + /** + * 인증톡 전자고지 제작 + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(String elctrnNticSndngId){ + EnsResponseVO responseVO = null; + try { + Long sendMastId = elctrnNticSndngDetailRepository.findLastSendMastIdByElctrnNticSndngId(elctrnNticSndngId) + .orElseThrow(() -> new EnsException(EnsErrCd.MAKE404, "일치하는 ENS 접수자료가 없습니다.")); + + responseVO = kkoMydocService.remake(sendMastId); + } catch (EnsException e){ + responseVO = EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + return responseVO; + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/support/TrafficCcMydocSender.java b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/support/TrafficCcMydocSender.java new file mode 100644 index 0000000..ce2f9d5 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/traffic/chuncheon/mydoc/v2/service/support/TrafficCcMydocSender.java @@ -0,0 +1,65 @@ +package cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.support; + +import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngDetailRepository; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.kkomydoc.service.KkoMydocService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Slf4j +@Component +@RequiredArgsConstructor +public class TrafficCcMydocSender implements EnsPhaseProcSupport { + + private final ElctrnNticSndngDetailRepository elctrnNticSndngDetailRepository; + + private final KkoMydocService kkoMydocService; + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List elctrnNticSndngIds) { + log.info("no process"); + return null; + } + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(String elctrnNticSndngId) { + log.info("no process"); + return null; + } + + + + /** + * 인증톡 전자고지 전송요청 + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(String elctrnNticSndngId){ + EnsResponseVO responseVO = null; + try { + Long sendMastId = elctrnNticSndngDetailRepository.findLastSendMastIdByElctrnNticSndngId(elctrnNticSndngId) + .orElseThrow(() -> new EnsException(EnsErrCd.SEND404, "일치하는 ENS 접수자료가 없습니다.")); + + responseVO = kkoMydocService.sendBulk(sendMastId); + } catch (EnsException e){ + responseVO = EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + return responseVO; + } + +} diff --git a/src/main/java/cokr/xit/ens/core/aop/AccessErrorMessage.java b/src/main/java/cokr/xit/ens/core/aop/AccessErrorMessage.java new file mode 100644 index 0000000..051984c --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/aop/AccessErrorMessage.java @@ -0,0 +1,46 @@ +package cokr.xit.ens.core.aop; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.monitor.Message; +import lombok.Builder; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@Builder +public class AccessErrorMessage implements Message { + + private final String ACTIVE_PROFILE; + private final AccessLog accessLog; + private final String serverUrl; + + public String create() { + StringBuilder sb = new StringBuilder(); + sb.append("###############################################################") + .append(System.getProperty("line.separator")) + .append(String.format("####### ENS unknown error info... [ -Dspring.profiles.active=%s ] #######", CmmnUtil.isEmpty(System.getProperty("spring.profiles.active")) ? ACTIVE_PROFILE : System.getProperty("spring.profiles.active"))) + .append(System.getProperty("line.separator")) + .append("###############################################################") + .append(System.getProperty("line.separator")) + .append("[Server URL]: " + serverUrl) + .append(System.getProperty("line.separator")) + .append("[Occurrence time]: ") + .append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))) + .append(System.getProperty("line.separator")) + .append("[Client Ip]: " + accessLog.getIp()) + .append(System.getProperty("line.separator")) + .append("[Request Url]: " + accessLog.getHttpMethod() + " " + accessLog.getUrl()) + .append(System.getProperty("line.separator")) + .append("[Request Param]: " + accessLog.getParam()) + .append(System.getProperty("line.separator")) +// .append("[Details]: ") +// .append(accessLog.getErrorMsg()) + .append(System.getProperty("line.separator")) + .append(System.getProperty("line.separator")) + .append("[StackTrace]:") + .append(System.getProperty("line.separator")) + .append(accessLog.getErrorMsg()); + + return sb.toString(); + } +} diff --git a/src/main/java/cokr/xit/ens/core/aop/AccessLog.java b/src/main/java/cokr/xit/ens/core/aop/AccessLog.java new file mode 100644 index 0000000..e6a34c3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/aop/AccessLog.java @@ -0,0 +1,84 @@ +package cokr.xit.ens.core.aop; + +import cokr.xit.ens.core.aop.code.AccessStatusCd; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +@Getter +@RequiredArgsConstructor +@Table(name = "ens_access_log", schema = "", catalog = "") +public class AccessLog { + + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long logId; + + @Column(length = 2000) + private String accessToken; + + private String reqSystemId; + + private String sessionId; + + private String ip; + + private String httpMethod; + + private String url; + + private String uri; + + @Lob + private String param; + @Lob + private String response; + + @Enumerated(EnumType.STRING) + private AccessStatusCd status; + + @Lob + private String errorMsg; + + @CreationTimestamp + private LocalDateTime startDt; + + @UpdateTimestamp + private LocalDateTime endDt; + + + + @Builder(builderClassName = "reqBuilder", builderMethodName = "reqBuilder") + public AccessLog(String accessToken, String sessionId, String ip, String httpMethod, String url, String uri, String param) { + this.accessToken = accessToken; + this.sessionId = sessionId; + this.ip = ip; + this.httpMethod = httpMethod; + this.url = url; + this.uri = uri; + this.param = param; + this.status = AccessStatusCd.req; + } + + public void setResponseCompleted(String response) { + this.status = AccessStatusCd.cmplt; + this.response = response; + } + public void setResponseFail(String errorMsg) { + this.status = AccessStatusCd.fail; + this.errorMsg = errorMsg; + } + public void setResponseNoAuth(String errorMsg) { + this.status = AccessStatusCd.noAuth; + this.errorMsg = errorMsg; + } + +} diff --git a/src/main/java/cokr/xit/ens/core/aop/AccessLogAspect.java b/src/main/java/cokr/xit/ens/core/aop/AccessLogAspect.java new file mode 100644 index 0000000..9c6efdf --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/aop/AccessLogAspect.java @@ -0,0 +1,372 @@ +package cokr.xit.ens.core.aop; + +import cokr.xit.ens.core.aop.repository.AccessLogRepository; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.monitor.slack.event.MonitorEvent; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.utils.JwtUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * @author (주)엑스아이티 개발팀 + * @version 1.0 Copyright(c) XIT All rights reserved. + * @업무그룹명: 접근 로그 관리 + * @설명: 시스템 접근 로그를 관리 한다. + * @최초작성일: 2021. 11. 4. 오후 4:32:05 + * @최초작성자: 박민규 + * @since 2002. 2. 2. + */ +@Slf4j +@Component +@Aspect +@RequiredArgsConstructor +//@Profile("!prod-iup") +public class AccessLogAspect { + + + @Value("${spring.profiles.active}") + private String ACTIVE_PROFILE; + private final AccessLogRepository accessLogRepository; + + private final String ACCESS_TOKEN_NAME = "Authorization"; + private final ApplicationEventPublisher applicationEventPublisher; + + @Value("${app.access.auth.exclude.uri}") + private List EXCLUDE_URIS; + + @Pointcut("execution(* cokr.xit..presentation.*Controller.*(..))") + public void presentationLayer() { + } + + @Pointcut("execution(* cokr.xit..service.*Impl.*(..))") + public void serviceLayer() { + } + + @Pointcut("execution(* cokr.xit..domain.*Repository.*(..))") + public void persistenceLayer() { + } + + + /** + *
메소드 설명: 요청 및 응답에 대한 로그를 생성 한다.
+ * + * @param proceedingJoinPoint + * @return + * @throws Throwable Object 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 30. + */ + @Around("presentationLayer()") + public Object addLogOfRequestAndResponse(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { + + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + long start = System.currentTimeMillis(); + + Object result = null; + AccessLog accessLog = null; + try { + + log.info("[BEFORE] : ..."); + accessLog = this.setRequestInfo(request); + accessLogRepository.save(accessLog); + + + + if (this.isCertified(request)) { + + result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs()); + + + log.info("[AFTER] : ..."); + this.setResponseInfo(accessLog, result); + accessLogRepository.save(accessLog); + + } else { + + String msg = String.format("권한이 없습니다. 엑세스토큰(%s)를 확인하시기 바랍니다.", ACCESS_TOKEN_NAME); + EnsResponseVO restResponseVO = EnsResponseVO.errBuilder() + .errCode(EnsErrCd.ERR901) + .errMsg(msg) + .build(); + result = new ResponseEntity(restResponseVO, HttpStatus.UNAUTHORIZED); + + + log.error(String.format("[NoAuth] : %s => %s", ACCESS_TOKEN_NAME, request.getHeader(ACCESS_TOKEN_NAME))); + accessLog.setResponseNoAuth(msg); + accessLogRepository.save(accessLog); + + } + + } catch (EnsException e) { + + log.error(String.format("[ERROR] : %s", e.getMessage())); + accessLog.setResponseFail(String.format("%s: %s", e.getErrCd(), e.getMessage())); + accessLogRepository.save(accessLog); + if (result == null) { + EnsResponseVO restResponseVO = EnsResponseVO + .errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + result = new ResponseEntity(restResponseVO, HttpStatus.INTERNAL_SERVER_ERROR); + } + } catch (Exception e) { + + log.error(String.format("[%s ERROR] : %s", EnsErrCd.UNKNOWN, e.getMessage()), e); + accessLog.setResponseFail(String.format("%s: %s", EnsErrCd.UNKNOWN, CmmnUtil.printStackTraceToString(e))); + accessLogRepository.save(accessLog); + if (result == null) { + EnsResponseVO restResponseVO = EnsResponseVO + .errBuilder() + .errCode(EnsErrCd.UNKNOWN) + .errMsg("알수없는 오류 입니다. 시스템관리자에게 문의하시기 바랍니다.") + .build(); + result = new ResponseEntity(restResponseVO, HttpStatus.INTERNAL_SERVER_ERROR); + + + applicationEventPublisher.publishEvent(MonitorEvent.builder() + .message(AccessErrorMessage.builder().ACTIVE_PROFILE(ACTIVE_PROFILE).accessLog(accessLog).serverUrl(CmmnUtil.getServerUrl()).build()) + .build()); + } + + } finally { + long end = System.currentTimeMillis(); + log.info("Request: {} {}: {}. request Ajax: {} ({}ms)", request.getMethod(), request.getRequestURL(), paramMapToString(request.getParameterMap()), isAjax(request), end - start); + + } + + return result; + } + + + /** + *
메소드 설명: 요청정보 설정
+ * + * @param request + * @return + * @throws JsonProcessingException AccessLog 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 30. + */ + @SuppressWarnings("deprecation") + private AccessLog setRequestInfo(HttpServletRequest request) throws JsonProcessingException { + String sessionId = request.getSession().getId(); + String param = null; + try { + param = this.requestBodyToString(request); + if (StringUtils.isEmpty(param)) + param = this.paramMapToJsonString(request.getParameterMap()); + } catch (Exception e) { + param = String.format("[요청 parameter 변환 실패]: %s", e.getMessage()); + } + + return AccessLog.reqBuilder() + .accessToken(request.getHeader(ACCESS_TOKEN_NAME)) + .sessionId(sessionId) + .ip(this.getClientIpAddr(request)) + .httpMethod(request.getMethod()) + .url(request.getRequestURL().toString()) + .uri(request.getRequestURI()) + .param(param) + .build(); + } + + /** + *
메소드 설명: 응답정보 설정
+ * + * @param accessLog + * @param result + * @author: 박민규 + * @date: 2021. 11. 30. + */ + private void setResponseInfo(AccessLog accessLog, Object result) { + String response = null; + if (result instanceof String) + response = (String) result; + else if (result instanceof List) + response = result.toString(); + else if (result instanceof Map) + response = result.toString(); + else + response = String.valueOf(result); + + accessLog.setResponseCompleted(response); + } + + + /** + *
메소드 설명: Request ParameterMap에 담긴 parameter를 String으로 반환 한다.
+ * + * @param paramMap + * @return String 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 30. + */ + private String paramMapToString(Map paramMap) { + return paramMap.entrySet() + .stream() + .map(entry -> String.format("%s : %s", + entry.getKey(), Arrays.toString(entry.getValue()))) + .collect(Collectors.joining(", ")); + } + + /** + *
메소드 설명: Request ParameterMap에 담긴 parameter를 Json String으로 반환 한다.
+ * + * @param paramMap + * @return + * @throws JsonProcessingException String 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 30. + */ + private String paramMapToJsonString(Map paramMap) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(paramMap); + } + + + /** + *
메소드 설명: Request Body로 전송된 parameter를 String으로 반환 한다.
+ * + * @param request + * @return String 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 30. + */ + private String requestBodyToString(HttpServletRequest request) { + StringBuffer body = new StringBuffer(); + String line = null; + try { + BufferedReader reader = request.getReader(); + while ((line = reader.readLine()) != null) { + body.append(line); + } + } catch (Exception e) { + log.info("Error reading JSON string: " + e.toString()); + } + return body.toString(); + } + + + /** + *
메소드 설명: 클라이언트의 IP정보를 가져온다.
+     * 	-L4스위치나 프록시 서버 등이 개입되면서 request.getRemoteAdder()의 내용이 변조되기 시작한다.
+     * 	-대신 추가적인 header가 생기면서(X-Forwarded-For, WL-Proxy-Client-IP 등) 원래의 정보는 그곳에 저장 된다.
+     * 	-아래 메서드는 그 헤더를 추출하여 클라이언트의 아이피를 정확하게 얻고자 하는 방법 이다.
+     * 	출처: https://nine01223.tistory.com/302 [스프링연구소(spring-lab)]
+     * 
+ * + * @param request + * @return String 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2020. 9. 16. + */ + private String getClientIpAddr(HttpServletRequest request) { + String ip = request.getHeader("X-Forwarded-For"); + + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + + return ip; + } + + private boolean isAjax(HttpServletRequest request) { + if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) + return true; + + return false; + + } + + /** + *
메소드 설명: 승인키로 계약된 서비스 조회하여 요청 uri와 일치하면 true 아니면 false를 반환 한다.
+ * + * + * @return boolean 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 30. + */ + protected boolean isCertified(HttpServletRequest request) { + + for (String url : EXCLUDE_URIS) { + Pattern pattern = Pattern.compile(url); + Matcher matcher = pattern.matcher(request.getRequestURI()); + if (matcher.matches()) + return true; + } + + + String accessToken = request.getHeader(ACCESS_TOKEN_NAME); + + JwtUtil jwtUtil = JwtUtil.verifyBuilder() + .secretKey(JwtUtil.DEFAULT_SECRET_KEY) + .jwt(accessToken) + .build(); + + + boolean isCertified = jwtUtil.isCertified(); + if (!isCertified) + return false; + + + boolean hasRole = false; + for (String role : jwtUtil.getClaims().get("roles").asArray(String.class)) { + Pattern pattern = Pattern.compile(role); + Matcher matcher = pattern.matcher(request.getRequestURI()); + if (matcher.matches()) { + hasRole = true; + break; + } + } + if (!hasRole) + return false; + + + String ip = this.getClientIpAddr(request); + String clientHost = jwtUtil.getClaims().get("aud").asString(); + if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip) || ip.equals(clientHost) || request.getRemoteHost().equals(clientHost)) + return true; + + return false; + } + + +} diff --git a/src/main/java/cokr/xit/ens/core/aop/EnsResponseVO.java b/src/main/java/cokr/xit/ens/core/aop/EnsResponseVO.java new file mode 100644 index 0000000..069c38e --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/aop/EnsResponseVO.java @@ -0,0 +1,56 @@ +package cokr.xit.ens.core.aop; + +import cokr.xit.ens.core.exception.code.EnsErrCd; +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@Schema(name = "EnsResponseVO") +@NoArgsConstructor +public class EnsResponseVO { + + @Schema(required = true, title = "에러 코드", example = " ") + @JsonProperty("errCode") + @JsonAlias({"err_code"}) + @SerializedName(value = "errCode", alternate = {"err_code"}) + private EnsErrCd errCode = null; + + @Schema(required = true, title = "에러 메시지", example = " ") + @JsonProperty("errMsg") + @JsonAlias({"err_msg"}) + @SerializedName(value = "errMsg", alternate = {"err_msg"}) + private String errMsg = null; + + @Schema(required = false, title = "결과 데이터", example = " ") + @JsonProperty("resultInfo") + @JsonAlias({"result_info"}) + @SerializedName(value = "resultInfo", alternate = {"result_info"}) + private T resultInfo; + + @Builder(builderClassName = "okBuilder" ,builderMethodName = "okBuilder") + EnsResponseVO(T resultInfo) { + this.errCode = EnsErrCd.OK; + this.errMsg = EnsErrCd.OK.getCodeNm(); + this.resultInfo = resultInfo; + } + + @Builder(builderClassName = "errBuilder" ,builderMethodName = "errBuilder") + EnsResponseVO(EnsErrCd errCode, String errMsg) { + this.errCode = errCode; + this.errMsg = errMsg; + } + + @Builder(builderClassName = "errRsltBuilder" ,builderMethodName = "errRsltBuilder") + EnsResponseVO(EnsErrCd errCode, String errMsg, T resultInfo) { + this.errCode = errCode; + this.errMsg = errMsg; + this.resultInfo = resultInfo; + } +} diff --git a/src/main/java/cokr/xit/ens/core/aop/code/AccessStatusCd.java b/src/main/java/cokr/xit/ens/core/aop/code/AccessStatusCd.java new file mode 100644 index 0000000..fe07366 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/aop/code/AccessStatusCd.java @@ -0,0 +1,24 @@ +package cokr.xit.ens.core.aop.code; + +import cokr.xit.ens.core.code.CodeMapperType; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum AccessStatusCd implements CodeMapperType { + + noAuth("권한없음") + ,req("요청완료") + ,cmplt("처리완료") + ,fail("처리실패") + ; + + @Getter + private final String codeNm; + + @Override + public String getCode() { + return this.name(); + } + +} diff --git a/src/main/java/cokr/xit/ens/core/aop/repository/AccessLogRepository.java b/src/main/java/cokr/xit/ens/core/aop/repository/AccessLogRepository.java new file mode 100644 index 0000000..ebc1e90 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/aop/repository/AccessLogRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.core.aop.repository; + +import cokr.xit.ens.core.aop.AccessLog; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface AccessLogRepository extends JpaRepository{ + +} diff --git a/src/main/java/cokr/xit/ens/core/code/CodeMapperFactory.java b/src/main/java/cokr/xit/ens/core/code/CodeMapperFactory.java new file mode 100644 index 0000000..04ea0ce --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/code/CodeMapperFactory.java @@ -0,0 +1,72 @@ +package cokr.xit.ens.core.code; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class CodeMapperFactory { + + private Map> factory; + + /** + *
메소드 설명: CodeMapperType을 구현한 Enum을 Factory에 추가하는 함수
+ * @param e void 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 10. 28. + */ + public void put(Class e) { + this.put(e.getSimpleName(), e); + } + /** + *
메소드 설명: CodeMapperType을 구현한 Enum을 Factory에 추가하는 함수
+ * @param key + * @param e void 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 10. 28. + */ + public void put(String key, Class e) { + factory.put(key, this.toEnumValue(e)); + } + + /** + *
메소드 설명: Factory에 추가된 Enum을 조회하는 함수
+ * @param e + * @return List 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 10. 28. + */ + public List get(Class e){ + return this.get(e.getSimpleName()); + } + /** + *
메소드 설명: Factory에 추가된 Enum을 조회하는 함수
+ * @param key + * @return List 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 10. 28. + */ + public List get(String key){ + return factory.get(key); + } + + + /** + *
메소드 설명: Enum의 내용들을 List로 변환하는 함수
+ * @param e + * @return List 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 10. 28. + */ + private List toEnumValue(Class e){ + return Arrays.stream(e.getEnumConstants()) + .map(CodeMapperValue::new) + .collect(Collectors.toList()); + } + +} diff --git a/src/main/java/cokr/xit/ens/core/code/CodeMapperType.java b/src/main/java/cokr/xit/ens/core/code/CodeMapperType.java new file mode 100644 index 0000000..760ffa0 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/code/CodeMapperType.java @@ -0,0 +1,20 @@ +package cokr.xit.ens.core.code; + +public interface CodeMapperType { + /** + *
메소드 설명: 해당 Enum의 코드를 조회하는 함수
+ * @return String 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 10. 28. + */ + String getCode(); + + /** + *
메소드 설명: 해당 Enum의 코드명을 조회하는 함수
+ * @return String 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 10. 28. + */ + String getCodeNm(); + +} diff --git a/src/main/java/cokr/xit/ens/core/code/CodeMapperValue.java b/src/main/java/cokr/xit/ens/core/code/CodeMapperValue.java new file mode 100644 index 0000000..f9f546b --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/code/CodeMapperValue.java @@ -0,0 +1,15 @@ +package cokr.xit.ens.core.code; + +import lombok.Getter; + +@Getter +public class CodeMapperValue { + private String code; + private String codeNm; + + public CodeMapperValue(CodeMapperType codeMapperType) { + this.code = codeMapperType.getCode(); + this.codeNm = codeMapperType.getCodeNm(); + } + +} diff --git a/src/main/java/cokr/xit/ens/core/code/support/SampleCd.java b/src/main/java/cokr/xit/ens/core/code/support/SampleCd.java new file mode 100644 index 0000000..014819d --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/code/support/SampleCd.java @@ -0,0 +1,22 @@ +package cokr.xit.ens.core.code.support; + +import cokr.xit.ens.core.code.CodeMapperType; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum SampleCd implements CodeMapperType { + + CODE1("코드1") + ,CODE2("코드2"); + + + @Getter + private final String codeNm; + + @Override + public String getCode() { + return this.name(); + } + +} diff --git a/src/main/java/cokr/xit/ens/core/code/support/SampleCdUse.java b/src/main/java/cokr/xit/ens/core/code/support/SampleCdUse.java new file mode 100644 index 0000000..bc65d8c --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/code/support/SampleCdUse.java @@ -0,0 +1,21 @@ +package cokr.xit.ens.core.code.support; + +import cokr.xit.ens.core.code.CodeMapperFactory; +import cokr.xit.ens.core.code.CodeMapperValue; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Slf4j +@Component +@RequiredArgsConstructor +public class SampleCdUse { + private final CodeMapperFactory codeMapperFactory; + + public void printSampleCds(){ + List sampleCdList = codeMapperFactory.get("SampleCd"); + sampleCdList.stream().forEach(row -> log.info("{} {}", row.getCode(), row.getCodeNm())); + } +} diff --git a/src/main/java/cokr/xit/ens/core/config/AsyncSupportConfig.java b/src/main/java/cokr/xit/ens/core/config/AsyncSupportConfig.java new file mode 100644 index 0000000..137326f --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/AsyncSupportConfig.java @@ -0,0 +1,25 @@ +package cokr.xit.ens.core.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurerSupport; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; + +@Configuration +@EnableAsync +public class AsyncSupportConfig extends AsyncConfigurerSupport { + + @Override + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(5); + executor.setMaxPoolSize(30); + executor.setQueueCapacity(50); + executor.setThreadNamePrefix("ENS-ASYNC-"); + executor.initialize(); + return executor; + } + +} diff --git a/src/main/java/cokr/xit/ens/core/config/CodeMapperConfig.java b/src/main/java/cokr/xit/ens/core/config/CodeMapperConfig.java new file mode 100644 index 0000000..7675848 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/CodeMapperConfig.java @@ -0,0 +1,23 @@ +package cokr.xit.ens.core.config; + +import cokr.xit.ens.core.code.CodeMapperFactory; +import cokr.xit.ens.core.code.support.SampleCd; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.LinkedHashMap; + +@Configuration +public class CodeMapperConfig { + + @Bean + public CodeMapperFactory codeMapperFactory() { + CodeMapperFactory codeMapperFactory = new CodeMapperFactory(new LinkedHashMap<>()); + + codeMapperFactory.put(SampleCd.class); + codeMapperFactory.put(EnsErrCd.class); + + return codeMapperFactory; + } +} diff --git a/src/main/java/cokr/xit/ens/core/config/JpaConfig.java b/src/main/java/cokr/xit/ens/core/config/JpaConfig.java new file mode 100644 index 0000000..d2d2cc6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/JpaConfig.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.core.config; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +@Configuration +@EnableJpaRepositories(basePackages = "cokr.xit.ens") +public class JpaConfig { +} diff --git a/src/main/java/cokr/xit/ens/core/config/QuerydslConfig.java b/src/main/java/cokr/xit/ens/core/config/QuerydslConfig.java new file mode 100644 index 0000000..2410576 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/QuerydslConfig.java @@ -0,0 +1,33 @@ +package cokr.xit.ens.core.config; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.querydsl.jpa.impl.JPAQueryFactory; + +/** + * + *
    + *
  • 업무 그룹명: JpaQueryFactory Bean 등록
  • + *
  • 설 명: 프로젝트 어느 곳에서나 JPAQueryFactory 를 주입 받아 Querydsl을 사용 할 수 있게 함.
  • + *
  • 참조사이트: https://jojoldu.tistory.com/372
  • + *
  • 작성일: 2021. 10. 18. 오후 4:25:17 + *
+ * + * @author 박민규 + * + */ +@Configuration +public class QuerydslConfig { + + @PersistenceContext + private EntityManager entityManager; + + @Bean + public JPAQueryFactory jpaQueryFactory() { + return new JPAQueryFactory(entityManager); + } +} diff --git a/src/main/java/cokr/xit/ens/core/config/SecurityConfig.java b/src/main/java/cokr/xit/ens/core/config/SecurityConfig.java new file mode 100644 index 0000000..4f1c08a --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/SecurityConfig.java @@ -0,0 +1,14 @@ +package cokr.xit.ens.core.config; + +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@EnableWebSecurity +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable(); + } +} diff --git a/src/main/java/cokr/xit/ens/core/config/SpringDocConfig.java b/src/main/java/cokr/xit/ens/core/config/SpringDocConfig.java new file mode 100644 index 0000000..7fe381f --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/SpringDocConfig.java @@ -0,0 +1,208 @@ +package cokr.xit.ens.core.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.servers.Server; +import org.springdoc.core.GroupedOpenApi; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import java.util.Arrays; +import java.util.List; + +@Configuration +public class SpringDocConfig { + + @Bean + public OpenAPI openAPI(@Value("${xit.swagger.conf.api.url}") String url + , @Value("${xit.swagger.conf.api.version}") String appVersion + , @Value("${spring.profiles.active}") String active) { + Info info = new Info().title("ENS API-Active Profile: " + active) + .version(appVersion) + .description("전자고지 Web Application API 입니다.") + .termsOfService("http://swagger.io/terms/") + .contact(new Contact().name("xit").url("https://www.xit.co.kr/").email("xit@xit.co.kr")) + .license(new License().name("Apache License Version 2.0").url("http://www.apache.org/licenses/LICENSE-2.0")); + + /*TODO : 등록시 url 뒤에 url에 ... (curl 실행시)*/ + List servers = Arrays.asList(new Server().url(url).description("ENS (" + active + ")")); + + /* 인증-user / password 방식 */ +// SecurityScheme securityScheme = new SecurityScheme() +// .type(SecurityScheme.Type.HTTP).scheme("basic") +// .in(SecurityScheme.In.HEADER).name("Authorization"); +// SecurityRequirement schemaRequirement = new SecurityRequirement().addList("basicAuth"); + + /* 인증-Token 방식 */ +// SecurityScheme securityScheme = new SecurityScheme() +// .type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT") +// .in(SecurityScheme.In.HEADER).name("Authorization"); +// SecurityRequirement schemaRequirement = new SecurityRequirement().addList("bearerAuth"); + + return new OpenAPI() +// .components(new Components().addSecuritySchemes("basicAuth", securityScheme)) +// .components(new Components().addSecuritySchemes("bearerAuth", securityScheme)) +// .addSecurityItem(schemaRequirement) +// .security(Collections.singletonList(schemaRequirement)) + .info(info) + .servers(servers); + } + + + @Bean + public GroupedOpenApi systemMng() { + return GroupedOpenApi.builder() + .group("SYS. 시스템관리") + .pathsToMatch("/sys/mng/**") + .build(); + } + + @Bean + public GroupedOpenApi systemUtil() { + return GroupedOpenApi.builder() + .group("SYS. 시스템도구") + .pathsToMatch("/sys/util/**") + .build(); + } + + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-iup", "dev-oracle"}) + @Bean + public GroupedOpenApi cmmnFtBillPaysApiDoc() { + return GroupedOpenApi.builder() + .group("CF. 부가기능-청구서 공통 서비스") + .pathsToMatch("/bill/pay/**") + .build(); + } + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-iup", "dev-oracle"}) + @Bean + public GroupedOpenApi cmmnFtBillKkopayApiDoc() { + return GroupedOpenApi.builder() + .group("CF. 부가기능-청구서(kakaopay)") + .pathsToMatch("/bill/kko/**") + .build(); + } + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-iup", "dev-oracle"}) + @Bean + public GroupedOpenApi cmmnFtBillNvpayApiDoc() { + return GroupedOpenApi.builder() + .group("CF. 부가기능-청구서(naver 간편결제)") + .pathsToMatch("/bill/nv/ep/**") + .build(); + } + + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-traffic", "prod-traffic-cheonan", "prod-iup"}) + @Bean + public GroupedOpenApi cmmnFtNiceCiDiApiDoc() { + return GroupedOpenApi.builder() + .group("CF. 부가기능-CI변환(나이스 CiDi)") + .pathsToMatch("/cmft/nice/ci/**") + .build(); + } + + @Bean + public GroupedOpenApi cmmnFtMblPageApiDoc() { + return GroupedOpenApi.builder() + .group("CF. 부가기능-모바일페이지") + .pathsToMatch( + "/cmft/mbl/page/**" + ) + .build(); + } + + + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-iup"}) + @Bean + public GroupedOpenApi kkoAlimtalkApiDoc() { + return GroupedOpenApi.builder() + .group("CMPT. 전자고지-kakao 알림톡") + .pathsToMatch("/kko/alimtalk/**") + .build(); + } + + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-traffic", "prod-traffic-cheonan", "prod-iup", "dev-oracle"}) + @Bean + public GroupedOpenApi kkoMydocApiDoc() { + return GroupedOpenApi.builder() + .group("CMPT. 전자고지-kakaopay 인증톡(내문서함)") + .pathsToMatch("/kko/mydoc/**") + .build(); + } + + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-iup", "dev-oracle"}) + @Bean + public GroupedOpenApi nvSigntalkApiDoc() { + return GroupedOpenApi.builder() + .group("CMPT. 전자고지-naver 인증톡") + .pathsToMatch("/nv/signtalk/**") + .build(); + } + + @Profile({"local", "local-test", "local-maria", "local-oracle"}) + @Bean + public GroupedOpenApi ktSigntalkApiDoc() { + return GroupedOpenApi.builder() + .group("CMPT. 전자고지-kt 인증톡") + .pathsToMatch("/kt/signtalk/**") + .build(); + } + + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-traffic-cheonan"}) + @Bean + public GroupedOpenApi ktGibisApiDoc() { + return GroupedOpenApi.builder() + .group("CMPT. 전자고지-kt 인증톡(지비스)") + .pathsToMatch("/kt/gibis/**") + .build(); + } + + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-iup", "prod-traffic-cheonan", "dev-oracle"}) + @Bean + public GroupedOpenApi intgrnNotiApiDoc() { + return GroupedOpenApi.builder() + .group("CMPT. 전자고지-통합고지") + .pathsToMatch("/intgrn/noti/**") + .build(); + } + + + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-iup", "dev-oracle"}) + @Bean + public GroupedOpenApi iupServiceApiDoc() { + return GroupedOpenApi.builder() + .group("BIZ. 이용시스템-민자고속도로(IUP)") + .pathsToMatch("/iup/**") + .build(); + } + + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-traffic"}) + @Bean + public GroupedOpenApi trafficCcServiceApiDoc() { + return GroupedOpenApi.builder() + .group("BIZ. 이용시스템-주정차웹(TRAFFIC-춘천)") + .pathsToMatch("/traffic/cc/**") + .build(); + } + + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-traffic-cheonan"}) + @Bean + public GroupedOpenApi trafficCaServiceApiDoc() { + return GroupedOpenApi.builder() + .group("BIZ. 이용시스템-주정차웹(TRAFFIC-천안)") + .pathsToMatch("/traffic/ca/**") + .build(); + } + + +// @Bean +// public GroupedOpenApi adminApiDoc() { +// return GroupedOpenApi.builder() +// .group("springshop-admin") +// .pathsToMatch("/admin/**") +// .addMethodFilter(method -> method.isAnnotationPresent(Admin.class)) +// .build(); +// } +} diff --git a/src/main/java/cokr/xit/ens/core/config/TomcatConfiguration.java b/src/main/java/cokr/xit/ens/core/config/TomcatConfiguration.java new file mode 100644 index 0000000..dc7c004 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/TomcatConfiguration.java @@ -0,0 +1,42 @@ +package cokr.xit.ens.core.config; + +import org.apache.catalina.connector.Connector; +import org.apache.coyote.ajp.AbstractAjpProtocol; +import org.apache.coyote.ajp.AjpNioProtocol; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.servlet.server.ServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import java.net.InetAddress; +import java.net.UnknownHostException; + + +@Configuration +@Profile({"local-test", "prod-traffic-cheonan"}) +public class TomcatConfiguration { + + @Bean + public ServletWebServerFactory servletContainer() { + TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory(); + tomcat.addAdditionalTomcatConnectors(createAjpConnector()); + return tomcat; + } + + private Connector createAjpConnector() { + Connector ajpConnector = new Connector("AJP/1.3"); + ajpConnector.setPort(18009); + ajpConnector.setSecure(false); + ajpConnector.setAllowTrace(false); + ajpConnector.setScheme("http"); + ((AbstractAjpProtocol) ajpConnector.getProtocolHandler()).setSecretRequired(false); + try { + AjpNioProtocol protocol = (AjpNioProtocol) ajpConnector.getProtocolHandler(); + protocol.setAddress(InetAddress.getByName("0.0.0.0")); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + return ajpConnector; + } +} diff --git a/src/main/java/cokr/xit/ens/core/config/WebConfig.java b/src/main/java/cokr/xit/ens/core/config/WebConfig.java new file mode 100644 index 0000000..0354616 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/WebConfig.java @@ -0,0 +1,30 @@ +package cokr.xit.ens.core.config; + +import cokr.xit.ens.core.filter.RequestWrapperFilter; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.view.json.MappingJackson2JsonView; + +import java.util.Arrays; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Bean(name = "jsonView") + public MappingJackson2JsonView jsonView() { + return new MappingJackson2JsonView(); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Bean +// @Profile("!prod-iup") + public FilterRegistrationBean requestWrapperFilter() { + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new RequestWrapperFilter()); + filterRegistrationBean.setUrlPatterns(Arrays.asList("/*")); + return filterRegistrationBean; + } + +} diff --git a/src/main/java/cokr/xit/ens/core/config/logging/P6spyLoggingConfig.java b/src/main/java/cokr/xit/ens/core/config/logging/P6spyLoggingConfig.java new file mode 100644 index 0000000..605ef6f --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/logging/P6spyLoggingConfig.java @@ -0,0 +1,19 @@ +package cokr.xit.ens.core.config.logging; + +import com.p6spy.engine.spy.P6SpyOptions; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PostConstruct; + +@Configuration +public class P6spyLoggingConfig { + + /** + * JPA SQL Logging + * decorator.datasource.p6spy.enable-logging: true / false + */ + @PostConstruct + public void setLogMessageFormat() { + P6SpyOptions.getActiveInstance().setLogMessageFormat(P6spySqlFormatConfiguration.class.getName()); + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/core/config/logging/P6spySqlFormatConfiguration.java b/src/main/java/cokr/xit/ens/core/config/logging/P6spySqlFormatConfiguration.java new file mode 100644 index 0000000..6056fd3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/logging/P6spySqlFormatConfiguration.java @@ -0,0 +1,72 @@ +package cokr.xit.ens.core.config.logging; + +import com.p6spy.engine.logging.Category; +import com.p6spy.engine.spy.appender.MessageFormattingStrategy; +import lombok.extern.slf4j.Slf4j; +import org.hibernate.engine.jdbc.internal.FormatStyle; + +import java.util.Locale; +import java.util.Objects; +import java.util.Stack; + +@Slf4j +public class P6spySqlFormatConfiguration implements MessageFormattingStrategy { + @Override + public String formatMessage(final int connectionId, final String now, final long elapsed, final String category, final String prepared, final String sql, final String url) { + Stack callStack = new Stack<>(); + StackTraceElement[] stackTrace = new Throwable().getStackTrace(); + + for (StackTraceElement stackTraceElement : stackTrace) { + String trace = stackTraceElement.toString(); + if (trace.startsWith("io.p6spy") && !trace.contains("P6spyPrettySqlFormatter")) { + callStack.push(trace); + } + } + + StringBuilder callStackBuilder = new StringBuilder(); + int order = 1; + while(callStack.size() != 0) { + callStackBuilder.append("\n\t\t").append(order++).append(". ").append(callStack.pop()); + } + + String message = new StringBuilder().append("\n\n\tConnection ID: ").append(connectionId) + .append("\n\tExecution Time: ").append(elapsed).append(" ms\n") + .append("\n\tCall Stack (number 1 is entry point): ").append(callStackBuilder).append("\n") + .toString(); + + return sqlFormat(sql, category, message); + } + + private String sqlFormat(String sql, String category, String message) { + if(sql.trim().isEmpty()) { + return ""; + } + + String sqlComment = null; + if(Objects.equals(Category.STATEMENT.getName(), category)) { + sql = sql.trim().toLowerCase(Locale.ROOT); + if(sql.startsWith("/*") && sql.contains("*/")){ + sqlComment = sql.substring(0, sql.indexOf("*/")+2); + sql = sql.substring(sqlComment.length()).trim(); + } + if(sql.startsWith("create") || sql.startsWith("alter") || sql.startsWith("comment") || sql.startsWith("drop")) { + sql = FormatStyle.DDL + .getFormatter() + .format(sql); + } + else { + sql = FormatStyle.BASIC + .getFormatter() + .format(sql); + } + } + + return new StringBuilder().append("\n") + .append("----------------------------------------------------------------------------------------------------") + .append(sqlComment == null ? "" : "\n" + sqlComment) + .append(sql) + .append(message) + .append("----------------------------------------------------------------------------------------------------") + .toString(); + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/core/config/redis/CacheKey.java b/src/main/java/cokr/xit/ens/core/config/redis/CacheKey.java new file mode 100644 index 0000000..a6ae55d --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/redis/CacheKey.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.core.config.redis; + +public class CacheKey { + public static final Long DEFAULT_EXP_SEC = 30L; + public static final String ORGMNG = "orgmng"; + public static final Long ORGMNG_EXP_SEC = 24*60*60L; + public static final String TMPLTMNG = "tmpltmng"; + public static final Long TMPLTMNG_EXP_SEC = 24*60*60L; +} diff --git a/src/main/java/cokr/xit/ens/core/config/redis/EmbeddedRedisConfig.java b/src/main/java/cokr/xit/ens/core/config/redis/EmbeddedRedisConfig.java new file mode 100644 index 0000000..d884dee --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/redis/EmbeddedRedisConfig.java @@ -0,0 +1,95 @@ +package cokr.xit.ens.core.config.redis; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import redis.embedded.RedisServer; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +@Slf4j +//@Configuration +public class EmbeddedRedisConfig { + + @Value("${spring.redis.port}") + private int redisPort; + + private RedisServer redisServer; + + @PostConstruct + public void redisServer() { +// redisServer = new RedisServer(redisPort); +// redisServer.start(); + + log.info("레디스 서버 기동:::port {}", redisPort); + try { + redisServer = RedisServer.builder() + .port(redisPort) +// .setting("maxheap 128M") + .setting("maxmemory 256M") + .build(); + redisServer.start(); + } catch (Exception e) { + log.error("레디스 서버 기동 실패:::\"{}\" 포트가 이미 사용 중 입니다.:::{}", redisPort, e.getMessage()); + } + } + + @PreDestroy + public void stopRedis() { + if (redisServer != null) { + redisServer.stop(); + } + } + +// /** +// * Embedded Redis가 현재 실행중인지 확인 +// */ +// private boolean isRedisRunning() throws IOException { +// return isRunning(executeGrepProcessCommand(redisPort)); +// } +// +// /** +// * 현재 PC/서버에서 사용가능한 포트 조회 +// */ +// public int findAvailablePort() throws IOException { +// +// for (int port = 10000; port <= 65535; port++) { +// Process process = executeGrepProcessCommand(port); +// if (!isRunning(process)) { +// return port; +// } +// } +// +// throw new IllegalArgumentException("Not Found Available port: 10000 ~ 65535"); +// } +// +// /** +// * 해당 port를 사용중인 프로세스 확인하는 sh 실행 +// */ +// private Process executeGrepProcessCommand(int port) throws IOException { +// String command = String.format("netstat -nat | grep LISTEN|grep %d", port); +// String[] shell = {"/bin/sh", "-c", command}; +// return Runtime.getRuntime().exec(shell); +// } +// +// /** +// * 해당 Process가 현재 실행중인지 확인 +// */ +// private boolean isRunning(Process process) { +// String line; +// StringBuilder pidInfo = new StringBuilder(); +// +// try (BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()))) { +// +// while ((line = input.readLine()) != null) { +// pidInfo.append(line); +// } +// +// } catch (Exception e) { +// } +// +// return !StringUtils.isEmpty(pidInfo.toString()); +// } + +} diff --git a/src/main/java/cokr/xit/ens/core/config/redis/RedisCacheConfig.java b/src/main/java/cokr/xit/ens/core/config/redis/RedisCacheConfig.java new file mode 100644 index 0000000..09c401e --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/redis/RedisCacheConfig.java @@ -0,0 +1,105 @@ +package cokr.xit.ens.core.config.redis; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + + +@Configuration +@EnableRedisRepositories +@EnableCaching +public class RedisCacheConfig { + @Value("${spring.redis.host}") + private String redisHost; + + @Value("${spring.redis.port}") + private int redisPort; + + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + return new LettuceConnectionFactory(redisHost, redisPort); + } + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); +// redisTemplate.setConnectionFactory(redisConnectionFactory()); + redisTemplate.setConnectionFactory(redisConnectionFactory); + + + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); +// redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); +// redisTemplate.afterPropertiesSet(); + + + return redisTemplate; + } + + + @Bean + public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) { + RedisCacheConfiguration redisCacheConfiguration = redisCacheDefaultConfiguration() + .entryTtl(Duration.ofSeconds(CacheKey.DEFAULT_EXP_SEC)) +// .computePrefixWith(CacheKeyPrefix.simple()) + ; + + + return RedisCacheManager.RedisCacheManagerBuilder + .fromConnectionFactory(redisConnectionFactory) + .cacheDefaults(redisCacheConfiguration) + .withInitialCacheConfigurations(redisCacheConfigurationMap()) + .build(); + + } + + private RedisCacheConfiguration redisCacheDefaultConfiguration() { + return RedisCacheConfiguration + .defaultCacheConfig() + .disableCachingNullValues() + .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) + .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); + } + + private Map redisCacheConfigurationMap() { + Map redisCacheConfigurationMap = new HashMap<>(); + redisCacheConfigurationMap.put(CacheKey.ORGMNG, redisCacheDefaultConfiguration().entryTtl(Duration.ofSeconds(CacheKey.ORGMNG_EXP_SEC))); + redisCacheConfigurationMap.put(CacheKey.TMPLTMNG, redisCacheDefaultConfiguration().entryTtl(Duration.ofSeconds(CacheKey.TMPLTMNG_EXP_SEC))); + + return redisCacheConfigurationMap; + } + + +// private Map redisCacheConfigurationMap() { +// Map cacheConfigurations = new HashMap<>(); +// for (Map.Entry cacheNameAndTimeout : cacheProperties.getTtl().entrySet()) { +// cacheConfigurations.put( +// cacheNameAndTimeout.getKey() +// , redisCacheDefaultConfiguration().entryTtl(Duration.ofSeconds(cacheNameAndTimeout.getValue())) +// ); +// } +// return cacheConfigurations; +// } +// +// +// + + +} diff --git a/src/main/java/cokr/xit/ens/core/config/support/CustomBeanNameGenerator.java b/src/main/java/cokr/xit/ens/core/config/support/CustomBeanNameGenerator.java new file mode 100644 index 0000000..0439bd4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/support/CustomBeanNameGenerator.java @@ -0,0 +1,61 @@ +package cokr.xit.ens.core.config.support; + +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.lang.NonNull; + +/** + * + *
+ *  API v1, v2 등으로 분류하는 경우
+ *  Bean 이름 식별시 풀패키지 명으로 식별 하도록 함
+ *  Use : 아래 두번째 방식 권장 - 첫 번째 방식은 재확인 필요
+ *
+ *     -------------------------
+ *     Application.java
+ *
+ *     SpringApplicationBuilder applicationBuilder = new SpringApplicationBuilder(Application.class);
+ *     CustomBeanNameGenerator beanNameGenerator = new CustomBeanNameGenerator();
+ *     applicationBuilder.beanNameGenerator(beanNameGenerator);
+ *     applicationBuilder.build().run(args);
+ *     -------------------------
+ *
+ *     OR
+ *
+ *     -------------------------
+ *     @ComponentScan(
+ *         nameGenerator = CustomBeanNameGenerator.class,
+ *         basePackages = {"cokr.xit.biz", "cokr.xit.core"},
+ *         excludeFilters = @ComponentScan.Filter(
+ *                 type = FilterType.ASPECTJ,
+ *                 pattern = {
+ *                         "cokr.xit"
+ *                 }
+ *         )
+ *     )
+ *
+ *     DatabaseConfig.java
+ *     @MapperScan(
+ *         nameGenerator = CustomBeanNameGenerator.class,
+ *         basePackages = DataSourceConfig.PACKAGE,
+ *         sqlSessionFactoryRef = "sqlSessionFactory"
+ *     )
+ *     static final String PACKAGE = "cokr.xit.**.mapper";
+ *     --------------------------
+ *
+ * 
+ * + */ +public class CustomBeanNameGenerator implements BeanNameGenerator { + @Override + public @NonNull String generateBeanName(@NonNull BeanDefinition definition, @NonNull BeanDefinitionRegistry registry) { + final String result = generateFullBeanName((AnnotatedBeanDefinition)definition); + return result; + } + + private String generateFullBeanName(final AnnotatedBeanDefinition definition) { + return definition.getMetadata().getClassName(); + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/EnsAMSEvent.java b/src/main/java/cokr/xit/ens/core/eventlistner/EnsAMSEvent.java new file mode 100644 index 0000000..4e82e79 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/EnsAMSEvent.java @@ -0,0 +1,22 @@ +package cokr.xit.ens.core.eventlistner; + +import cokr.xit.ens.core.eventlistner.adaptor.EnsAMSAcceptAdaptor; +import cokr.xit.ens.core.eventlistner.adaptor.EnsAMSCallbackAdaptor; +import cokr.xit.ens.core.eventlistner.adaptor.EnsAMSMakeAdaptor; +import cokr.xit.ens.core.eventlistner.adaptor.EnsAMSSendAdaptor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Builder +@Getter +public class EnsAMSEvent { + + @Setter + private int idx = 0; + private EnsAMSAcceptAdaptor accept; + private EnsAMSMakeAdaptor make; + private EnsAMSSendAdaptor send; + private EnsAMSCallbackAdaptor callback; + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/EnsAMSEventListener.java b/src/main/java/cokr/xit/ens/core/eventlistner/EnsAMSEventListener.java new file mode 100644 index 0000000..fdc1b44 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/EnsAMSEventListener.java @@ -0,0 +1,33 @@ +package cokr.xit.ens.core.eventlistner; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class EnsAMSEventListener implements EnsAMSEventListenerTemplate { + + @Override + @Order(1) + @EventListener + public void execute(EnsAMSEvent event) { + if(event.getAccept()!=null) + event.getAccept().execute(); + if(event.getMake()!=null) + event.getMake().execute(); + if(event.getSend()!=null) + event.getSend().execute(); + } + + @Override + @Order(2) + @EventListener + public void callback(EnsAMSEvent event) { + if(event.getCallback()!=null) + event.getCallback().execute(); + } +} diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/EnsAMSEventListenerTemplate.java b/src/main/java/cokr/xit/ens/core/eventlistner/EnsAMSEventListenerTemplate.java new file mode 100644 index 0000000..39d6435 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/EnsAMSEventListenerTemplate.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.core.eventlistner; + +public interface EnsAMSEventListenerTemplate

{ + + void execute(P arg); + + void callback(P arg); +} diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/AcceptEventListener.java b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/AcceptEventListener.java new file mode 100644 index 0000000..8a7a234 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/AcceptEventListener.java @@ -0,0 +1,52 @@ +package cokr.xit.ens.core.eventlistner._ignore; + +import cokr.xit.ens.core.eventlistner._ignore.events.AcceptAfterTransactionEvent; +import cokr.xit.ens.core.eventlistner._ignore.events.AcceptBeforeTransactionEvent; +import cokr.xit.ens.core.eventlistner._ignore.events.AcceptEvent; +import cokr.xit.ens.modules.kkomydoc.service.support.KkoMydocAcceptor; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; + +@Slf4j +@Component +@RequiredArgsConstructor +public class AcceptEventListener { + private final KkoMydocAcceptor acceptor; + +// @Override +// public void process(Event e) { +// +// } + + @EventListener + @Order(1) + public void process1(final AcceptEvent event){ + log.info("AcceptEventHandler Process 1 호출......"); + } + @EventListener + @Order(2) + public void process2(final AcceptEvent event){ + log.info("AcceptEventHandler Process 2 호출......"); + } + + @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) + public void beforeTransactionProcess(AcceptBeforeTransactionEvent event){ + log.info("AcceptEventHandler beforeTransactionProcess 호출......"); + event.callback(); + } + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void afterTransactionProcess(AcceptAfterTransactionEvent event){ + log.info("AcceptEventHandler afterTransactionProcess 호출......"); + event.callback(); + } + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION) + public void completedTransactionProcess(AcceptAfterTransactionEvent event){ + log.info("AcceptEventHandler completedTransactionProcess 호출......"); + event.completed(); + } +} diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/KkoMydocExampleService.java b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/KkoMydocExampleService.java new file mode 100644 index 0000000..e415f73 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/KkoMydocExampleService.java @@ -0,0 +1,50 @@ +package cokr.xit.ens.core.eventlistner._ignore; + +import cokr.xit.ens.core.eventlistner._ignore.events.AcceptBeforeTransactionEvent; +import cokr.xit.ens.core.utils.MapDeserailizer; +import cokr.xit.ens.modules.kkomydoc.model.KkoMydocAcceptReqDTO; +import cokr.xit.ens.core.eventlistner._ignore.events.AcceptEvent; +import cokr.xit.ens.modules.kkomydoc.service.support.KkoMydocAcceptor; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Slf4j +@Service +@RequiredArgsConstructor +public class KkoMydocExampleService { + private final KkoMydocAcceptor acceptor; + + private final ApplicationEventPublisher applicationEventPublisher; + + public void process(String jsonStr){ + Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).serializeNulls().create(); + KkoMydocAcceptReqDTO reqDTO = gson.fromJson(jsonStr, KkoMydocAcceptReqDTO.class); + + applicationEventPublisher.publishEvent(new AcceptEvent(reqDTO)); + } + + public void transactionProcess(){ + String jsonStr = ""; + AcceptBeforeTransactionEvent beforeEvent = new AcceptBeforeTransactionEvent() { + @Override + public void callback() { + System.out.println(jsonStr); + } + }; + AcceptBeforeTransactionEvent afterEvent = new AcceptBeforeTransactionEvent() { + @Override + public void callback() { + + } + }; + applicationEventPublisher.publishEvent(beforeEvent); + applicationEventPublisher.publishEvent(afterEvent); + } + +} diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/events/AbstractTransactionEvent.java b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/events/AbstractTransactionEvent.java new file mode 100644 index 0000000..8c51188 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/events/AbstractTransactionEvent.java @@ -0,0 +1,6 @@ +package cokr.xit.ens.core.eventlistner._ignore.events; + +public interface AbstractTransactionEvent { + + void callback(); +} diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/events/AcceptAfterTransactionEvent.java b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/events/AcceptAfterTransactionEvent.java new file mode 100644 index 0000000..213acd9 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/events/AcceptAfterTransactionEvent.java @@ -0,0 +1,7 @@ +package cokr.xit.ens.core.eventlistner._ignore.events; + +public interface AcceptAfterTransactionEvent extends AbstractTransactionEvent{ + + void completed(); + +} diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/events/AcceptBeforeTransactionEvent.java b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/events/AcceptBeforeTransactionEvent.java new file mode 100644 index 0000000..4ae436d --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/events/AcceptBeforeTransactionEvent.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.core.eventlistner._ignore.events; + +public interface AcceptBeforeTransactionEvent extends AbstractTransactionEvent { + +} diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/events/AcceptEvent.java b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/events/AcceptEvent.java new file mode 100644 index 0000000..5bf8e8c --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/events/AcceptEvent.java @@ -0,0 +1,17 @@ +package cokr.xit.ens.core.eventlistner._ignore.events; + +import cokr.xit.ens.modules.kkomydoc.model.KkoMydocAcceptReqDTO; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class AcceptEvent implements AbstractTransactionEvent{ + + private final KkoMydocAcceptReqDTO kkoMydocAcceptReqDTO; + + @Override + public void callback() { + + } +} diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/package-info.java b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/package-info.java new file mode 100644 index 0000000..818e6ad --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/_ignore/package-info.java @@ -0,0 +1,29 @@ +/** + * EventListener Example 패키지 + *

+ * -. @EventListener 어노테이션 사용 예시 + * -. 동일 Event에 대한 @Order 어노테이션 사용 예시 + * -. @TransactionalEventListener 어노테이션 사용 예시 + * + * [예시] + * * Event 발생: + * private final ApplicationEventPublisher applicationEventPublisher; + * ... + * applicationEventPublisher.publishEvent(new :이벤트클래스); + * * Event 수신: + * @EventListener + * public void process(final :이벤트클래스 event){...} + * @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT/AFTER_COMMIT/AFTER_COMPLETION) + * public void beforeTransactionProcess(:이벤트클래스 event){...} + * + * [참고사이트] + * * [EventListner를 활용한 느슨한 결합 및 이벤트 처리](https://woodcock.tistory.com/27?category=978595) + * * [Spring의 @EventListener 쓰는 이유?](https://sunghs.tistory.com/139) + *

+ * + * @since 1.0 + * @author 박민규 + * @version 1.0 + */ +package cokr.xit.ens.core.eventlistner._ignore; + diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/adaptor/EnsAMSAcceptAdaptor.java b/src/main/java/cokr/xit/ens/core/eventlistner/adaptor/EnsAMSAcceptAdaptor.java new file mode 100644 index 0000000..9f47e34 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/adaptor/EnsAMSAcceptAdaptor.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.core.eventlistner.adaptor; + +public interface EnsAMSAcceptAdaptor { + T execute(); +} diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/adaptor/EnsAMSCallbackAdaptor.java b/src/main/java/cokr/xit/ens/core/eventlistner/adaptor/EnsAMSCallbackAdaptor.java new file mode 100644 index 0000000..c6bed85 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/adaptor/EnsAMSCallbackAdaptor.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.core.eventlistner.adaptor; + +public interface EnsAMSCallbackAdaptor { + T execute(); +} diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/adaptor/EnsAMSMakeAdaptor.java b/src/main/java/cokr/xit/ens/core/eventlistner/adaptor/EnsAMSMakeAdaptor.java new file mode 100644 index 0000000..a348a9e --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/adaptor/EnsAMSMakeAdaptor.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.core.eventlistner.adaptor; + +public interface EnsAMSMakeAdaptor { + T execute(); +} diff --git a/src/main/java/cokr/xit/ens/core/eventlistner/adaptor/EnsAMSSendAdaptor.java b/src/main/java/cokr/xit/ens/core/eventlistner/adaptor/EnsAMSSendAdaptor.java new file mode 100644 index 0000000..b7fd1b2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/eventlistner/adaptor/EnsAMSSendAdaptor.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.core.eventlistner.adaptor; + +public interface EnsAMSSendAdaptor { + T execute(); +} diff --git a/src/main/java/cokr/xit/ens/core/exception/EnsException.java b/src/main/java/cokr/xit/ens/core/exception/EnsException.java new file mode 100644 index 0000000..629bbcc --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/exception/EnsException.java @@ -0,0 +1,47 @@ +package cokr.xit.ens.core.exception; + +import cokr.xit.ens.core.exception.code.EnsErrCd; + +public class EnsException extends RuntimeException { + + /** + * serialVersionUID + */ + private static final long serialVersionUID = 1L; + + private EnsErrCd errCd; + + private Object data; + + public EnsException(EnsErrCd errCd) { + super(errCd.getCodeNm()); + this.errCd = errCd; + } + + public EnsException(EnsErrCd errCd, String message) { +// super(String.format("%s::: %s", errCd.getCodeNm(), message)); + super(String.format("%s", message)); + this.errCd = errCd; + } + + public EnsException(EnsErrCd errCd, String message, Object data) { + super(String.format("%s", message)); + this.errCd = errCd; + this.data = data; + } + + public EnsException(EnsErrCd errCd, String message, Throwable cause) { +// super(String.format("%s::: %s", errCd.getCodeNm(), message), cause); + super(String.format("%s", message), cause); + this.errCd = errCd; + } + + public EnsErrCd getErrCd() { + return errCd; + } + + public Object getData() { return data; } + + +} + diff --git a/src/main/java/cokr/xit/ens/core/exception/code/EnsErrCd.java b/src/main/java/cokr/xit/ens/core/exception/code/EnsErrCd.java new file mode 100644 index 0000000..f139de8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/exception/code/EnsErrCd.java @@ -0,0 +1,182 @@ +package cokr.xit.ens.core.exception.code; + +import cokr.xit.ens.core.code.CodeMapperType; + +/** + *
    + *
  • 업무 그룹명: 내부 오류 코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2021. 8. 4. 오후 3:51:43 + *
+ * + * @author 박민규 + */ +public enum EnsErrCd implements CodeMapperType { + + OK("정상"), + UNKNOWN("알수없음"), + + NO_REQUIRED_PARAM("필수 파라미터가 없습니다."), + INVALID_REQUEST("유효하지 않은 요청데이터 입니다."), + INVALID_REQUEST_URL("유효하지 않은 요청 URL 입니다."), + NOT_FOUND_BEAN("빈(bean)을 찾을 수 없습니다."), + NO_DATA_FOUND("자료를 찾을 수 없습니다."), + INVALID_DATA("유효하지 않은 데이터 입니다."), + API_COMM_ERROR("API 통신 오류가 발생 했습니다."), + INVALID_RESPONSE("유효하지 않은 응답 입니다."), + INVALID_RES_CODE("유효하지 않은 응답코드 입니다."), + INVALID_RES_DATA("유효하지 않은 응답데이터 입니다."), + RESPONSED_FAILURE_CODE("실패코드가 응답 되었습니다."), + FAILED_CREATE_RESPONSE_DATA("응답데이터 생성 실패"), + URL_ALREADY_CREATED("URL이 이미 생성 되었습니다."), + PAYMENT_ALREADY_CMPLTED("결제가 완료된 자료 입니다."), + SERVICE_NOT_SUPPORTED("지원하지 않는 서비스 입니다."), + + + ERR401("필수 파라미터가 없습니다."), + ERR402("파라미터 유효성 검증 오류"), + ERR403("잘못된 파라미터 입니다."), + ERR404("일치하는 자료가 없습니다."), + ERR405("잘못된 요청 값."), + ERR410("필수값 없음"), + ERR411("잘못된 JSON 포맷 문자열"), + ERR500("서버 오류"), + ERR501("HttpServer 오류"), + ERR502("HttpClient 오류"), + ERR503("RestClient 오류"), + ERR504("요청 데이터 Json 파싱 오류"), + ERR505("응답 데이터 Json 파싱 오류"), + ERR506("Hash 생성 오류"), + ERR507("유효하지 않은 데이터"), + ERR511("JSON 형식으로 변환 실패"), + ERR512("JSON Parsing Fail"), + ERR513("Services Not Supported"), + ERR521("방화벽 설정 오류"), + ERR540("중복된 데이터"), + ERR600("API 오류"), + ERR601("API서버 응답 오류"), + ERR602("API서버 내부 오류"), + ERR603("유효하지 않은 토큰(OTT) 값"), + ERR604("API 통신 실패"), + ERR610("응답 데이터에 필수값이 없음"), + ERR620("API Response Error"), + ERR699("API 기타 오류"), + ERR999("기타 오류"), + ERR901("권한 없음"), + ERR902("유효하지 않은 데이터"), + ERR903("처리 완료된 데이터"), + ERR904("CI 변환 실패"), + + + + BILL401("duplicated \"bill_uid\""), + BILL402("duplicated \"biller_user_key\""), + BILL403("validation fail"), + BILL404("not found data"), + BILL405("invalid value"), + BILL501("json convert fail"), + BILL511("청구서 URL 생성 병렬처리 중 ERROR"), + BILL512("청구서 URL 생성 실패"), + BILL601("json parsing fail"), + BILL602("http status failure response"), + BILL603("response data is invalid"), + BILL604("client api failure response"), + BILL999("unknown error"), + + + ACPT402("유효성 검증 실패"), + ACPT404("일치하는 자료가 없습니다."), + ACPT405("접수 가능한 자료가 아닙니다."), + ACPT410("필수값 없음"), + ACPT411("잘못된 JSON 포맷 문자열"), + ACPT412("청구서 접수 실패"), + ACPT500("접수 처리 중 오류"), + ACPT511("JSON 형식으로 변환 실패"), + ACPT999("기타 오류"), + + + MAKE404("일치하는 자료가 없습니다."), + MAKE410("필수값 없음"), + MAKE411("잘못된 JSON 포맷 문자열"), + MAKE500("제작 처리 중 오류"), + MAKE511("JSON 형식으로 변환 실패"), + MAKE512("청구서 제작 실패"), + MAKE513("CI 제작 실패"), + MAKE521("데이터 생성 실패"), + MAKE610("응답 데이터에 필수값이 없음"), + MAKE620("API Response Error"), + MAKE630("API Request Error"), + + + SEND404("일치하는 자료가 없습니다."), + SEND405("잘못된 요청 값."), + SEND410("필수값 없음"), + SEND411("잘못된 JSON 포맷 문자열"), + SEND500("전송 처리 중 오류"), + SEND502("발송메시지 생성 실패"), + SEND511("JSON 형식으로 변환 실패"), + SEND601("토큰생성 실패"), + SEND620("API Response Error"), + SEND630("API Request Error"), + + + RSLT404("일치하는 자료가 없습니다."), + RSLT405("요청건수와 실제 자료의 건수가 상이 합니다."), + RSLT406("일부 자료가 결과반영에 실패 했습니다."), + RSLT407("전체 자료가 결과반영에 실패 했습니다."), + RSLT410("필수값 없음"), + RSLT411("잘못된 JSON 포맷 문자열"), + RSLT500("전송결과 처리 중 오류"), + RSLT502("요청메시지 생성 실패"), + RSLT511("JSON 형식으로 변환 실패"), + RSLT512("제공되지 않는 서비스 입니다."), + RSLT601("전송결과 조회 실패"), + RSLT620("API Response Error"), + RSLT630("API Request Error"), + RSLT999("기타 오류"), + + + PRVD404("일치하는 자료가 없습니다."), + PRVD410("필수값 없음"), + PRVD411("잘못된 JSON 포맷 문자열"), + PRVD500("상태갱신 처리 중 오류"), + PRVD511("JSON 형식으로 변환 실패"), + PRVD502("요청메시지 생성 실패"), + PRVD601("상태 조회 실패"), + PRVD620("API Response Error"), + PRVD630("API Request Error"), + ; + + + private final String code; + private final String codeNm; + + EnsErrCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } + + + public static EnsErrCd valueOfEnum(String code) { + if (code == null) + return EnsErrCd.UNKNOWN; + + EnsErrCd ensErrCd = null; + try { + ensErrCd = EnsErrCd.valueOf(code); + } catch (IllegalArgumentException e) { + ensErrCd = EnsErrCd.UNKNOWN; + } + return ensErrCd; + } +} diff --git a/src/main/java/cokr/xit/ens/core/filter/CorsFilter.java b/src/main/java/cokr/xit/ens/core/filter/CorsFilter.java new file mode 100644 index 0000000..2b1d84a --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/filter/CorsFilter.java @@ -0,0 +1,41 @@ +//package cokr.xit.ens.core.filter; +// +//import org.springframework.core.Ordered; +//import org.springframework.core.annotation.Order; +//import org.springframework.stereotype.Component; +// +//import javax.servlet.*; +//import javax.servlet.http.HttpServletRequest; +//import javax.servlet.http.HttpServletResponse; +//import java.io.IOException; +//import java.util.Arrays; +//import java.util.List; +// +//@Component +//@Order(Ordered.HIGHEST_PRECEDENCE) +//public class CorsFilter implements Filter { +// @Override +// public void init(FilterConfig filterConfig) throws ServletException { +// } +// +// @Override +// public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { +// +// HttpServletRequest request = (HttpServletRequest) servletRequest; +// HttpServletResponse response = (HttpServletResponse) servletResponse; +// +// +// response.setHeader("Access-Control-Allow-Origin", "*"); +//// response.setHeader("Access-Control-Allow-Credentials", "true"); +// response.setHeader("Access-Control-Allow-Methods","*"); +// response.setHeader("Access-Control-Max-Age", "3600"); +// response.setHeader("Access-Control-Allow-Headers", +// "Origin, X-Requested-With, Content-Type, Accept, Authorization"); +// +// if("OPTIONS".equalsIgnoreCase(request.getMethod())) { +// response.setStatus(HttpServletResponse.SC_OK); +// }else { +// filterChain.doFilter(servletRequest, servletResponse); +// } +// } +//} diff --git a/src/main/java/cokr/xit/ens/core/filter/RequestWrapper.java b/src/main/java/cokr/xit/ens/core/filter/RequestWrapper.java new file mode 100644 index 0000000..698e890 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/filter/RequestWrapper.java @@ -0,0 +1,90 @@ +package cokr.xit.ens.core.filter; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +import org.apache.commons.io.IOUtils; +import org.springframework.util.StringUtils; + +/** + * + *
    + *
  • 업무 그룹명: RequestWrapper 클래스
  • + *
  • 설 명: getInputStream() 오버라이딩하여 재사용이 가능하도록 한다.
  • + *
  • 작성일: 2021. 11. 30. 오전 11:22:09 + *
+ * + * @author 박민규 + * + */ +public class RequestWrapper extends HttpServletRequestWrapper{ + private final Charset encoding; + private byte[] rawData; + + @SuppressWarnings("deprecation") + public RequestWrapper(HttpServletRequest request) throws IOException { + super(request); + String characterEncoding = request.getCharacterEncoding(); + if (StringUtils.isEmpty(characterEncoding)) { + characterEncoding = StandardCharsets.UTF_8.name(); + } + this.encoding = Charset.forName(characterEncoding); + + try { + InputStream inputStream = request.getInputStream(); //getInputStream()은 한번만 사용 가능. 이후 getInputStream 호출 시 "getInputStream() has already been called for this request" 오류 발생 + this.rawData = IOUtils.toByteArray(inputStream); + } catch (IOException e) { + throw e; + } + + } + + @Override + public ServletInputStream getInputStream() throws IOException { + final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.rawData); + ServletInputStream servletInputStream = new ServletInputStream() { + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + } + + public int read() throws IOException { + return byteArrayInputStream.read(); + } + }; + return servletInputStream; + } + + @Override + public BufferedReader getReader() throws IOException { + return new BufferedReader(new InputStreamReader(this.getInputStream(), this.encoding)); + } + + @Override + public ServletRequest getRequest() { + return super.getRequest(); + } + + + +} diff --git a/src/main/java/cokr/xit/ens/core/filter/RequestWrapperFilter.java b/src/main/java/cokr/xit/ens/core/filter/RequestWrapperFilter.java new file mode 100644 index 0000000..63610b8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/filter/RequestWrapperFilter.java @@ -0,0 +1,22 @@ +package cokr.xit.ens.core.filter; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +public class RequestWrapperFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + RequestWrapper readableRequestWrapper = new RequestWrapper((HttpServletRequest) request); //RequestWrapper 클래스로 wrapping + chain.doFilter(readableRequestWrapper, response); + } + +} diff --git a/src/main/java/cokr/xit/ens/core/init/InitJpaRunner.java b/src/main/java/cokr/xit/ens/core/init/InitJpaRunner.java new file mode 100644 index 0000000..d825e84 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/init/InitJpaRunner.java @@ -0,0 +1,232 @@ +package cokr.xit.ens.core.init; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.TmpltMngIntgrnDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.OrgMngDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.service.OrgMngService; +import cokr.xit.ens.modules.common.ctgy.sys.mng.service.TmpltMngService; +import cokr.xit.ens.modules.kkoalimtalk.model.TmpltMngKkoAlimtalkDTO; +import cokr.xit.ens.modules.kkomydoc.model.TmpltMngKkoMydocDTO; +import cokr.xit.ens.modules.ktsigntalk.common.code.MTypeCd; +import cokr.xit.ens.modules.ktsigntalk.direct.model.TmpltMngKtSigntalkDTO; +import cokr.xit.ens.modules.ktsigntalk.gibis.model.TmpltMngKtGibisDTO; +import cokr.xit.ens.modules.nvsigntalk.model.TmpltMngNvSigntalkDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public abstract class InitJpaRunner implements ApplicationRunner { + + @Autowired + private OrgMngService orgMngService; + @Autowired + private TmpltMngService tmpltMngService; + + @Value("${contract.kakao.pay.mydoc.access-token}") + protected String KKO_MD_ACCESS_TOKEN; + @Value("${contract.kakao.pay.mydoc.contract-uuid}") + protected String KKO_MD_CONTRACT_UUID; + @Value("${contract.kakao.pay.bill.dozn.biller-code}") + protected String KKO_BP_BILLER_CODE; + @Value("${contract.kakao.pay.bill.dozn.authorization}") + protected String KKO_BP_AUTHORIZATION; + @Value("${contract.kakao.alimtalk.biztalk.bsid}") + protected String KKO_AT_BSID; + @Value("${contract.kakao.alimtalk.biztalk.passwd}") + protected String KKO_AT_PASSWD; + @Value("${contract.kakao.alimtalk.biztalk.senderKey}") + protected String KKO_AT_SENDER_KEY; + @Value("${contract.nice.dici.socket.site-code}") + protected String NICE_CD_SITE_CODE; + @Value("${contract.nice.dici.socket.site-pw}") + protected String NICE_CD_SITE_PW; + @Value("${contract.nice.dici.rest.client-id}") + protected String NICE_CD_CLIENT_ID; + @Value("${contract.nice.dici.rest.client-secret}") + protected String NICE_CD_CLIENT_SECRET; + @Value("${contract.naver.signtalk.x-naver-client-id}") + protected String NV_ST_X_NAVER_CLIENT_ID; + @Value("${contract.naver.signtalk.x-naver-client-secret}") + protected String NV_ST_X_NAVER_CLIENT_SECRET; + + @Value("${contract.kt.signtalk.direct.access-token}") + protected String KT_ST_ACCESS_TOKEN; + @Value("${contract.kt.signtalk.direct.service-cd}") + protected String KT_ST_SERVICE_CD; + @Value("${contract.kt.signtalk.direct.service-key}") + protected String KT_ST_SERVICE_KEY; + @Value("${contract.kt.signtalk.direct.client-id}") + protected String KT_ST_CLIENT_ID; + @Value("${contract.kt.signtalk.direct.client_pw}") + protected String KT_ST_CLIENT_SECRET; + + @Override + public void run(ApplicationArguments args) throws Exception { + List orgMngResult = createOrgMngDTO().stream().map(dto -> orgMngService.add(dto)).collect(Collectors.toList()); + List tmpltMngResult = createTmpltMngDTO().stream() + .map(data -> tmpltMngService.add(data, (String) data.get("dtype"))) + .collect(Collectors.toList()); + System.out.println("============================================================================================================"); + System.out.println("======== Initailize Information [OrgMng & TmpltMng] :: active profiles - " + System.getProperty("spring.profiles.active") + " ========"); + System.out.println(orgMngResult.toString()); + System.out.println(tmpltMngResult.toString()); + System.out.println("============================================================================================================"); + } + + abstract protected List createOrgMngDTO(); + + protected OrgMngDTO createOrgMngDTO(String orgCd, String nvOrgId, String orgNm, String kkoBpCsignYn, String kkoBpPrepayApi, String kkoBpPayResultApi) { + return OrgMngDTO.builder() + .orgCd(orgCd) + .orgNm(orgNm) + + .kkoMdAccessToken(KKO_MD_ACCESS_TOKEN) + .kkoMdContractUuid(KKO_MD_CONTRACT_UUID) + + .kkoBpCsignYn(kkoBpCsignYn) + .kkoBpBillerCode(KKO_BP_BILLER_CODE) + .kkoBpAuthorization(KKO_BP_AUTHORIZATION) + .kkoBpPrepayApi(kkoBpPrepayApi) + .kkoBpPayResultApi(kkoBpPayResultApi) + + .kkoAtBsid(KKO_AT_BSID) + .kkoAtPasswd(KKO_AT_PASSWD) + .kkoAtSenderKey(KKO_AT_SENDER_KEY) + + .niceCdSiteCode(NICE_CD_SITE_CODE) + .niceCdSitePw(NICE_CD_SITE_PW) + .niceCdClientId(NICE_CD_CLIENT_ID) + .niceCdClientSercet(NICE_CD_CLIENT_SECRET) + + .nvStXNaverClientId(NV_ST_X_NAVER_CLIENT_ID) + .nvStXNaverClientSecret(NV_ST_X_NAVER_CLIENT_SECRET) + .nvStOrgId(nvOrgId) + + .ktStAccessToken(KT_ST_ACCESS_TOKEN) + .ktStServiceCd(KT_ST_SERVICE_CD) + .ktStServiceKey(KT_ST_SERVICE_KEY) + .ktStClientId(KT_ST_CLIENT_ID) + .ktStClientSecret(KT_ST_CLIENT_SECRET) + .build(); + } + + + abstract protected List> createTmpltMngDTO(); + + final protected TmpltMngKkoAlimtalkDTO createTmpltMngKkoAlimtalk(String orgCd, String tmpltCd, String biztalkTmpltCode, String title, String message, String useYn) { + return + TmpltMngKkoAlimtalkDTO.builder() + .dtype("kkoat") + .orgCd(orgCd) + .tmpltCd(tmpltCd) + .title(title) + .message(message) + .useYn(useYn == null ? "Y" : useYn) + .biztalkOrgCd(null) + .biztalkTmpltCode(biztalkTmpltCode) + .build(); + } + + protected TmpltMngKkoMydocDTO createTmpltMngKkoMydoc(String orgCd, String tmpltCd, String title, String message, String useYn, String csNumber, String csName, String ciTransUseYn, String tmpltMsgUseYn, String tmpltCsInfoUseYn) { + return TmpltMngKkoMydocDTO.builder() + .dtype("kkomd") + .orgCd(orgCd) + .tmpltCd(tmpltCd) + .title(title) + .message(message) + .useYn(useYn == null ? "Y" : useYn) + .csNumber(csNumber) + .csName(csName) + .ciTransUseYn(ciTransUseYn) + .tmpltMsgUseYn(tmpltMsgUseYn) + .tmpltCsInfoUseYn(tmpltCsInfoUseYn) + .build(); + } + + final protected TmpltMngNvSigntalkDTO createTmpltMngNvSigntalk(String orgCd, String tmpltCd, String title, String message, String useYn, String callCenterNo, String ciTransUseYn, String tmpltMsgUseYn, String tmpltCsInfoUseYn, String messageDataFmt) { + return TmpltMngNvSigntalkDTO.builder() + .dtype("nvst") + .orgCd(orgCd) + .tmpltCd(tmpltCd) + .title(title) + .message(message) + .useYn(useYn == null ? "Y" : useYn) + .callCenterNo(callCenterNo) + .ciTransUseYn(ciTransUseYn) + .tmpltMsgUseYn(tmpltMsgUseYn) + .tmpltCsInfoUseYn(tmpltCsInfoUseYn) +// .messageDataFmt(CmmnUtil.isEmpty(messageDataFmt) ? null : mapper.readValue(messageDataFmt, Map.class)) + .messageDataFmt(messageDataFmt) + .build(); + + + } + + final protected TmpltMngKtGibisDTO createTmpltMngKtGibis(String orgCd, String tmpltCd, String title, String message, String useYn, String msgCd, MTypeCd mTypeCd, String msgType, Integer optType, String sndTelNo, String sendTel, String ciTransUseYn, String tmpltMsgUseYn, String tmpltCsInfoUseYn) { + return TmpltMngKtGibisDTO.builder() + .dtype("ktgbs") + .orgCd(orgCd) + .tmpltCd(tmpltCd) + .title(title) + .message(message) + .useYn(useYn == null ? "Y" : useYn) + .msgCd(msgCd) + .mtype(mTypeCd) + .msgType(msgType) + .optType(optType) + .sndTelNo(sndTelNo) + .sendTel(sendTel) + .ciTransUseYn(ciTransUseYn) + .tmpltMsgUseYn(tmpltMsgUseYn) + .tmpltCsInfoUseYn(tmpltCsInfoUseYn) + .build(); + } + + final protected TmpltMngIntgrnDTO createTmpltMngIntgrn(PostSeCd try1, PostSeCd try2, PostSeCd try3, String orgCd, String tmpltCd, String title, String message, String useYn) { + return createTmpltMngIntgrn(try1, try2, try3, orgCd, tmpltCd, title, message, useYn, null, null, null, null, null); + } + + final protected TmpltMngIntgrnDTO createTmpltMngIntgrn(PostSeCd try1, PostSeCd try2, PostSeCd try3, String orgCd, String tmpltCd, String title, String message, String useYn, TmpltMngKkoAlimtalkDTO kkoAlimtalk) { + return createTmpltMngIntgrn(try1, try2, try3, orgCd, tmpltCd, title, message, useYn, kkoAlimtalk, null, null, null, null); + } + + final protected TmpltMngIntgrnDTO createTmpltMngIntgrn(PostSeCd try1, PostSeCd try2, PostSeCd try3, String orgCd, String tmpltCd, String title, String message, String useYn, TmpltMngKkoAlimtalkDTO kkoAlimtalk, TmpltMngKkoMydocDTO kkoMydoc) { + return createTmpltMngIntgrn(try1, try2, try3, orgCd, tmpltCd, title, message, useYn, kkoAlimtalk, kkoMydoc, null, null, null); + } + + final protected TmpltMngIntgrnDTO createTmpltMngIntgrn(PostSeCd try1, PostSeCd try2, PostSeCd try3, String orgCd, String tmpltCd, String title, String message, String useYn, TmpltMngKkoAlimtalkDTO kkoAlimtalk, TmpltMngKkoMydocDTO kkoMydoc, TmpltMngNvSigntalkDTO nvSigntalk) { + return createTmpltMngIntgrn(try1, try2, try3, orgCd, tmpltCd, title, message, useYn, kkoAlimtalk, kkoMydoc, nvSigntalk, null, null); + } + + final protected TmpltMngIntgrnDTO createTmpltMngIntgrn(PostSeCd try1, PostSeCd try2, PostSeCd try3, String orgCd, String tmpltCd, String title, String message, String useYn, TmpltMngKkoAlimtalkDTO kkoAlimtalk, TmpltMngKkoMydocDTO kkoMydoc, TmpltMngNvSigntalkDTO nvSigntalk, TmpltMngKtSigntalkDTO ktSigntalk) { + return createTmpltMngIntgrn(try1, try2, try3, orgCd, tmpltCd, title, message, useYn, kkoAlimtalk, kkoMydoc, nvSigntalk, ktSigntalk, null); + } + + final protected TmpltMngIntgrnDTO createTmpltMngIntgrn(PostSeCd try1, PostSeCd try2, PostSeCd try3, String orgCd, String tmpltCd, String title, String message, String useYn, TmpltMngKkoAlimtalkDTO kkoAlimtalk, TmpltMngKkoMydocDTO kkoMydoc, TmpltMngNvSigntalkDTO nvSigntalk, TmpltMngKtSigntalkDTO ktSigntalk, TmpltMngKtGibisDTO ktGibis) { + return + TmpltMngIntgrnDTO.builder() + .dtype("intgrn") + .orgCd(orgCd) + .tmpltCd(tmpltCd) + .title(title) + .message(message) + .useYn(useYn == null ? "Y" : useYn) + .try1(try1) + .try2(try2) + .try3(try3) + .kkoAlimtalk(kkoAlimtalk) + .kkoMydoc(kkoMydoc) + .nvSigntalk(nvSigntalk) + .ktSigntalk(ktSigntalk) + .ktGibis(ktGibis) + .build(); + } + + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/core/init/JpaRunner.java b/src/main/java/cokr/xit/ens/core/init/JpaRunner.java new file mode 100644 index 0000000..e00eb14 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/init/JpaRunner.java @@ -0,0 +1,268 @@ +package cokr.xit.ens.core.init; + +import cokr.xit.ens.biz.iup.code.IupPrcsCd; +import cokr.xit.ens.biz.iup.code.IupSendTypeCd; +import cokr.xit.ens.biz.iup.domain.FsJob; +import cokr.xit.ens.biz.iup.domain.TbInputDataBulkTest; +import cokr.xit.ens.biz.iup.domain.TbInputDataXit; +import cokr.xit.ens.biz.iup.domain.TbInputXit; +import cokr.xit.ens.biz.iup.domain.repository.FsJobRepository; +import cokr.xit.ens.biz.iup.domain.repository.TbInputDataBulkTestRepository; +import cokr.xit.ens.biz.iup.domain.repository.TbInputDataXitRepository; +import cokr.xit.ens.biz.iup.domain.repository.TbInputXitRepository; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.TmpltMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.OrgMngRepository; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.TmpltMngRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.context.annotation.Profile; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +//@Component +@Transactional +@Profile({"local", "local-maria", "local-oracle"}) +public class JpaRunner implements ApplicationRunner { + + @PersistenceContext + EntityManager entityManager; + @Autowired + private FsJobRepository fsJobRepository; + @Autowired + private TbInputXitRepository tbInputXitRepository; + @Autowired + private TbInputDataXitRepository tbInputDataXitRepository; + @Autowired + private TbInputDataBulkTestRepository tbInputDataBulkTestRepository; + @Autowired + private OrgMngRepository orgMngRepository; + @Autowired + private TmpltMngRepository tmpltMngRepository; + + private final String REG_ID = "ENS_SYS"; + + private int DATA_UNIT = 100; + + @Override + public void run(ApplicationArguments args) throws Exception { + + + try { + /** + * IUP Sample 데이터 + */ + List fsJobList = getFsJob(); + List tbInputXitList = getTbInput(fsJobList.get(0)); + fsJobRepository.saveAll(fsJobList); +// tbInputXitRepository.saveAll(tbInputXitList); +// tbInputXitList.stream() +//// .parallel() +// .forEach(row -> +// tbInputDataXitRepository.saveAll(getTbInputData(row)) +// ); + + /** + * ENS Sample 데이터 + */ + List orgMngs = getOrgMng(); + orgMngRepository.saveAll(orgMngs); + tmpltMngRepository.saveAll(getTmpltMng(orgMngs)); + + } catch (Exception e) { + e.printStackTrace(); + } + + + /** + * Bulk Insert Test - use saveAll + */ +// tbInputDataBulkTestRepository.saveAll(getTbInputDataBulkTest(100000)); + /** + * Bulk Insert Test - use save + */ +// SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd"); +// String today = date.format(new Date()); +// +// for(int i=0; i< 100000; i++){ +// tbInputDataBulkTestRepository.save(getOneTbInputDataBulkTest(i, today)); +// } + } + + /** + * IUP + * + * @return + */ + private List getFsJob() { + + return Arrays.asList( + FsJob.builder().jobCd("E1001").orgCd("0005").jobName("민자고속도로 미납통행료 독촉장").templateCd("CEPHIS_001").useYn("Y").regId(REG_ID).build() + ); + } + + + /** + * IUP 발송마스터 생성 + * + * @return + */ + private List getTbInput(FsJob fsJob) { + List list = new ArrayList<>(); + SimpleDateFormat date = new SimpleDateFormat("yyyyMMddHHmmsss"); + for (int i = 1; i <= 4; i++) { + String today = date.format(new Date()); + list.add(cokr.xit.ens.biz.iup.domain.TbInputXit.builder() + .lnkInputId(Long.valueOf(today + ("" + i))) + .orgCd("0005") + .fsJob(fsJob) + .totCnt(Long.valueOf((DATA_UNIT * i))) + .prcsCd(IupPrcsCd.TGRG) + .errMsg(null) +// .runDt() + .expiresDt(LocalDateTime.of(2022, 2, 17, 15, 30, 00)) + .sendType(IupSendTypeCd.NI) + .regId(REG_ID) + .regDt(LocalDateTime.now()) + .runDt(LocalDateTime.now()) + .rcptDt(LocalDateTime.now().toString()) + .payExpiresDt(LocalDateTime.of(2022, 3, 17, 23, 59, 59)) + .build() + ); + } + + return list; + } + + /** + * IUP 발송상세 생성 + * + * @param tbInputXit + * @return + */ + private List getTbInputData(TbInputXit tbInputXit) { + List list = new ArrayList<>(); + + SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd"); + String today = date.format(new Date()); + + for (int i = 0; i < tbInputXit.getTotCnt().intValue(); i++) { + list.add(TbInputDataXit.builder() + .tbInputXit(tbInputXit) + .dataId(today + UUID.randomUUID()) +// .dataId(String.format("%s%012d",today, i)) + .sid("8611281234567") + .name("홍길동" + (i + 1)) + .birthday("19861128") + .gender("1") + .msgData("{\"~~@@!!CAR_NO!!@@~~\":\"60러5503\",\"~~@@!!DEGREE!!@@~~\":\"2\",\"~~@@!!FEE!!@@~~\":\"3,200\",\"~~@@!!YYYY!!@@~~\":\"2022\",\"~~@@!!MM!!@@~~\":\"03\",\"~~@@!!DD!!@@~~\":\"17\",\"~~@@!!BANK!!@@~~\":\"우체국\",\"~~@@!!ACCOUNT!!@@~~\":\"8608-90-80973468\",\"~~@@!!HISTORY!!@@~~\":\"-2022-01-08 17:19 (불암산 1,400)\n" + + "-2022-01-08 16:58 (양주 1,800)\",\"~~@@!!CALL_NO!!@@~~\":\"(031)522-6300~1\",\"~~@@!!HOMEPAGE!!@@~~\":\"https://seoulbeltway.co.kr/main/esccar.jsp\"}") + .msgDtlData(null) + .regId(REG_ID) + .regDt(java.sql.Date.valueOf(LocalDate.now())) + .payStatusCd("OK") + .payUrl(null) + .carNo("48나" + i) + .build() + ); + + } + + return list; + } + + /** + * IUP 발송상세 벌크 insert 생성 + * + * @return + */ + private List getTbInputDataBulkTest(int cnt) { + List list = new ArrayList<>(); + + SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd"); + String today = date.format(new Date()); + + for (int i = 0; i < cnt; i++) { + list.add(getOneTbInputDataBulkTest(i, today)); + } + + return list; + } + + private TbInputDataBulkTest getOneTbInputDataBulkTest(int i, String today) { + + return TbInputDataBulkTest.builder() + .dataId(today + UUID.randomUUID()) + .sid("8611281234567") + .name("홍길동" + (i + 1)) + .birthday("19861128") + .gender("1") + .msgData("{\"~~@@!!CAR_NO!!@@~~\":\"60러5503\",\"~~@@!!DEGREE!!@@~~\":\"2\",\"~~@@!!FEE!!@@~~\":\"3,200\",\"~~@@!!YYYY!!@@~~\":\"2022\",\"~~@@!!MM!!@@~~\":\"03\",\"~~@@!!DD!!@@~~\":\"17\",\"~~@@!!BANK!!@@~~\":\"우체국\",\"~~@@!!ACCOUNT!!@@~~\":\"8608-90-80973468\",\"~~@@!!HISTORY!!@@~~\":\"-2022-01-08 17:19 (불암산 1,400)\n" + + "-2022-01-08 16:58 (양주 1,800)\",\"~~@@!!CALL_NO!!@@~~\":\"(031)522-6300~1\",\"~~@@!!HOMEPAGE!!@@~~\":\"https://seoulbeltway.co.kr/main/esccar.jsp\"}") + .msgDtlData(null) + .regId(REG_ID) + .regDt(java.sql.Date.valueOf(LocalDate.now())) + .payStatusCd("OK") + .payUrl(null) + .carNo("48나" + i) + .build(); + } + + + private List getOrgMng() { + + return Arrays.asList( + OrgMng.builder() + .orgCd("0005") + .orgNm("단순미납기관") + .kkoBpCsignYn("N") + .build() + , OrgMng.builder() + .orgCd("0006") + .orgNm("강제징수기관") + .kkoBpCsignYn("N") + .build() + ); + } + + private List getTmpltMng(List orgMngs) { + List tmpltMngs = orgMngs.stream() + .map(orgMng -> TmpltMng.builder() +// .orgCd(orgCd) + .orgMng(orgMng) + .tmpltCd("CEPHIS_001") + .title("유료도로 미납통행료 1차 안내문") + .message("민자도로 관리지원센터에서 #{TARGET_NAME}님께 발송한 미납통행료 고지서가 도착했습니다.\n" + + "\n" + + "인천대교 미납통행료 1차 안내문\n" + + "\n" + + "□ 차량번호: #{CAR_NO}\n" + + "□ 노선명: 인천대교\n" + + "□ 미납통행일시\n" + + "#{HISTORY}\n" + + "□ 미납통행료: #{FEE}원\n" + + "□ 납부기한: #{YYYY}년 #{MM}월 #{DD}일까지\n" + + "□ 납부방법\n" + + "- 하단의 (납부하기) 클릭 또는\n" + + "- 가상계좌(#{BANK} #{ACCOUNT})\n" + + "□ 홈페이지 문의\n" + + "- #{HOMEPAGE}\n" + + "\n" + + "※ 본 모바일 알림톡은 유료도로법에 따라 민자도로 관리지원센터에서 통행료 수납을 위탁 받아 발송한 것이며, 알림톡 수신 시 종이고지서는 발송되지 않습니다.\n" + + "\n" + + "문의처 : #{REP_CALL_NO}") + .useYn("Y") + .registId("ENS_SYS") + .build()) + .collect(Collectors.toList()); + return tmpltMngs; + } +} diff --git a/src/main/java/cokr/xit/ens/core/jpa/dialect/MariaDB103DialectCustom.java b/src/main/java/cokr/xit/ens/core/jpa/dialect/MariaDB103DialectCustom.java new file mode 100644 index 0000000..004c2e2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/jpa/dialect/MariaDB103DialectCustom.java @@ -0,0 +1,16 @@ +package cokr.xit.ens.core.jpa.dialect; + +import org.hibernate.dialect.MariaDB103Dialect; +import org.hibernate.dialect.function.StandardSQLFunction; +import org.hibernate.type.StandardBasicTypes; + +public class MariaDB103DialectCustom extends MariaDB103Dialect { + + public MariaDB103DialectCustom() { + super(); + + registerFunction("ECL_DECRYPT", new StandardSQLFunction("ECL_DECRYPT", StandardBasicTypes.STRING)); + registerFunction("ECL_ENCRYPT", new StandardSQLFunction("ECL_ENCRYPT", StandardBasicTypes.STRING)); + registerFunction("GROUP_CONCAT", new StandardSQLFunction("group_concat", StandardBasicTypes.STRING)); + } +} diff --git a/src/main/java/cokr/xit/ens/core/jpa/dialect/Oracle10gDialectCustom.java b/src/main/java/cokr/xit/ens/core/jpa/dialect/Oracle10gDialectCustom.java new file mode 100644 index 0000000..6716818 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/jpa/dialect/Oracle10gDialectCustom.java @@ -0,0 +1,15 @@ +package cokr.xit.ens.core.jpa.dialect; + +import org.hibernate.dialect.Oracle10gDialect; +import org.hibernate.dialect.function.StandardSQLFunction; +import org.hibernate.type.StandardBasicTypes; + +public class Oracle10gDialectCustom extends Oracle10gDialect { + + public Oracle10gDialectCustom() { + super(); + + registerFunction("ECL_DECRYPT", new StandardSQLFunction("ECL_DECRYPT", StandardBasicTypes.STRING)); + registerFunction("ECL_ENCRYPT", new StandardSQLFunction("ECL_ENCRYPT", StandardBasicTypes.STRING)); + } +} diff --git a/src/main/java/cokr/xit/ens/core/jpa/support/BooleanToYnConverter.java b/src/main/java/cokr/xit/ens/core/jpa/support/BooleanToYnConverter.java new file mode 100644 index 0000000..7f298e4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/jpa/support/BooleanToYnConverter.java @@ -0,0 +1,18 @@ +package cokr.xit.ens.core.jpa.support; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +@Converter +public class BooleanToYnConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(Boolean attribute) { + return (attribute != null && attribute) ? "Y" : "N"; + } + + @Override + public Boolean convertToEntityAttribute(String yn) { + return "Y".equalsIgnoreCase(yn); + } +} diff --git a/src/main/java/cokr/xit/ens/core/mapstruct/GenericMapper.java b/src/main/java/cokr/xit/ens/core/mapstruct/GenericMapper.java new file mode 100644 index 0000000..4546561 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/mapstruct/GenericMapper.java @@ -0,0 +1,14 @@ +package cokr.xit.ens.core.mapstruct; + +import org.mapstruct.BeanMapping; +import org.mapstruct.MappingTarget; +import org.mapstruct.NullValuePropertyMappingStrategy; + +public interface GenericMapper { + + D toDto(E e); + E toEntity(D d); + + @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) + void updateFromDto(D dto, @MappingTarget E entity); +} diff --git a/src/main/java/cokr/xit/ens/core/mapstruct/StructMapperConfig.java b/src/main/java/cokr/xit/ens/core/mapstruct/StructMapperConfig.java new file mode 100644 index 0000000..443e974 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/mapstruct/StructMapperConfig.java @@ -0,0 +1,14 @@ +package cokr.xit.ens.core.mapstruct; + +import org.mapstruct.MapperConfig; +import org.mapstruct.ReportingPolicy; + +/** + * 특정 타입이나 객체간 매핑을 MapStruct 스스로할 수 없거나 다른 Mapper를 이용해야 한다면 'uses'를 사용할 수 있다. + * 'uses = JsonMapper.class'로 지정하면 객체에서 String으로 변환이 필요할 때 JsonMapper를 사용한다. + * spring bean으로 등록하기 위해 componentModel = "spring" 속성 필수 + * [참고사이트](https://ryanwoo.tistory.com/240) + */ +@MapperConfig(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) +public class StructMapperConfig { +} diff --git a/src/main/java/cokr/xit/ens/core/message/sample/presentation/KafkaSampleProducerController.java b/src/main/java/cokr/xit/ens/core/message/sample/presentation/KafkaSampleProducerController.java new file mode 100644 index 0000000..de4343b --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/message/sample/presentation/KafkaSampleProducerController.java @@ -0,0 +1,24 @@ +package cokr.xit.ens.core.message.sample.presentation; + +import cokr.xit.ens.core.message.sample.service.KafkaSampleProducerService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class KafkaSampleProducerController { + + @Autowired + private KafkaSampleProducerService kafkaSampleProducerService; + + @PostMapping(value = "/kafka/sample/push") + public void push(@RequestBody String message) { + kafkaSampleProducerService.sendMessage(message); + } + @PostMapping(value = "/kafka/sample/push/topic/{topicName}") + public void push(@PathVariable String topicName, @RequestBody String message) { + kafkaSampleProducerService.sendMessage(topicName, message); + } +} diff --git a/src/main/java/cokr/xit/ens/core/message/sample/service/KafkaSampleConsumerService.java b/src/main/java/cokr/xit/ens/core/message/sample/service/KafkaSampleConsumerService.java new file mode 100644 index 0000000..f4bbb7d --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/message/sample/service/KafkaSampleConsumerService.java @@ -0,0 +1,23 @@ +package cokr.xit.ens.core.message.sample.service; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.annotation.KafkaListener; + +import java.io.IOException; + +@Slf4j +//@Service +public class KafkaSampleConsumerService { + + + @KafkaListener(topics = "testTopic", groupId = "group-id-ens") + public void consumer1(String message) throws IOException { + log.info("[consumer1] receive message : " + message); + } + + @KafkaListener(topics = "testTopic2", groupId = "group-id-ens") + public void consumer2(String message) throws IOException { + log.info("[consumer2] receive message : " + message); + } + +} diff --git a/src/main/java/cokr/xit/ens/core/message/sample/service/KafkaSampleProducerService.java b/src/main/java/cokr/xit/ens/core/message/sample/service/KafkaSampleProducerService.java new file mode 100644 index 0000000..09c8056 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/message/sample/service/KafkaSampleProducerService.java @@ -0,0 +1,27 @@ +package cokr.xit.ens.core.message.sample.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Service; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class KafkaSampleProducerService { + + @Autowired + private KafkaTemplate kafkaTemplate; + + private final String TOPIC_NAME = "testTopic"; + + public void sendMessage(String message) { + log.info("send message : " + message); + this.kafkaTemplate.send(TOPIC_NAME, message); + } + public void sendMessage(String topicName, String message) { + log.info(String.format("[%s]send message : %s", topicName, message)); + this.kafkaTemplate.send(topicName, message); + } + +} diff --git a/src/main/java/cokr/xit/ens/core/model/EnsAcceptReqDTO.java b/src/main/java/cokr/xit/ens/core/model/EnsAcceptReqDTO.java new file mode 100644 index 0000000..ed7edbb --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/model/EnsAcceptReqDTO.java @@ -0,0 +1,46 @@ +package cokr.xit.ens.core.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; + +@SuperBuilder +@Getter +@Schema(name = "EnsAcceptReqDTO") +@NoArgsConstructor +public class EnsAcceptReqDTO { + + @Length(max = 30, message = "중개사업자의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "중개사업자", example = "dozn") + private String vender; + + @Length(max = 20, message = "기관코드의 최대 길이를 초과 했습니다.") + @NotEmpty(message = "기관코드는 필수 입력값 입니다.") + @Schema(required = true, title = "기관코드", example = "EX_ORG001") + private String org_cd; + + @Length(max = 30, message = "템플릿코드의 최대 길이를 초과 했습니다.") + @NotEmpty(message = "템플릿코드는 필수 입력값 입니다.") + @Schema(required = false, title = "템플릿코드", example = "EX_TMPLT001") + private String tmplt_cd; + + @Schema(required = false, title = "제목", example = " ") + private String post_bundle_title; + + @NotEmpty(message = "전송일시는 필수 입력값 입니다") + @Schema(required = true, title = "접수일시(yyyyMMddHHmmss)", example = "20220317192730") + private String send_dt; + + @NotEmpty(message = "마감일시는 필수 입력값 입니다") + @Schema(required = true, title = "마감일시(yyyyMMddHHmmss)", example = "20220317235959") + private String close_dt; + +// @Valid +// @NotEmpty(message = "문서목록은 필수 입력값 입니다") +// private List documents; + +} diff --git a/src/main/java/cokr/xit/ens/core/model/EnsBillAcptReqDTO.java b/src/main/java/cokr/xit/ens/core/model/EnsBillAcptReqDTO.java new file mode 100644 index 0000000..7c75b61 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/model/EnsBillAcptReqDTO.java @@ -0,0 +1,48 @@ +package cokr.xit.ens.core.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Builder +@Getter +@Setter +@Schema(name = "EnsBillAcptReqDTO") +public class EnsBillAcptReqDTO { + +// @NotNull(message = "청구서ID 사용 여부는 필수 입력값 입니다.") +// @Schema(hidden = true, required = true, title = "청구서ID 사용 여부", example = "false") +// private Boolean use_bill_uid; + + @Schema(hidden = true, required = false, title = "청구서 유니크ID", example = " ") + @JsonProperty("billUid") + @JsonAlias({"bill_uid"}) + @SerializedName(value = "billUid", alternate = {"bill_uid"}) + private String billUid; + + @NotNull(message = "청구서 타입은 필수 입력값 입니다.") + @Schema(required = true, title = "청구서 타입", example = "all") + @JsonProperty("billSe") + @JsonAlias({"bill_se"}) + @SerializedName(value = "billSe", alternate = {"bill_se"}) + private BillSeCd billSe; + + @NotBlank(message = "빌러유저키는 필수 입력값 입니다.") + @Length(max = 40, message = "빌러유저키의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "기관에서 관리하는 해당 고객번호 혹은 계약번호", example = " ") + @JsonProperty("billerUserKey") + @JsonAlias({"biller_user_key"}) + @SerializedName(value = "billerUserKey", alternate = {"biller_user_key"}) + private String billerUserKey; + + +} diff --git a/src/main/java/cokr/xit/ens/core/model/EnsRsltRespDTO.java b/src/main/java/cokr/xit/ens/core/model/EnsRsltRespDTO.java new file mode 100644 index 0000000..52d8dcc --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/model/EnsRsltRespDTO.java @@ -0,0 +1,32 @@ +package cokr.xit.ens.core.model; + +import cokr.xit.ens.modules.common.code.StatCd; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import javax.persistence.EnumType; +import javax.persistence.Enumerated; + +@SuperBuilder +@Getter +@Schema(name = "EnsRsltRespDTO") +@NoArgsConstructor +public class EnsRsltRespDTO { + @Schema(required = true, title = "상태정보", example = " ") + @Enumerated(EnumType.STRING) + private StatCd statCd; + @Schema(required = true, title = "기관코드", example = "EX_ORG001") + private String orgCd; + @Schema(required = false, title = "템플릿코드", example = "EX_TMPLT001") + private String tmpltCd; + @Schema(required = false, title = "제목", example = " ") + private String postBundleTitle; + @Schema(required = true, title = "접수일시(yyyyMMddHHmmss)", example = "20220317192730") + private String sendDt; + @Schema(required = true, title = "마감일시(yyyyMMddHHmmss)", example = "20220317235959") + private String closeDt; + @Schema(required = true, title = "마감여부", example = "false") + private Boolean closeAt; +} diff --git a/src/main/java/cokr/xit/ens/core/model/config/XitBaseProperty.java b/src/main/java/cokr/xit/ens/core/model/config/XitBaseProperty.java new file mode 100644 index 0000000..b61cfe9 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/model/config/XitBaseProperty.java @@ -0,0 +1,28 @@ +package cokr.xit.ens.core.model.config; + +import cokr.xit.ens.core.model.EnsBillAcptReqDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +@Getter +@SuperBuilder +@NoArgsConstructor +@Schema(name = "XitBaseProperty") +public class XitBaseProperty { + @Schema(required = false, title = "모바일페이지 노출 데이터", example = "{\"details\":[{\"title\":\"텍스트 타입\",\"item_type\":\"TEXT\",\"properties\":{\"use_toggle\":false,\"style\":{\"highlight\":{\"하하하\":{\"use-clipboard\":true,\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"}}},\"hyperlink\":[\"http://www.naver.com\",\"http://www.xit.co.kr\"]},\"elements\":[\"test\",\"하하하\"]},{\"title\":\"PRE 텍스트 타입\",\"item_type\":\"PRE_TEXT\",\"properties\":{\"use_toggle\":false,\"style\":{\"highlight\":{\"다라마\":{\"use-clipboard\":true,\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"},\"1111-23123-12313\":{\"use-clipboard\":false,\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"}}},\"hyperlink\":[\"http://www.naver.com\",\"http://www.xit.co.kr\"]},\"elements\":\"가나다라마\\r\\nABCDEFGHI\\n1234567890\\n1111-23123-12313 카카오\\n카카오뱅크\\nhttp://www.naver.com\"},{\"title\":\"키-밸류 타입\",\"item_type\":\"KEY_VALUE\",\"properties\":{\"use_toggle\":false,\"style\":{\"highlight\":{\"액\":{\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"}}},\"hyperlink\":[\"http://www.naver.com\",\"http://www.xit.co.kr\"]},\"elements\":[{\"key\":\"당월 부과 금액\",\"value\":\"200,203원\",\"level\":1},{\"key\":\"미납액\",\"value\":\"1,200원\",\"level\":1}]},{\"title\":\"테이블 타입\",\"item_type\":\"TABLE\",\"properties\":{\"use_toggle\":false,\"style\":{\"text_align\":[\"center\",\"left\",\"right\"],\"highlight\":{\"전기료\":{\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"}}},\"hyperlink\":[\"http://www.naver.com\",\"http://www.xit.co.kr\"]},\"elements\":{\"head\":[\"항목\",\"당월금액\",\"전월대비\"],\"rows\":[[\"전기료\",\"1,000,000원\",\"+500,000\"],[\"수도료\",\"300,000원\",\"-100,000\"]]}},{\"title\":\"이미지 타입\",\"item_type\":\"IMAGE\",\"print_type\":\"이미지출력타입(공백: img태그(default), SLIDE: 슬라이드 기능 적용)\",\"properties\":{\"use_toggle\":false},\"elements\":[{\"key\":\"링크 이미지\",\"value\":\"http://www.xit.co.kr/....\"},{\"key\":\"Base64 이미지\",\"value\":\"data:image/png;base64,iVBORw0KGgoAAAAN....\"}]},{\"title\":\"링크버튼 타입\",\"item_type\":\"BUTTON\",\"link_url\":\"https://www.naver.com\"},{\"title\":\"결제버튼 타입\",\"item_type\":\"PAY_BUTTON\"}]}") + private Map>> mbl_page_data; + + @Schema(required = false, title = "템플릿 메시지 데이터", example = "{\"#{TARGET_NAME}\":\"홍길동\",\"#{CAR_NO}\":\"12더1234\",\"#{HISTORY}\":\"2022-01-01\",\"#{FEE}\":\"1000\",\"#{YYYY}\":\"2022\",\"#{MM}\":\"03\",\"#{DD}\":\"30\",\"#{BANK}\":\"기업\",\"#{ACCOUNT}\":\"311-063233-01-123\",\"#{HOMEPAGE}\":\"http://www.xit.co.kr\",\"#{REP_CALL_NO}\":\"070-4490-7404\"}") + private Map tmplt_msg_data; + + @Valid + private EnsBillAcptReqDTO bill_acpt_data; + + +} diff --git a/src/main/java/cokr/xit/ens/core/monitor/Message.java b/src/main/java/cokr/xit/ens/core/monitor/Message.java new file mode 100644 index 0000000..1892435 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/monitor/Message.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.core.monitor; + +public interface Message { + String create(); +} diff --git a/src/main/java/cokr/xit/ens/core/monitor/slack/SlackMessage.java b/src/main/java/cokr/xit/ens/core/monitor/slack/SlackMessage.java new file mode 100644 index 0000000..233edd3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/monitor/slack/SlackMessage.java @@ -0,0 +1,40 @@ +package cokr.xit.ens.core.monitor.slack; + +import cokr.xit.ens.core.monitor.slack.struct.SlackSenderStrategy; +import cokr.xit.ens.core.monitor.slack.support.ChannelGetter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Slf4j +@RequiredArgsConstructor +@Component +public class SlackMessage { + + @Value("${slack.token}") + private String TOKEN; + @Value("${slack.api.users}") + private String API_USERS; + @Value("${slack.recev.emails}") + private List emails; + + public void send(SlackSenderStrategy sender) { + for (String email : emails) { + try { + sender.execute(TOKEN, ChannelGetter.builder() + .TOKEN(TOKEN) + .API_URL(API_USERS) + .email(email) + .build() + .execute()); + } catch (Exception e) { + log.info("Slack 전송 실패", e); + } + } + } + + ; +} diff --git a/src/main/java/cokr/xit/ens/core/monitor/slack/event/MonitorEvent.java b/src/main/java/cokr/xit/ens/core/monitor/slack/event/MonitorEvent.java new file mode 100644 index 0000000..5a1c0a1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/monitor/slack/event/MonitorEvent.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.core.monitor.slack.event; + +import cokr.xit.ens.core.monitor.Message; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class MonitorEvent { + + private Message message; +} diff --git a/src/main/java/cokr/xit/ens/core/monitor/slack/event/MonitorEventListener.java b/src/main/java/cokr/xit/ens/core/monitor/slack/event/MonitorEventListener.java new file mode 100644 index 0000000..bf80b90 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/monitor/slack/event/MonitorEventListener.java @@ -0,0 +1,30 @@ +package cokr.xit.ens.core.monitor.slack.event; + +import cokr.xit.ens.core.monitor.slack.support.MessageSender; +import cokr.xit.ens.core.monitor.slack.SlackMessage; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.event.EventListener; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class MonitorEventListener { + @Value("${slack.api.chat}") + private String API_CHAT; + private final SlackMessage slackMessage; + + @Order(1) + @EventListener +// @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void send(MonitorEvent event) { + slackMessage.send(MessageSender.builder() + .API_URL(this.API_CHAT) + .message(event.getMessage().create()) + .build()); + } + +} diff --git a/src/main/java/cokr/xit/ens/core/monitor/slack/struct/SlackSenderStrategy.java b/src/main/java/cokr/xit/ens/core/monitor/slack/struct/SlackSenderStrategy.java new file mode 100644 index 0000000..40cbd75 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/monitor/slack/struct/SlackSenderStrategy.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.core.monitor.slack.struct; + +public interface SlackSenderStrategy { + void execute(String token, String channel); +} diff --git a/src/main/java/cokr/xit/ens/core/monitor/slack/struct/SlackSenderTemplate.java b/src/main/java/cokr/xit/ens/core/monitor/slack/struct/SlackSenderTemplate.java new file mode 100644 index 0000000..2d4f732 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/monitor/slack/struct/SlackSenderTemplate.java @@ -0,0 +1,28 @@ +package cokr.xit.ens.core.monitor.slack.struct; + +import cokr.xit.ens.core.utils.MapDeserailizer; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.experimental.SuperBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.entity.ContentType; +import org.springframework.http.HttpHeaders; + +import java.util.Map; + +@Slf4j +@SuperBuilder +public abstract class SlackSenderTemplate implements SlackSenderStrategy { + + protected String API_URL; + + protected final Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).disableHtmlEscaping().create(); + + protected HttpHeaders createHeaders(ContentType contentType, String token) { + HttpHeaders headers = new HttpHeaders(); + headers.add("Authorization", "Bearer " + token); + headers.add("Content-type", contentType.toString()); + return headers; + } + +} diff --git a/src/main/java/cokr/xit/ens/core/monitor/slack/support/ChannelGetter.java b/src/main/java/cokr/xit/ens/core/monitor/slack/support/ChannelGetter.java new file mode 100644 index 0000000..4ceb2e0 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/monitor/slack/support/ChannelGetter.java @@ -0,0 +1,58 @@ +package cokr.xit.ens.core.monitor.slack.support; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.utils.MapDeserailizer; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.Builder; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.entity.ContentType; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +@Slf4j +@Builder +public class ChannelGetter { + + private String TOKEN; + private String API_URL; + private String email; + + + public String execute() { + + RestTemplate restTemplate = new RestTemplate(); + HttpEntity requestEntity = new HttpEntity<>(this.createHeaders(ContentType.APPLICATION_FORM_URLENCODED)); + ResponseEntity responseEntity = restTemplate.exchange(String.format("%s?email=%s", API_URL, email), HttpMethod.GET, requestEntity, String.class); + log.info("===================================================================="); + log.info("==== Slack getSlackId Response... ===="); + log.info(String.format("[ HttpStatusCode %d ]", responseEntity.getStatusCode().value())); + log.info(responseEntity.getBody()); + log.info("===================================================================="); + + Map result = gson.fromJson(responseEntity.getBody(), Map.class); + if(!CmmnUtil.isEmpty(result.get("error"))) + throw new EnsException(EnsErrCd.ERR620, String.format("Slack ID 조회 실패. %s [ email %s API_URL %s TOKEN %s ]", (String) result.get("error"), email, API_URL, TOKEN) ); + + Map profile = (Map) result.get("user"); + String id = profile.get("id"); + return id; + + } + + protected final Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).disableHtmlEscaping().create(); + + protected HttpHeaders createHeaders(ContentType contentType) { + HttpHeaders headers = new HttpHeaders(); + headers.add("Authorization", "Bearer " + TOKEN); + headers.add("Content-type", contentType.toString()); + return headers; + } +} diff --git a/src/main/java/cokr/xit/ens/core/monitor/slack/support/ImageSender.java b/src/main/java/cokr/xit/ens/core/monitor/slack/support/ImageSender.java new file mode 100644 index 0000000..e93fa45 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/monitor/slack/support/ImageSender.java @@ -0,0 +1,51 @@ +package cokr.xit.ens.core.monitor.slack.support; + +import cokr.xit.ens.core.monitor.slack.struct.SlackSenderTemplate; +import lombok.experimental.SuperBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.entity.ContentType; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@SuperBuilder +public class ImageSender extends SlackSenderTemplate { + + private String pretext; + private String message; + private String imgUrl; + + + @Override + public void execute(String token, String channel) { + Map params = new HashMap<>(); + params.put("channel", channel); + Map attachment = new HashMap<>(); + attachment.put("pretext", pretext); + attachment.put("text", message); + attachment.put("image_url", imgUrl); + List> attachments = new ArrayList<>(); + attachments.add(attachment); + params.put("attachments", attachments); + String body = gson.toJson(params); + + + HttpEntity requestEntity = new HttpEntity<>(body, this.createHeaders(ContentType.APPLICATION_JSON, token)); + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity responseEntity = restTemplate.exchange(this.API_URL, HttpMethod.POST, requestEntity, String.class); + log.info("===================================================================="); + log.info("==== Slack Send-Photo Response... ===="); + log.info(String.format("[ HttpStatusCode %d ]", responseEntity.getStatusCode().value())); + log.info(responseEntity.getBody()); + log.info("===================================================================="); + + } + +} diff --git a/src/main/java/cokr/xit/ens/core/monitor/slack/support/MessageSender.java b/src/main/java/cokr/xit/ens/core/monitor/slack/support/MessageSender.java new file mode 100644 index 0000000..c06baac --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/monitor/slack/support/MessageSender.java @@ -0,0 +1,43 @@ +package cokr.xit.ens.core.monitor.slack.support; + +import cokr.xit.ens.core.monitor.slack.struct.SlackSenderTemplate; +import lombok.experimental.SuperBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.entity.ContentType; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@SuperBuilder +public class MessageSender extends SlackSenderTemplate { + + private String message; + + + @Override + public void execute(String token, String channel) { + + Map params = new HashMap<>(); + params.put("channel", channel); + params.put("text", message); + String body = gson.toJson(params); + + + HttpEntity requestEntity = new HttpEntity<>(body, this.createHeaders(ContentType.APPLICATION_JSON, token)); + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity responseEntity = restTemplate.exchange(API_URL, HttpMethod.POST, requestEntity, String.class); + log.info("===================================================================="); + log.info("==== Slack Send-Message Response... ===="); + log.info(String.format("[ HttpStatusCode %d ]", responseEntity.getStatusCode().value())); + log.info(responseEntity.getBody()); + log.info("===================================================================="); + } + + + +} diff --git a/src/main/java/cokr/xit/ens/core/repository/MybatisCrudSupport.java b/src/main/java/cokr/xit/ens/core/repository/MybatisCrudSupport.java new file mode 100644 index 0000000..5933c66 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/repository/MybatisCrudSupport.java @@ -0,0 +1,13 @@ +package cokr.xit.ens.core.repository; + +import java.util.List; +import java.util.Optional; + +public interface MybatisCrudSupport { + + List findAll(P p); + Optional findById(ID id); + int add(P p); + int modify(P p); + int remove(P p); +} diff --git a/src/main/java/cokr/xit/ens/core/repository/SpringDataJdbcRepository.java b/src/main/java/cokr/xit/ens/core/repository/SpringDataJdbcRepository.java new file mode 100644 index 0000000..5f4bbab --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/repository/SpringDataJdbcRepository.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.core.repository; + +import java.util.List; + +public interface SpringDataJdbcRepository { + + + public void saveAll(List list); +} diff --git a/src/main/java/cokr/xit/ens/core/repository/SpringDataJdbcRepositoryImpl.java b/src/main/java/cokr/xit/ens/core/repository/SpringDataJdbcRepositoryImpl.java new file mode 100644 index 0000000..3a5fda8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/repository/SpringDataJdbcRepositoryImpl.java @@ -0,0 +1,73 @@ +package cokr.xit.ens.core.repository; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.List; + + +@Slf4j +@Repository +@RequiredArgsConstructor +public class SpringDataJdbcRepositoryImpl implements SpringDataJdbcRepository { + + private final JdbcTemplate jdbcTemplate; + @Value("${spring.jpa.properties.hibernate.jdbc.batch_size}") + private int BATCH_SIZE; + + + @Override + public void saveAll(List list) { + int batchCount = 0; + List subItems = new ArrayList<>(); + for (int i = 0; i < list.size(); i++) { + subItems.add(list.get(i)); + if ((i + 1) % BATCH_SIZE == 0) { + batchCount = batchInsert(batchCount, subItems); + } + } + if (!subItems.isEmpty()) { + batchCount = batchInsert(batchCount, subItems); + } + log.info("batchCount: " + batchCount); + } + + + private int batchInsert(int batchCount, List list) { + +// jdbcTemplate.batchUpdate("INSERT INTO tb_input_data_bulk_test (birthday, car_no, data_id, gender, msg_data, msg_dtl_data, name, pay_status_cd, pay_url, reg_dt, reg_id, sid, upd_dt, upd_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", +// new BatchPreparedStatementSetter() { +// +// @Override +// public void setValues(PreparedStatement ps, int i) throws SQLException { +// ps.setString(1, list.get(i).getBirthday()); +// ps.setString(2, list.get(i).getCarNo()); +// ps.setString(3, list.get(i).getDataId()); +// ps.setString(4, list.get(i).getGender()); +// ps.setString(5, list.get(i).getMsgData()); +// ps.setString(6, list.get(i).getMsgDtlData()); +// ps.setString(7, list.get(i).getName()); +// ps.setString(8, list.get(i).getPayStatusCd()); +// ps.setString(9, list.get(i).getPayUrl()); +// ps.setDate(10, list.get(i).getRegDt()); +// ps.setString(11, list.get(i).getRegId()); +// ps.setString(12, list.get(i).getSid()); +// ps.setDate(13, list.get(i).getUpdDt()); +// ps.setString(14, list.get(i).getUpdId()); +//// ps.setLong(15, list.get(i).getId()); +// } +// @Override +// public int getBatchSize() { +// return list.size(); +// } +// }); + list.clear(); + batchCount++; + return batchCount; + } + +} diff --git a/src/main/java/cokr/xit/ens/core/utils/ApplicationContextProvider.java b/src/main/java/cokr/xit/ens/core/utils/ApplicationContextProvider.java new file mode 100644 index 0000000..d03c545 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/ApplicationContextProvider.java @@ -0,0 +1,21 @@ +package cokr.xit.ens.core.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +@Component +public class ApplicationContextProvider implements ApplicationContextAware { + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext ctx) throws BeansException { + applicationContext = ctx; + } + + + public static ApplicationContext getApplicationContext() { + return applicationContext; + } +} diff --git a/src/main/java/cokr/xit/ens/core/utils/BeanUtils.java b/src/main/java/cokr/xit/ens/core/utils/BeanUtils.java new file mode 100644 index 0000000..888826c --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/BeanUtils.java @@ -0,0 +1,17 @@ +package cokr.xit.ens.core.utils; + +import org.springframework.context.ApplicationContext; + +public class BeanUtils { + + + public static T getBean(Class type) { + ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext(); + + if (applicationContext == null) { + throw new NullPointerException("no Initialize \"ApplicationContext\""); + } + + return applicationContext.getBean(type); + } +} diff --git a/src/main/java/cokr/xit/ens/core/utils/Checks.java b/src/main/java/cokr/xit/ens/core/utils/Checks.java new file mode 100644 index 0000000..2fd0b4e --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/Checks.java @@ -0,0 +1,151 @@ +package cokr.xit.ens.core.utils; + +import java.util.Iterator; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Checks { + /** + * val이 null이 아니면 그대로 리턴, 아니면 defVal + * + * @param val T + * @param defVal T + * @return T + */ + public static T checkVal(T val, T defVal) { + return (isNotNull(val) ? val : defVal); + } + + /** + * val이 Empty가 아니면 그대로 리턴, 아니면 defVal (Empty는 배열이나 Map도 가능) + * + * @param val T + * @param defVal T + * @return T + */ + public static T checkEmptyVal(T val, T defVal) { + return (isNotEmpty(val) ? val : defVal); + } + + /** + * expression이 true이면 val, 아니면 defVal + * + * @param expression boolean + * @param tVal T + * @param fVal T + * @return T + */ + public static T checkVal(boolean expression, T tVal, T fVal) { + return (expression ? tVal : fVal); + } + + + public static boolean isNull(Object checkValue) { + return !isNotNull(checkValue); + } + + public static boolean isNotNull(Object checkValue) { + return checkValue != null; + } + + public static boolean isEmpty(Object checkValue) { + return !isNotEmpty(checkValue); + } + + public static boolean isNotEmpty(Object checkValue) { + if (isNotNull(checkValue)) { + + if (checkValue instanceof String) { + return !((String) checkValue).isEmpty(); + } else if (checkValue instanceof Iterator) { + return ((Iterator) checkValue).hasNext(); + } else if (checkValue instanceof Iterable) { + return ((Iterable) checkValue).iterator().hasNext(); + } else if (checkValue instanceof Map) { + return !((Map) checkValue).isEmpty(); + } +// else if ( checkValue instanceof DataSetMap ) { +// return !( ( DataSetMap ) checkValue ).isEmpty(); +// } + + if (checkValue.getClass().isArray()) { + return ((Object[]) checkValue).length != 0; + } else { + + return true; + } + } + + return false; + } + + public static boolean isNumeric(String str) { + if (Checks.isEmpty(str)) + return false; + + return str.matches("-?\\d+(.\\d+)?"); + } + + public static boolean isInstance(Object checkValue, Class... classes) { + if (isNotNull(checkValue)) { + for (Class clazz : classes) { + if (clazz.isInstance(checkValue)) { + return true; + } + } + } + + return false; + } + + /** + * email형식 체크 + * + * @param str + * @return + * @메소드 : isCheckEmail + */ + public static boolean isCheckEmail(String str) { + if (Checks.isEmpty(str)) + return false; + + String regex = "^([\\w-]+(?:\\.[\\w-]+)*)@((?:[\\w-]+\\.)*\\w[\\w-]{0,66})\\.([a-z]{2,6}(?:\\.[a-z]{2})?)$"; + Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + + Matcher matcher = pattern.matcher(str); + return matcher.find(); + } + + /** + * 전화형식 체크 + * + * @param str + * @return + * @메소드 : isCheckTel + */ + public static boolean isCheckTel(String str) { + if (Checks.isEmpty(str)) + return false; + + String regex = "^\\d[\\d-]+\\d$"; + Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE); + + Matcher matcher = pattern.matcher(str); + return matcher.find(); + } + + /** + * 주민번호 체크 + * + * @param jid + * @return + */ + public static boolean isCheckJid(String jid) { + if (jid == null) return false; + + String regex = "\\d{2}([0]\\d|[1][0-2])([0][1-9]|[1-2]\\d|[3][0-1])[1-8]\\d{6}"; + + return Pattern.matches(regex, jid); + } +} diff --git a/src/main/java/cokr/xit/ens/core/utils/CmmnUtil.java b/src/main/java/cokr/xit/ens/core/utils/CmmnUtil.java new file mode 100644 index 0000000..2aa3e53 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/CmmnUtil.java @@ -0,0 +1,230 @@ + +package cokr.xit.ens.core.utils; + +import cokr.xit.ens.core.exception.code.EnsErrCd; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import javax.servlet.http.HttpServletRequest; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +public class CmmnUtil { + +// private final static Logger logger = LoggerFactory.getLogger(CmmnUtil.class); + + + /** + *
메소드 설명: API 호출
+     * 	-.반환결과
+     * 	:result => 결과 코드(OK: 정상, others: 오류)
+     * 	:resultMsg	=> 결과 메시지
+     * 	:responseEntity => api 응답 메시지
+     * 
+ * + * @param method + * @param url + * @param param + * @param headers + * @return Map 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 4. + */ + public static Map callApi(HttpMethod method, String url, String param, HttpHeaders headers) { + log.debug("param ======================="); + log.debug(param); + + + Map resultMap = new HashMap(); + ResponseEntity responseEntity = null; + String result = EnsErrCd.OK.getCode(); + String resultMsg = EnsErrCd.OK.getCodeNm(); + + try { + + HttpEntity entity = null; + UriComponents uri = null; + switch (method) { + case GET: + entity = new HttpEntity<>(headers); + uri = UriComponentsBuilder + .fromHttpUrl(String.format("%s?%s", url, param)) + .encode() + .build(); + break; + case POST: + entity = new HttpEntity<>(param, headers); + uri = UriComponentsBuilder + .fromHttpUrl(url) + .encode() + .build(); + break; + + default: + break; + } + + + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + factory.setConnectTimeout(3000); + factory.setReadTimeout(3000); + RestTemplate restTemplate = new RestTemplate(factory); + responseEntity = restTemplate.exchange(uri.toString(), method, entity, String.class); + + +// 코드: responseEntity.getStatusCodeValue() +// 메시지: responseEntity.getStatusCode() + } catch ( + HttpServerErrorException e) { + result = EnsErrCd.ERR501.getCode(); + resultMsg = String.format("%s [사유: %s]", EnsErrCd.ERR501.getCodeNm(), e.getMessage()); + log.error(String.format("call API 서버오류[url =>%s param => %s error => %s]", url, param, e.getMessage())); + } catch ( + HttpClientErrorException e) { + result = EnsErrCd.ERR502.getCode(); + resultMsg = String.format("%s [사유: %s]", EnsErrCd.ERR502.getCodeNm(), e.getMessage()); + log.error(String.format("call API 클라이언트오류[url =>%s param => %s error => %s]", url, param, e.getMessage())); + } catch (RestClientException e) { + result = EnsErrCd.ERR503.getCode(); + resultMsg = String.format("%s [사유: %s]", EnsErrCd.ERR503.getCodeNm(), e.getMessage()); + log.error(String.format("RestAPI 호출 오류[url =>%s param => %s error => %s]", url, param, e.getMessage())); + } catch (Exception e) { + result = EnsErrCd.ERR999.getCode(); + resultMsg = String.format("%s [사유: %s]", EnsErrCd.ERR999.getCodeNm(), e.getMessage()); + log.error(String.format("call API 기타오류[url =>%s param => %s error => %s]", url, param, e.getMessage())); + } + + + + resultMap.put("resCd", result); + resultMap.put("resMsg", resultMsg); + resultMap.put("responseEntity", responseEntity); + return resultMap; + } + + + /** + *
메소드 설명: 객체를 Json 포맷 String으로 반환 한다.
+ * + * @param obj + * @return String 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 5. + */ + public static String toJsonString(Object obj) { + return toJsonString(obj, JsonInclude.Include.ALWAYS); + } + + /** + *
메소드 설명: 객체를 Json 포맷 String으로 반환 한다.
+ * + * @param obj + * @param type JsonInclude.Include + *
+     *                                     [type 종류]
+     *                                     	ALWAYS: 모든 필드
+     *                                     	NON_NULL: null제외
+     *                                      NON_ABSENT: null제외
+     *                                      NON_EMPTY: null/absent/isEmpty()==true/lenth==0 제외
+     *                                      NON_DEFAULT: empty는 제외된다.primitive 타입이 디폴트 값이면 제외한다. (int / Integer : 0 , boolean / Boolean : false 등)
+     *                                     
+ * @return String 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 5. + */ + public static String toJsonString(Object obj, JsonInclude.Include type) { + String result = null; + + try { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(type); + result = mapper.writeValueAsString(obj); + } catch (JsonProcessingException e) { +// throw new CustomException(RESP_CODE.INTERNAL_SERVER_ERROR, String.format("obj -> jsonString converting fail:: %s", e.getMessage())); + throw new RuntimeException(String.format("obj -> jsonString converting fail:: %s", e.getMessage()), e); + } + + return result; + } +// /** +// *
메소드 설명: jsonString을 Object로 반환한다
+// * @param clz +// * @param jsonStr +// * @return Object 요청처리 후 응답객체 +// * @author: 박민규 +// * @date: 2021. 12. 23. +// */ +// public static Object jsonStringtoObj(Class clz, String jsonStr) { +// Object result = null; +// +// try { +// ObjectMapper mapper = new ObjectMapper(); +// result = mapper.readValue(jsonStr, clz.getClass()); +// } catch (JsonProcessingException e) { +// throw new RuntimeException(String.format("jsonString -> obj converting fail:: %s", e.getMessage()), e); +// } +// +// return result; +// } + + public static boolean isEmpty(Object obj) { + if (obj == null) return true; + if ((obj instanceof String) && (((String) obj).trim().length() == 0)) { + return true; + } + if (obj instanceof Map) { + return ((Map) obj).isEmpty(); + } + if (obj instanceof Map) { + return ((Map) obj).isEmpty(); + } + if (obj instanceof List) { + return ((List) obj).isEmpty(); + } + if (obj instanceof Object[]) { + return (((Object[]) obj).length == 0); + } + + return false; + } + + + public static String getServerUrl() { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + + return String.format("%s://%s:%s", request.getScheme(), request.getServerName(), request.getServerPort()); + } + + public static String printStackTraceToString(Exception e) { + try { + StringWriter errors = new StringWriter(); + e.printStackTrace(new PrintWriter(errors)); + + return errors.toString(); + } catch (Exception ex) { + return "printStackTrace 변환에 실패 했습니다. " + ex.getMessage(); + } + } + + +} diff --git a/src/main/java/cokr/xit/ens/core/utils/DateUtil.java b/src/main/java/cokr/xit/ens/core/utils/DateUtil.java new file mode 100644 index 0000000..ae46ec6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/DateUtil.java @@ -0,0 +1,410 @@ + +package cokr.xit.ens.core.utils; + +import lombok.extern.slf4j.Slf4j; + +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Calendar; +import java.util.Date; +import java.util.Optional; + +@Slf4j +public class DateUtil { + + + /** + *
메소드 설명: 절대시간(단위: milliesecond)을 현재 시간으로 반환 한다.
+ * + * @param millisec + * @param fmt + * @return String 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 19. + */ + public static String absTimeMillisecToDate(Long millisec, String fmt) { + if (millisec == null) + return null; + return absTimeToDate(millisec, fmt); + } + + /** + *
메소드 설명: 절대시간(단위: second)을 현재 시간으로 반환 한다.
+ * + * @param sec + * @param fmt + * @return String 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 19. + */ + public static String absTimeSecToDate(int sec, String fmt) { + return absTimeSecToDate(sec * 1L, fmt); + } + + /** + *
메소드 설명: 절대시간(단위: second)을 현재 시간으로 반환 한다.
+ * + * @param sec + * @param fmt + * @return String 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 19. + */ + public static String absTimeSecToDate(Long sec, String fmt) { + if (sec == null) + return null; + return absTimeToDate(sec * 1000L, fmt); + } + + /** + *
메소드 설명: 절대시간(단위: ms)을 현재 시간으로 반환 한다.
+ * + * @param millionSec + * @param fmt + * @return String 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 19. + */ + public static String absTimeToDate(Long millionSec, String fmt) { + if (fmt == null || "".equals(fmt)) fmt = "yyyy-MM-dd HH:mm:ss"; + + Date date = new Date(millionSec); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(fmt); + + return simpleDateFormat.format(date); + } + + + /** + *
메소드 설명: 시간을 절대시간(단위: sec)로 반환 한다.
+ * + * @param expireDt 만료일시(yyyyMMddHHmmss) + * @return Long 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 19. + */ + public static Long dateToAbsTimeSec(String expireDt) { + return dateToAbsTime(expireDt) / 1000; + } + + /** + *
메소드 설명: 시간을 절대시간(단위: sec)로 반환 한다.
+ * + * @param year + * @param month + * @param day + * @param hour + * @param minute + * @param sec + * @return Long 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 19. + */ + public static Long dateToAbsTimeSec(int year, int month, int day, int hour, int minute, int sec) { + return dateToAbsTime(year, month, day, hour, minute, sec) / 1000; + } + + /** + *
메소드 설명: 시간을 절대시간(단위: ms)로 반환 한다.
+ * + * @param expireDt 만료일시(yyyyMMddHHmmss) + * @return Long 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 19. + */ + @SuppressWarnings("finally") + public static Long dateToAbsTime(String expireDt) { + if (expireDt == null) + return 0L; + + expireDt = expireDt.replaceAll("[^0-9]", ""); + if ("".equals(expireDt)) + return 0L; + + int year, month, day, hour, minute, sec; + year = month = day = hour = minute = sec = 0; + try { + year = Integer.parseInt(expireDt.substring(0, 4)); + month = Integer.parseInt(expireDt.substring(4, 6)); + day = Integer.parseInt(expireDt.substring(6, 8)); + hour = Integer.parseInt(expireDt.substring(8, 10)); + minute = Integer.parseInt(expireDt.substring(10, 12)); + sec = Integer.parseInt(expireDt.substring(12, 14)); + } catch (Exception e) { + log.error(String.format("dateToAbsTime fail... expireDt is [%s]", expireDt)); + } finally { + return dateToAbsTime(year, month, day, hour, minute, sec); + } + + } + + /** + *
메소드 설명: 시간을 절대시간(단위: ms)로 반환 한다.
+ * + * @param year + * @param month + * @param day + * @param hour + * @param minute + * @param sec + * @return Long 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 19. + */ + @SuppressWarnings("deprecation") + public static Long dateToAbsTime(int year, int month, int day, int hour, int minute, int sec) { + if (month < 0) month = 1; + if (month > 11) month = 12; + if (day < 1 || day > 31) day = 1; + if (hour < 0 || hour > 23) hour = 0; + if (minute < 0 || minute > 59) minute = 0; + if (sec < 0 || sec > 59) sec = 0; + + Date curDate = new Date(year - 1900, month - 1, day, hour, minute, sec); + return curDate.getTime(); + } + + + /** + *
메소드 설명: 시간을 상대시간(단위: ms)로 반환 한다.
+ * + * @param expireDt 만료일시(yyyyMMddHHmmss) + * @return Long 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 19. + */ + @SuppressWarnings("finally") + public static Long dateToRelTime(String expireDt) { + if (expireDt == null) + return 0L; + + expireDt = expireDt.replaceAll("[^0-9]", ""); + if ("".equals(expireDt)) + return 0L; + + int year, month, day, hour, minute, sec; + year = month = day = hour = minute = sec = 0; + try { + year = Integer.parseInt(expireDt.substring(0, 4)); + month = Integer.parseInt(expireDt.substring(4, 6)); + day = Integer.parseInt(expireDt.substring(6, 8)); + hour = Integer.parseInt(expireDt.substring(8, 10)); + minute = Integer.parseInt(expireDt.substring(10, 12)); + sec = Integer.parseInt(expireDt.substring(12, 14)); + } catch (Exception e) { + log.error(String.format("dateToRelTime fail... expireDt is [%s]", expireDt)); + } finally { + return dateToRelTime(year, month, day, hour, minute, sec); + } + + } + + /** + *
메소드 설명: 시간을 상대시간(단위: ms)로 반환 한다.
+ * + * @param year + * @param month + * @param day + * @param hour + * @param minute + * @param sec + * @return Long 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 19. + */ + @SuppressWarnings("deprecation") + public static Long dateToRelTime(int year, int month, int day, int hour, int minute, int sec) { + if (month < 0) month = 1; + if (month > 11) month = 12; + if (day < 1 || day > 31) day = 1; + if (hour < 0 || hour > 23) hour = 0; + if (minute < 0 || minute > 59) minute = 0; + if (sec < 0 || sec > 59) sec = 0; + + return dateToRelTime(LocalDateTime.of(year, month, day, hour, minute, sec)); + } + + /** + *
메소드 설명: 시간을 상대시간(단위: ms)로 반환 한다.
+ * + * @param date + * @return Long 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 19. + */ + public static Long dateToRelTime(LocalDateTime date) { + + Long fromDateMs = DateUtil.dateToAbsTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); + Long toDateMs = DateUtil.dateToAbsTime(date.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); + + return toDateMs - fromDateMs; + } + + /** + *
메소드 설명: 일수를 상대시간(단위: ms)로 반환 한다.
+ * + * @param days + * @return Long 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 11. 19. + */ + public static Long daysToRelTime(int days) { + if (days < 0) days = 0; + return days * 24L * 60L * 60L * 1000L; + } + + /** + *
메소드 설명: 일시(yyyyMMddHHmmss)를 LocalDateTime 으로 반환 한다.
+ * + * @param yyyyMMddHHmmss + * @return Long 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2022. 3. 15. + */ + public static LocalDateTime toLocalDateTime(String yyyyMMddHHmmss) { + String date = Optional.ofNullable(yyyyMMddHHmmss).orElseGet(() -> null); + + if (date == null) return null; + + date = date.replaceAll("[^0-9]", ""); + if (date.length() != 14) + return null; + + + return LocalDateTime.of( + Integer.parseInt(date.substring(0, 4)) + , Integer.parseInt(date.substring(4, 6)) + , Integer.parseInt(date.substring(6, 8)) + , Integer.parseInt(date.substring(8, 10)) + , Integer.parseInt(date.substring(10, 12)) + , Integer.parseInt(date.substring(12, 14)) + ); + } + + + /** + * 날짜(date) 사이의 간격을 계산하여 일자(day)로 반환 한다. + * + * @param fromDate + * @param toDate + * @return + */ + public static int daysByFromBetweenTo(Date fromDate, Date toDate) { + return daysByFromBetweenTo(fromDate.getTime(), toDate.getTime()); + } + + /** + * 날짜(date) 사이의 간격을 계산하여 일자(day)로 반환 한다. + * + * @param fromDate + * @param toDate + * @return + */ + public static int daysByFromBetweenTo(LocalDateTime fromDate, LocalDateTime toDate) { + return daysByFromBetweenTo(Timestamp.valueOf(fromDate).getTime(), Timestamp.valueOf(toDate).getTime()); + } + + /** + * 초(sec) 사이의 간격을 계산하여 일자(day)로 반환 한다. + * + * @param fromSec + * @param toSec + * @return + */ + public static int daysByFromBetweenTo(int fromSec, int toSec) { + return daysByFromBetweenTo(fromSec * 1000L, toSec * 1000L); + } + + /** + * 밀리초(ms) 사이의 간격을 계산하여 일자(day)로 반환 한다. + * + * @param fromMs + * @param toMs + * @return + */ + public static int daysByFromBetweenTo(long fromMs, long toMs) { + return (int) ((toMs - fromMs) / (24 * 60 * 60 * 1000)); + } + + /** + * 밀리초(ms) 사이의 간격을 계산하여 초(second)로 반환 한다. + * + * @param fromDate + * @param toDate + * @toDate + */ + public static int secByFromBetweenTo(LocalDateTime fromDate, LocalDateTime toDate) { + return secByFromBetweenTo(Timestamp.valueOf(fromDate).getTime(), Timestamp.valueOf(toDate).getTime()); + } + + /** + * 밀리초(ms) 사이의 간격을 계산하여 초(second)로 반환 한다. + * + * @param fromMs + * @param toMs + * @return + */ + public static int secByFromBetweenTo(long fromMs, long toMs) { + return (int) ((toMs - fromMs) / (1000)); + } + + + /** + * 초(sec)를 일수(day)로 반환 한다. + * + * @return + */ + public static int secToDays(int sec) { + return msToDays(sec * 1000L); + } + + /** + * 밀리초(ms)를 일수(day)로 반환 한다. + * + * @return + */ + public static int msToDays(long ms) { + return (int) (ms / (24 * 60 * 60 * 1000)); + } + + + /** + * 현재날짜에 초(sec)를 더한 날짜를 반환 한다. + * + * @param sec + * @param pattern + * @return + */ + public static String relTimeSecToDate(int sec, String pattern) { + if ("".equals(pattern) || pattern == null) + pattern = "yyyyMMdd"; + + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis((sec * 1000L) + (new Date().getTime())); + Date date = calendar.getTime(); + + return new SimpleDateFormat(pattern).format(date); + } + + /** + * 특정날짜에 초(sec)를 더한 날짜를 반환 한다. + * + * @param sec + * @param pattern + * @return + */ + public static String addRelTimeSecToDate(LocalDateTime localDateTime, int sec, String pattern) { + if ("".equals(pattern) || pattern == null) + pattern = "yyyyMMdd"; + + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis((sec * 1000L) + Timestamp.valueOf(localDateTime).getTime()); + Date date = calendar.getTime(); + + return new SimpleDateFormat(pattern).format(date); + } + + +} diff --git a/src/main/java/cokr/xit/ens/core/utils/IdGenerator.java b/src/main/java/cokr/xit/ens/core/utils/IdGenerator.java new file mode 100644 index 0000000..0a164bc --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/IdGenerator.java @@ -0,0 +1,92 @@ +package cokr.xit.ens.core.utils; + +import net.bytebuddy.utility.RandomString; + +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +public class IdGenerator { + + private static AtomicReference currentTime = new AtomicReference<>(System.currentTimeMillis()); + + public static Long getCurrentTimeMs() { + Long prev; + Long next = System.currentTimeMillis(); + do { + prev = currentTime.get(); + next = next > prev ? next : prev + 1; + } while (!currentTime.compareAndSet(prev, next)); + return next; + } + + public static Long getCurrentTimeSec() { + return IdGenerator.getCurrentTimeMs() / 1000L; + } + + public static String getRandomString(int length) { + return RandomString.make(length); + } + + public static String getUUID() { + return UUID.randomUUID().toString(); + } + + public static String getUUID(String prefix) { + return prefix + "-" + getUUID(); + } + + public static String getUUID(String prefix, String postfix) { + return getUUID(prefix) + "-" + postfix; + + } + + private static AtomicLong atomicCounter = new AtomicLong(); + + public static String getUUIDwithCount() { + String currentCounter = String.valueOf(atomicCounter.getAndIncrement()); + String uniqueId = UUID.randomUUID().toString(); + + return uniqueId + "-" + currentCounter; + } + + public static String getUUIDwithCount(String prefix) { + return prefix + "-" + getUUIDwithCount(); + } + + public static String getUUIDwithCount(String prefix, String postfix) { + return getUUIDwithCount(prefix) + "-" + postfix; + } + + public static String getShortUUID() { + UUID u = UUID.randomUUID(); + return toIDString(u.getMostSignificantBits()) + toIDString(u.getLeastSignificantBits()); + } + + public static String getShortUUID(String prefix) { + return prefix + "-" + getShortUUID(); + } + + public static String getShortUUID(String prefix, String postfix) { + return getShortUUID(prefix) + "-" + postfix; + } + + private static String toIDString(long i) { + char[] buf = new char[32]; + int z = 64; + int cp = 32; + long b = z - 1; + do { + buf[--cp] = DIGITS66[(int) (i & b)]; + i >>>= 6; + } while (i != 0); + return new String(buf, cp, (32 - cp)); + } + + + private final static char[] DIGITS66 = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '-', '.', '_', '~' + }; +} diff --git a/src/main/java/cokr/xit/ens/core/utils/JwtUtil.java b/src/main/java/cokr/xit/ens/core/utils/JwtUtil.java new file mode 100644 index 0000000..af9efcc --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/JwtUtil.java @@ -0,0 +1,112 @@ +package cokr.xit.ens.core.utils; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.Claim; +import lombok.Builder; +import lombok.Getter; +import org.springframework.util.StringUtils; + +import java.util.Base64; +import java.util.Base64.Decoder; +import java.util.Date; +import java.util.Iterator; +import java.util.Map; + +@Getter +public class JwtUtil { + + @SuppressWarnings("unused") + public final static String DEFAULT_SECRET_KEY = "czovL3d3dy50ZXN0LmNvLmtyIiwicm9sZX"; + + private String token; + + private String header; + private String payload; + + private boolean isCertified = false; + private Map claims; + + @SuppressWarnings("deprecation") + @Builder(builderClassName = "createBuilder", builderMethodName = "createBuilder") + public JwtUtil(String secretKey, String iss, String sub, String aud, Date exp, Date nbf, Date iat, String jti, String uUuid, String[] roles) { + if (StringUtils.isEmpty(secretKey)) + throw new RuntimeException("SecretKey(은)는 필수조건 입니다."); + + this.token = JWT.create() + .withIssuer(iss) + .withSubject(sub) + .withAudience(aud) + .withExpiresAt(exp) + .withNotBefore(nbf) + .withIssuedAt(iat) + .withJWTId(jti) + .withClaim("uUuid", uUuid) + .withArrayClaim("roles", roles) + .sign(Algorithm.HMAC512(secretKey.getBytes())); + } + + + @Builder(builderClassName = "decodeBuilder", builderMethodName = "decodeBuilder") + public JwtUtil(String jwt) { + + Decoder decoder = Base64.getDecoder(); + final String[] splitJwt = jwt.split("\\."); + this.token = jwt; + this.header = new String(decoder.decode(splitJwt[0].getBytes())); + this.payload = new String(decoder.decode(splitJwt[1].getBytes())); + } + + + @Builder(builderClassName = "verifyBuilder", builderMethodName = "verifyBuilder") + public JwtUtil(String secretKey, String jwt) { + this.verify(secretKey, jwt, Algorithm.HMAC512(secretKey.getBytes())); + } + + @Builder(builderClassName = "verifyBuilderByAlgorithm", builderMethodName = "verifyBuilderByAlgorithm") + public JwtUtil(String secretKey, String token, Algorithm algorithm) { + this.verify(secretKey, token, algorithm); + } + + @SuppressWarnings("deprecation") + private void verify(String secretKey, String jwt, Algorithm algorithm) { + if (StringUtils.isEmpty(secretKey)) + throw new RuntimeException("SecretKey(은)는 필수조건 입니다."); + + try { + System.out.println(String.format("[Token] => %s", jwt)); + this.claims = JWT.require(algorithm) + .build() + .verify(jwt.replace("Bearer", "").trim()) + .getClaims(); + + this.isCertified = true; + } catch (Exception e) { + this.isCertified = false; + System.out.println(String.format("Token Verify Fail... %s", e.getMessage())); + } + } + + public void claimsToString() { + System.out.println("[Token Claims]"); + if (this.claims == null) + return; + + Iterator it = this.claims.keySet().iterator(); + while (it.hasNext()) { + String key = it.next(); + Claim claim = this.claims.get(key); +// System.out.println(String.format(" %s = %s", key, claim.asString())); + if (claim.asMap() != null) + System.out.println(String.format(" %s = %s", key, claim.asMap().toString())); + else if (claim.asArray(String.class) != null) { + StringBuilder sb = new StringBuilder(); + for (String str : claim.asArray(String.class)) + sb.append(",").append(str); + System.out.println(String.format(" %s = [%s]", key, sb.toString().substring(1))); + } else + System.out.println(String.format(" %s = %s", key, claim.as(String.class))); + } + } + +} diff --git a/src/main/java/cokr/xit/ens/core/utils/MapDeserailizer.java b/src/main/java/cokr/xit/ens/core/utils/MapDeserailizer.java new file mode 100644 index 0000000..92b0d9b --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/MapDeserailizer.java @@ -0,0 +1,58 @@ +package cokr.xit.ens.core.utils; + +import com.google.gson.*; + +import java.lang.reflect.Type; +import java.util.*; + +public class MapDeserailizer implements JsonDeserializer> { + + @Override + @SuppressWarnings("unchecked") + public Map deserialize(JsonElement json, Type typeOfT, + JsonDeserializationContext context) throws JsonParseException { + return (Map) read(json); + } + + public Object read(JsonElement in) { + if (in.isJsonArray()) { + + List list = new ArrayList(); + JsonArray arr = in.getAsJsonArray(); + for (JsonElement anArr : arr) { + + list.add(read(anArr)); + } + return list; + } else if (in.isJsonObject()) { + Map map = new HashMap(); + JsonObject obj = in.getAsJsonObject(); + Set> entitySet = obj.entrySet(); + for (Map.Entry entry : entitySet) { + + map.put(entry.getKey(), read(entry.getValue())); + } + return map; + } else if (in.isJsonPrimitive()) { + JsonPrimitive prim = in.getAsJsonPrimitive(); + if (prim.isBoolean()) { + + return prim.getAsBoolean(); + } else if (prim.isString()) { + + return prim.getAsString(); + } else if (prim.isNumber()) { + Number num = prim.getAsNumber(); + + if (Math.ceil(num.doubleValue()) == num.longValue()) + + return num.longValue(); + else { + + return num.doubleValue(); + } + } + } + return null; + } +} diff --git a/src/main/java/cokr/xit/ens/core/utils/RequireValidator.java b/src/main/java/cokr/xit/ens/core/utils/RequireValidator.java new file mode 100644 index 0000000..2725c00 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/RequireValidator.java @@ -0,0 +1,79 @@ +package cokr.xit.ens.core.utils; + +import lombok.Builder; +import lombok.Getter; +import org.springframework.util.StringUtils; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +@Builder +@Getter +public class RequireValidator { + + private Object obj; + + private List message = new ArrayList<>(); + + + /** + *
메소드 설명: 객체 검증
+     * 	-.검증을 통과하지 못한 필드의 메시지를 message 필드에 설정한다.
+     * 
+ * + * @return RequireValidator 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 6. + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + public RequireValidator validate() { + Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + Set> validate = validator.validate(this.obj); + + if (!validate.isEmpty()) { + this.message = new ArrayList(); + + Iterator it = validate.iterator(); + while (it.hasNext()) { + ConstraintViolation cv = (ConstraintViolation) it.next(); + this.message.add(cv.getMessage()); + } + } + + + return this; + } + + + /** + *
메소드 설명: Exception 발생
+     * 	-.message가 null이 아닐 경우 Exception을 발생 시킨다.
+     * 
+ * void 요청처리 후 응답객체 + * + * @author: 박민규 + * @date: 2021. 8. 6. + */ + @SuppressWarnings("deprecation") + public RequireValidator throwableException() { + if (!StringUtils.isEmpty(this.message)) +// throw new CustomException(RESP_CODE.INVALID_PARAMETER, message.toString()); + throw new RuntimeException(String.format("유효성 검증 Fail::: %s", message.toString())); + + return this; + } + + @Override + public String toString() { + if (!StringUtils.isEmpty(this.message)) + return message.toString(); + else + return null; + } + +} diff --git a/src/main/java/cokr/xit/ens/core/utils/crypto/AES256.java b/src/main/java/cokr/xit/ens/core/utils/crypto/AES256.java new file mode 100644 index 0000000..2366437 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/crypto/AES256.java @@ -0,0 +1,70 @@ +package cokr.xit.ens.core.utils.crypto; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.Key; + +@Slf4j +public class AES256 { + private String scretKey; + private String iv; + private Key keySpec; + + + public AES256(String key) { + this.scretKey = key.substring(0, 32); + this.iv = key.substring(0, 16); + byte[] keyBytes = new byte[16]; + try { + byte[] b = scretKey.getBytes("UTF-8"); + int len = b.length; + if (len > keyBytes.length) { + len = keyBytes.length; + } + System.arraycopy(b, 0, keyBytes, 0, len); + } catch (Exception e) { + e.printStackTrace(); + } + SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); + + this.keySpec = keySpec; + + } + + public String encrypt(String str) { + if (str == null || "".equals(str)) return str; + try { + Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); + c.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv.getBytes())); + + byte[] encrypted = c.doFinal(str.getBytes("UTF-8")); + String encStr = new String(Base64.encodeBase64(encrypted)); + return encStr; + + } catch (Exception e) { + log.error("AES encode fail. {}", e.getMessage()); + e.printStackTrace(); + return str; + } + } + + public String decrypt(String str) { + if (str == null || "".equals(str)) return str; + try { + Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); + c.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv.getBytes())); + byte[] byteStr = Base64.decodeBase64(str.getBytes()); + String decStr = new String(c.doFinal(byteStr), "UTF-8"); + return decStr; + + } catch (Exception e) { + log.error("AES decode fail. {}", e.getMessage()); + e.printStackTrace(); + return str; + } + } +} diff --git a/src/main/java/cokr/xit/ens/core/utils/crypto/Crypto.java b/src/main/java/cokr/xit/ens/core/utils/crypto/Crypto.java new file mode 100644 index 0000000..5a79588 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/crypto/Crypto.java @@ -0,0 +1,16 @@ +package cokr.xit.ens.core.utils.crypto; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum Crypto { + AES256("0e1n2s3e4n5c6r7y8p9t256secretkey"); + + public String getCode() { + return this.name(); + } + + @Getter + private final String key; +} diff --git a/src/main/java/cokr/xit/ens/core/utils/crypto/SHA256.java b/src/main/java/cokr/xit/ens/core/utils/crypto/SHA256.java new file mode 100644 index 0000000..33e07f8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/crypto/SHA256.java @@ -0,0 +1,52 @@ +package cokr.xit.ens.core.utils.crypto; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class SHA256 { + + public static String encrypt(String text) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(text.getBytes()); + + return bytesToHex(md.digest()); + } + + private static String bytesToHex(byte[] bytes) { + StringBuilder builder = new StringBuilder(); + for (byte b : bytes) { + builder.append(String.format("%02x", b)); + } + return builder.toString(); + } + +// public static String encryptV2(String raw) throws NoSuchAlgorithmException { +// +// +//// String raw = "password1234"; +// String hex = ""; +// +// +// SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); +// byte[] bytes = new byte[16]; +// random.nextBytes(bytes); +// +// String salt = new String(Base64.getEncoder().encode(bytes)); +// String rawAndSalt = raw + salt; +// +// System.out.println("raw : " + raw); +// System.out.println("salt : " + salt); +// +// MessageDigest md = MessageDigest.getInstance("SHA-256"); +// +// md.update(raw.getBytes()); +// hex = String.format("%064x", new BigInteger(1, md.digest())); +// System.out.println("raw의 해시값 : " + hex); +// +// +// md.update(rawAndSalt.getBytes()); +// hex = String.format("%064x", new BigInteger(1, md.digest())); +// System.out.println("raw+salt의 해시값 : " + hex); +// return hex; +// } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/modules/IndexController.java b/src/main/java/cokr/xit/ens/modules/IndexController.java new file mode 100644 index 0000000..7cee2e5 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/IndexController.java @@ -0,0 +1,39 @@ +package cokr.xit.ens.modules; + +import cokr.xit.ens.core.aop.repository.AccessLogRepository; +import cokr.xit.ens.core.code.CodeMapperFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Slf4j +@Controller +@RequiredArgsConstructor +public class IndexController { + + private final AccessLogRepository accessLogRepository; + private final CodeMapperFactory codeMapperFactory; + + @GetMapping("/") + public String index() { +// log.info("Welcome to the world!!"); +// codeMapperFactory.get(SampleCd.class).forEach((row) -> System.out.println(row.getCode()+"="+row.getCodeNm())); +// Queue q = new LinkedList(); +// for(int i=1; i<=100; i++) { +// q.offer(i); +// if(i%10==0) +// System.out.println(String.format("poll => %d", q.poll())); +// } +// q.forEach(i -> System.out.println("value => "+i)); +// for(int i=101; i<=200; i++) { +// q.offer(i); +// if(i%10==0) +// System.out.println(String.format("poll => %d", q.poll())); +// } +// q.forEach(i -> System.out.println("value => "+i)); + + return "index"; + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/biztmplt/CleanRepositorySupport.java b/src/main/java/cokr/xit/ens/modules/common/biztmplt/CleanRepositorySupport.java new file mode 100644 index 0000000..bf0bf20 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/biztmplt/CleanRepositorySupport.java @@ -0,0 +1,11 @@ +package cokr.xit.ens.modules.common.biztmplt; + +import javax.transaction.Transactional; + +public interface CleanRepositorySupport { + + @Transactional + void truncate(); + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/biztmplt/EnsPhaseProcSupport.java b/src/main/java/cokr/xit/ens/modules/common/biztmplt/EnsPhaseProcSupport.java new file mode 100644 index 0000000..a7e84be --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/biztmplt/EnsPhaseProcSupport.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.modules.common.biztmplt; + +import java.util.List; + +public interface EnsPhaseProcSupport { + + T statReady(List

args); + + T statBegin(P arg); + + T execute(P arg); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/biztmplt/MakeProcTemplate.java b/src/main/java/cokr/xit/ens/modules/common/biztmplt/MakeProcTemplate.java new file mode 100644 index 0000000..a00710a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/biztmplt/MakeProcTemplate.java @@ -0,0 +1,104 @@ +package cokr.xit.ens.modules.common.biztmplt; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.domain.SendMast; +import cokr.xit.ens.modules.common.domain.repository.SendMastRepository; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Component +public abstract class MakeProcTemplate implements EnsPhaseProcSupport { + + @Autowired + private SendMastRepository sendMastRepository; + + + /** + * 제작준비 + * @param sendMastIds + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List sendMastIds){ + EnsResponseVO respVO = null; + try { + /** + * 필수값 확인 + */ + if (CmmnUtil.isEmpty(sendMastIds)) + throw new EnsException(EnsErrCd.MAKE410, "발송마스터ID(은)는 필수조건 입니다."); + + /** + * 저장 + * -. 발송마스터의 상태를 "제작준비(makerdy)" 으로 변경 한다. + */ + List resultInfo = sendMastRepository.findAllBySendMastIdIn(sendMastIds).stream() + .map(row -> { + row.setStatCd(StatCd.makerdy); + return row.getSendMastId(); + }) + .collect(Collectors.toList()); + ; + + respVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } catch (EnsException e) { + + respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(); + } catch (Exception e) { + + respVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.MAKE500).errMsg(e.getMessage()).build(); + } + + return respVO; + } + + + /** + * 제작시작 + * @param sendMastId + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(Long sendMastId) { + + EnsResponseVO respVO = null; + try { + /** + * 필수값 확인 + */ + if (CmmnUtil.isEmpty(sendMastId)) + throw new EnsException(EnsErrCd.MAKE410, "발송마스터ID(은)는 필수조건 입니다."); + + /** + * 저장 + * -. 발송마스터의 상태를 "제작중(making)" 으로 변경 한다. + */ + SendMast sendMast = sendMastRepository.findById(sendMastId).orElseThrow(()->new EnsException(EnsErrCd.MAKE404, String.format("일치하는 발송마스터 자료가 없습니다. [ sendMastId %s ]", sendMastId))); + sendMast.setStatCd(StatCd.making); + + + respVO = EnsResponseVO.okBuilder().resultInfo(sendMastId).build(); + } catch (EnsException e) { + + respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(); + } catch (Exception e) { + + respVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.MAKE500).errMsg(e.getMessage()).build(); + } + + return respVO; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/biztmplt/ResultProcTemplate.java b/src/main/java/cokr/xit/ens/modules/common/biztmplt/ResultProcTemplate.java new file mode 100644 index 0000000..a9d55b1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/biztmplt/ResultProcTemplate.java @@ -0,0 +1,40 @@ +package cokr.xit.ens.modules.common.biztmplt; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Slf4j +@Component +public abstract class ResultProcTemplate implements EnsPhaseProcSupport { + + + /** + * 갱신준비 + * @param sendMastIds + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List sendMastIds){ + log.info("no process"); + return null; + } + + + /** + * 갱신시작 + * @param sendMastId + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(Long sendMastId) { + log.info("no process"); + return null; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/biztmplt/SendDetailRepositorySupport.java b/src/main/java/cokr/xit/ens/modules/common/biztmplt/SendDetailRepositorySupport.java new file mode 100644 index 0000000..56c378d --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/biztmplt/SendDetailRepositorySupport.java @@ -0,0 +1,10 @@ +package cokr.xit.ens.modules.common.biztmplt; + +import java.util.List; + +public interface SendDetailRepositorySupport { + +// List findAllFetchBySendMastIdAndMkBillUseYAndUrlIsNull(Long sendMastId, boolean urlIsNull); + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/biztmplt/SendProcTemplate.java b/src/main/java/cokr/xit/ens/modules/common/biztmplt/SendProcTemplate.java new file mode 100644 index 0000000..f7b2d35 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/biztmplt/SendProcTemplate.java @@ -0,0 +1,104 @@ +package cokr.xit.ens.modules.common.biztmplt; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.domain.SendMast; +import cokr.xit.ens.modules.common.domain.repository.SendMastRepository; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Component +public abstract class SendProcTemplate implements EnsPhaseProcSupport { + + @Autowired + private SendMastRepository sendMastRepository; + + + /** + * 전송준비 + * @param sendMastIds + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List sendMastIds){ + EnsResponseVO respVO = null; + try { + /** + * 필수값 확인 + */ + if (CmmnUtil.isEmpty(sendMastIds)) + throw new EnsException(EnsErrCd.SEND410, "발송마스터ID(은)는 필수조건 입니다."); + + /** + * 저장 + * -. 발송마스터의 상태를 "전송준비(sendrdy)" 으로 변경 한다. + */ + List resultInfo = sendMastRepository.findAllBySendMastIdIn(sendMastIds).stream() + .map(row -> { + row.setStatCd(StatCd.sendrdy); + return row.getSendMastId(); + }) + .collect(Collectors.toList()); + ; + + respVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } catch (EnsException e) { + + respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(); + } catch (Exception e) { + + respVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.SEND500).errMsg(e.getMessage()).build(); + } + + return respVO; + } + + + /** + * 전송시작 + * @param sendMastId + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(Long sendMastId) { + + EnsResponseVO respVO = null; + try { + /** + * 필수값 확인 + */ + if (CmmnUtil.isEmpty(sendMastId)) + throw new EnsException(EnsErrCd.SEND410, "발송마스터ID(은)는 필수조건 입니다."); + + /** + * 저장 + * -. 발송마스터의 상태를 "전송중(sending)" 으로 변경 한다. + */ + SendMast sendMast = sendMastRepository.findById(sendMastId).orElseThrow(()->new EnsException(EnsErrCd.SEND404, String.format("일치하는 발송마스터 자료가 없습니다. [ sendMastId %s ]", sendMastId))); + sendMast.setStatCd(StatCd.sending); + + + respVO = EnsResponseVO.okBuilder().resultInfo(sendMastId).build(); + } catch (EnsException e) { + + respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(); + } catch (Exception e) { + + respVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.SEND500).errMsg(e.getMessage()).build(); + } + + return respVO; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/code/IntgrnDtlStatCd.java b/src/main/java/cokr/xit/ens/modules/common/code/IntgrnDtlStatCd.java new file mode 100644 index 0000000..19ccf07 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/code/IntgrnDtlStatCd.java @@ -0,0 +1,98 @@ +package cokr.xit.ens.modules.common.code; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + *

    + *
  • 업무 그룹명: 진행상태코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2021. 11. 23. 오후 5:10:35 + *
+ * + * @author 박민규 + */ +@RequiredArgsConstructor +public enum IntgrnDtlStatCd implements IntgrnDtlStatMapperType { + UNKNOWN("알수없음") + + + , REG("등록") + , MAKING("제작") + + , ACPT_OK("접수요청성공") + , ACPT_FAIL("접수실패") + , ACPT_CMPLT("접수완료") + + + , UNIDENTIFIED_USER("비회원") + , FORBIDDEN("수신거부") + , INVALID_VALUE("파라미터 오류") +// , INTERNAL_ERROR("카카오페이 서버 오류") + , INTERNAL_ERROR("API 서버 내부 오류") + , INVALID_REQUEST("유효하지 않은 요청") + , FORBIDDEN_USER("허용되지 않은 사용자") + + , FAIL("전송실패") + , SENT("송신") + , RECEIVED("수신") + , READ("열람") + , EXPIRED("만료") + ; + + + @Getter + private final String codeNm; + + @Override + public String getCode() { + return this.name(); + } + + + @Override + public IntgrnDtlStatCd getIntgrnDtlStatCd() { + return this; + } + + + public boolean isSuccess() { + switch (this) { + case SENT: + case RECEIVED: + case READ: + case EXPIRED: + return true; + default: + return false; + } + } + + public boolean isFail() { + switch (this) { + case ACPT_FAIL: + case UNIDENTIFIED_USER: + case FORBIDDEN: + case INVALID_VALUE: + case INTERNAL_ERROR: + case INVALID_REQUEST: + case FORBIDDEN_USER: + case FAIL: + return true; + default: + return false; + } + } + + public static List getFails() { + List list = new ArrayList<>(); + for (IntgrnDtlStatCd value : IntgrnDtlStatCd.values()) { + if (value.isFail()) + list.add(value); + } + return list; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/code/IntgrnDtlStatMapperType.java b/src/main/java/cokr/xit/ens/modules/common/code/IntgrnDtlStatMapperType.java new file mode 100644 index 0000000..7aad9c4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/code/IntgrnDtlStatMapperType.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.modules.common.code; + +import cokr.xit.ens.core.code.CodeMapperType; + +public interface IntgrnDtlStatMapperType extends CodeMapperType { + IntgrnDtlStatCd getIntgrnDtlStatCd(); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/code/PostSeCd.java b/src/main/java/cokr/xit/ens/modules/common/code/PostSeCd.java new file mode 100644 index 0000000..431bba6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/code/PostSeCd.java @@ -0,0 +1,27 @@ +package cokr.xit.ens.modules.common.code; + +import cokr.xit.ens.core.code.CodeMapperType; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum PostSeCd implements CodeMapperType { + + testMblPage("모바일페이지 테스트") + ,intgrnNoti("통합 전자고지") + ,kkoMydoc("카카오페이 내문서함(인증톡)") + ,kkoAlimtalk("카카오페이 알림톡") + ,nvSigntalk("네이버 고지서(인증톡)") + ,ktSigntalk("KT 인증톡") + ,ktGibis("KT 인증톡(지비스)"); + + + @Getter + private final String codeNm; + + @Override + public String getCode() { + return this.name(); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/code/StatCd.java b/src/main/java/cokr/xit/ens/modules/common/code/StatCd.java new file mode 100644 index 0000000..73131df --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/code/StatCd.java @@ -0,0 +1,37 @@ +package cokr.xit.ens.modules.common.code; + +import cokr.xit.ens.core.code.CodeMapperType; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum StatCd implements CodeMapperType { + + accept("접수") + + , makerdy("제작준비") + , making("제작중") + , makeok("제작성공") + , makefail("제작실패") + + , sendrdy("전송준비") + , sending("전송중") + , sendok("전송성공") + , sendfail("전송실패") + + , sendcmplt("전송완료") + + , open("열람중") + + , close("조회기간마감") + ; + + @Getter + private final String codeNm; + + @Override + public String getCode() { + return this.name(); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/code/UseNativeQuery.java b/src/main/java/cokr/xit/ens/modules/common/code/UseNativeQuery.java new file mode 100644 index 0000000..4d8bb70 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/code/UseNativeQuery.java @@ -0,0 +1,40 @@ +package cokr.xit.ens.modules.common.code; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * Native Query를 사용하는 테이블을 관리한다. + */ +@RequiredArgsConstructor +public enum UseNativeQuery { + IntgrnSendDetail("ens_intgrn_snd_dtl") + ,SendDetailKkoMydoc("ens_snd_dtl_kko_md") + ,SendDetailNvSigntalk("ens_snd_dtl_nv_st") + ,SendDetailKtSigntalk("ens_snd_dtl_kt_st") + ,SendDetailKtGibis("ens_snd_dtl_kt_gbs") + + + ,SendDetailKkoAlimtalkReqHist("ens_snd_dtl_kko_at_req_his") + ,SendDetailKkoAlimtalkRsltHist("ens_snd_dtl_kko_at_rslt_his") + + ,SendDetailKkoMydocReqHist("ens_snd_dtl_kko_md_req_his") + ,SendDetailKkoMydocStatHist("ens_snd_dtl_kko_md_stat_his") + ,SendDetailKkoMydocTokenHist("ens_snd_dtl_kko_md_ott_his") + + ,SendDetailNvSigntalkReqHist("ens_snd_dtl_nv_st_req_his") + ,SendDetailNvSigntalkStatHist("ens_snd_dtl_nv_st_stat_his") + ,SendDetailNvSigntalkTokenHist("ens_snd_dtl_nv_st_ott_his") + + ,SendDetailKtSigntalkReqHist("ens_snd_dtl_kt_st_req_his") + ,SendDetailKtSigntalkStatHist("ens_snd_dtl_kt_st_stat_his") + ,SendDetailKtSigntalkTokenHist("ens_snd_dtl_kt_st_ott_his") + + ,SendDetailKtGibisReqHist("ens_snd_dtl_kt_gbs_req_his") + ,SendDetailKtGibisStatHist("ens_snd_dtl_kt_gbs_stat_his") + ,SendDetailKtGibisTokenHist("ens_snd_dtl_kt_gbs_ott_his") + ; + + @Getter + private final String tblNm; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/code/VenderCd.java b/src/main/java/cokr/xit/ens/modules/common/code/VenderCd.java new file mode 100644 index 0000000..cb30813 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/code/VenderCd.java @@ -0,0 +1,39 @@ +package cokr.xit.ens.modules.common.code; + +import cokr.xit.ens.core.code.CodeMapperType; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum VenderCd implements CodeMapperType { + + none("입력없음") + ,unknown("알수없음") + ,intech("아이앤텍") + ,biztalk("비즈톡") + ,dozn("더즌") + ; + + @Getter + private final String codeNm; + + @Override + public String getCode() { + return this.name(); + } + + + public static VenderCd valueOfEnum(String statCd){ + if(statCd == null) + return VenderCd.none; + + VenderCd docBoxStatusCd = null; + try { + docBoxStatusCd = VenderCd.valueOf(statCd.toLowerCase()); + } catch (IllegalArgumentException e){ + docBoxStatusCd = VenderCd.unknown; + } + return docBoxStatusCd; + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoPayApi.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoPayApi.java new file mode 100644 index 0000000..47d9840 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoPayApi.java @@ -0,0 +1,166 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.api; + +import cokr.xit.ens.core.utils.CmmnUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; +import org.springframework.http.*; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import java.net.URI; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +@Slf4j +@Component +@Profile({"!local-test"}) +public class BillKkoPayApi implements BillKkoPayApiSpec { + + @Value("${contract.kakao.pay.bill.dozn.host}") + private String HOST; + @Value("${contract.kakao.pay.bill.dozn.api.url}") + private String API_URL; + @Value("${contract.kakao.pay.bill.dozn.api.reurl}") + private String API_RE_URL; + + + /** + *
메소드 설명: API 호출
+     * 
+ * + * @param method + * @param url + * @param body + * @param headers + * @return ResponseEntity 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 4. + */ + private ResponseEntity callApi(HttpMethod method, String url, String body, HttpHeaders headers) { + + StringBuffer sb = new StringBuffer(); + ResponseEntity responseEntity = null; + try { + + HttpEntity entity = null; + UriComponents uri = null; + switch (method) { + case GET: + entity = new HttpEntity<>(headers); + uri = UriComponentsBuilder + .fromHttpUrl(String.format("%s?%s", url, body == null ? "" : body)) +// .encode(StandardCharsets.UTF_8) //"%"기호가 "%25"로 인코딩 발생하여 주석처리 함. + .build(false); + break; + case POST: + entity = new HttpEntity<>(body, headers); + uri = UriComponentsBuilder + .fromHttpUrl(url) + .encode(StandardCharsets.UTF_8) + .build(); + break; + + default: + break; + } + + + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + factory.setConnectTimeout(5000); + factory.setReadTimeout(60000); + RestTemplate restTemplate = new RestTemplate(factory); + sb.append("\n url => " + uri.toString()) + .append("\n method => " + method) + .append("\n headers => " + entity.getHeaders().toString()) + .append("\n body => " + entity.getBody()); + responseEntity = restTemplate.exchange(URI.create(uri.toString()), method, entity, String.class); + + /* + * HttpStatus 정보 확인 방법 + * -.코드: responseEntity.getStatusCodeValue() + * -.메시지: responseEntity.getStatusCode() + */ + + } catch (HttpServerErrorException e) { + responseEntity = new ResponseEntity(e.getResponseBodyAsString(), e.getStatusCode()); + log.error("call API 서버오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } catch (HttpClientErrorException e) { + responseEntity = new ResponseEntity(e.getResponseBodyAsString(), e.getStatusCode()); + log.error("call API 클라이언트오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } catch (RestClientException e) { + responseEntity = new ResponseEntity(e.getMessage(), HttpStatus.REQUEST_TIMEOUT); + log.error("RestAPI 호출 오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } catch (Exception e) { + responseEntity = new ResponseEntity(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + log.error("call API 기타오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } finally { + log.info("카카오페이 청구서 API\n[ REQUEST ]-----------------------------------------------------------------------\n{}\n[ RESPONSE ]-----------------------------------------------------------------------\n{}", sb.toString(), responseEntity.getBody()); + } + + + return responseEntity; + } + + + /** + * 청구서링크 생성 + * + * @param billerCode + * @param authorization + * @param jsonStr + * @return + */ + @Override + public ResponseEntity url(String billerCode, String authorization, String jsonStr) { + + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", authorization); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + headers.set("X-Xit-BillerCode", billerCode); + + + StringBuilder url = new StringBuilder(); + url.append(this.HOST) + .append(this.API_URL.replace("{billerCode}", billerCode == null ? "" : billerCode)); + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers); + return resp; + } + + + /** + * 청구서링크 재생성 + * + * @param billerCode + * @param authorization + * @param jsonStr + * @return + */ + @Override + public ResponseEntity reUrl(String billerCode, String authorization, String jsonStr) { + + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", authorization); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + headers.set("X-Xit-BillerCode", billerCode); + + + StringBuilder url = new StringBuilder(); + url.append(this.HOST) + .append(this.API_RE_URL.replace("{billerCode}", billerCode == null ? "" : billerCode)); + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers); + return resp; + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoPayApiSpec.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoPayApiSpec.java new file mode 100644 index 0000000..912aa8f --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoPayApiSpec.java @@ -0,0 +1,27 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.api; + +import org.springframework.http.ResponseEntity; + +public interface BillKkoPayApiSpec { + + /** + * 청구서링크 생성 + * + * @param billerCode + * @param authorization + * @param jsonStr + * @return + */ + ResponseEntity url(String billerCode, String authorization, String jsonStr); + + + /** + * 청구서링크 재생성 + * + * @param billerCode + * @param authorization + * @param jsonStr + * @return + */ + ResponseEntity reUrl(String billerCode, String authorization, String jsonStr); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoPayApiTest.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoPayApiTest.java new file mode 100644 index 0000000..535a38a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoPayApiTest.java @@ -0,0 +1,141 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.api; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.utils.IdGenerator; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; +import org.springframework.http.*; +import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +@Slf4j +@Component +@Profile({"local-test"}) +public class BillKkoPayApiTest implements BillKkoPayApiSpec { + + @Value("${contract.kakao.pay.bill.dozn.host}") + private String HOST; + @Value("${contract.kakao.pay.bill.dozn.api.url}") + private String API_URL; + @Value("${contract.kakao.pay.bill.dozn.api.reurl}") + private String API_RE_URL; + + /** + * 청구서링크 생성 + * + * @param billerCode + * @param authorization + * @param jsonStr + * @return + */ + @Override + public ResponseEntity url(String billerCode, String authorization, String jsonStr) { + + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", authorization); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + + + StringBuilder url = new StringBuilder(); + url.append(this.HOST) + .append(this.API_URL.replace("{billerCode}", billerCode == null ? "" : billerCode)); + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers); + + + String uuid = IdGenerator.getUUID(); + String data = "{\"res_code\":\"OK\",\"message\":\"성공\",\"data\":{\"url\":\"https://billgatesweb.kakao.com/r/platform/pages/paynow/search/" + uuid + "\"}}"; + return ResponseEntity.ok(data); + } + + + /** + * 청구서링크 재생성 + * + * @param billerCode + * @param authorization + * @param jsonStr + * @return + */ + @Override + public ResponseEntity reUrl(String billerCode, String authorization, String jsonStr) { + + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", authorization); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + + + StringBuilder url = new StringBuilder(); + url.append(this.HOST) + .append(this.API_RE_URL.replace("{billerCode}", billerCode == null ? "" : billerCode)); + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers); + + + String uuid = IdGenerator.getUUID(); + String data = "{\"res_code\":\"OK\",\"message\":\"성공\",\"data\":{\"url\":\"https://billgatesweb.kakao.com/r/platform/pages/paynow/search/" + uuid + "\"}}"; + return ResponseEntity.ok(data); + } + + /** + *
메소드 설명: API 호출
+     * 
+ * + * @param method + * @param url + * @param body + * @param headers + * @return ResponseEntity 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 4. + * @apiNote: 사이트 참조 https://e2e2e2.tistory.com/15 + */ + private ResponseEntity callApi(HttpMethod method, String url, String body, HttpHeaders headers) { + + StringBuffer sb = new StringBuffer(); + ResponseEntity responseEntity = ResponseEntity.ok("test"); + try { + + HttpEntity entity = null; + UriComponents uri = null; + switch (method) { + case GET: + entity = new HttpEntity<>(headers); + uri = UriComponentsBuilder + .fromHttpUrl(String.format("%s?%s", url, body == null ? "" : body)) + .build(false); + break; + case POST: + entity = new HttpEntity<>(body, headers); + uri = UriComponentsBuilder + .fromHttpUrl(url) + .encode(StandardCharsets.UTF_8) + .build(); + break; + + default: + break; + } + + sb.append("\n url => " + uri.toString()) + .append("\n method => " + method) + .append("\n headers => " + entity.getHeaders().toString()) + .append("\n body => " + entity.getBody()); + } catch (Exception e) { + log.error("call API 기타오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } finally { + log.info("카카오페이 청구서 API\n[ REQUEST ]-----------------------------------------------------------------------\n{}\n[ RESPONSE ]-----------------------------------------------------------------------\n{}", sb.toString(), responseEntity.getBody()); + } + + + return responseEntity; + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/code/BillKkoCardCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/code/BillKkoCardCd.java new file mode 100644 index 0000000..7e1ffb3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/code/BillKkoCardCd.java @@ -0,0 +1,73 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *
    + *
  • 업무 그룹명: 카카오페이 청구서API - 카드사 코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2022. 2. 15. 오후 3:51:43 + *
+ * @author 박민규 + */ + +public enum BillKkoCardCd implements CodeMapperType { + + BC("비씨카드") + ,BUSAN("부산은행") + ,DAEGU("대구은행") + ,DONGBUSEC("DB금융투자") + ,GWANGJU("광주은행") + ,HANA("하나카드") + ,HANABC("하나비씨카드") + ,HYUNDAI("현대카드") + ,IBK("IBK기업은행") + ,JEJU("제주은행") + ,JEONBUK("전북은행") + ,KAKAOBANK("카카오뱅크") + ,KAKAOPAY("카카오페이") + ,KB("국민카드") + ,KBANK("케이뱅크") + ,KBBC("국민비씨카드") + ,KBSEC("KB증권") + ,KDB("산업은행") + ,KYOBOSEC("교보증권") + ,KYUNGNAM("경남은행") + ,LOTTE("롯데카드") + ,MIRAESEC("미래에셋증권") + ,NH("농협(NH)") + ,NHBC("농협비씨카드") + ,POST("우체국") + ,SAEMAUL("새마을금고") + ,SAMSUNG("삼성카드") + ,SAVINGS("저축은행") + ,SC("SC제일은행") + ,SHINHAN("신한카드") + ,SHINHANBC("신한비씨카드") + ,SHINHYUP("신용협동조합") + ,SJ("산림조합중앙회") + ,SSGJBETC("SSG카드(JB)") + ,SUHYUP("수협") + ,WOORI("우리카드") + ,YUANTASEC("유안타증권") + ,UNKNOWN("사용불가카드") + ; + + private final String code; + private final String codeNm; + BillKkoCardCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/code/BillKkoErrCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/code/BillKkoErrCd.java new file mode 100644 index 0000000..6522dfc --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/code/BillKkoErrCd.java @@ -0,0 +1,82 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *
    + *
  • 업무 그룹명: 카카오페이 청구서API - ERROR 코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2022. 2. 15. 오후 3:51:43 + *
+ * @author 박민규 + */ + +public enum BillKkoErrCd implements CodeMapperType { + + + OK("성공") + ,E001("필수 파라미터가 없습니다.") + ,E006("파라미터의 최대 길이가 초과했습니다.") + ,E007("파라미터의 자릿수가 맞지 않습니다.") + ,E008("JSON 파싱 에러") + + + + ,E801("[에이전시] 내부 에러") + ,E806("[에이전시] 카카오페이에 요청 중 타임아웃 발생") + ,E807("[에이전시] 요청 데이터 JSON 파싱 에러") + ,E808("[에이전시] 응답 데이터 JSON 파싱 에러") + ,E809("[에이전시] 요청에 대한 응답 데이터를 받지 못했습니다.") + ,E817("[에이전시] 오류 건으로 분류된 청구서입니다.") + + + + ,E003("잘못된 빌러 식별 코드입니다.") + ,E005("청구서 식별 코드가 필요합니다.") + ,E101("parameter 저장이 실패했습니다. key, value 의 길이 및 타입을 확인해주세요.") + ,E811("[에이전시] 청구서 식별 코드가 중복됩니다.") + ,E818("[에이전시] 이미 링크 생성된 청구서입니다.") + + + +// ,E101("parameter 저장이 실패했습니다. key, value 의 길이 및 타입을 확인해주세요.") + ,E812("[에이전시] 등록되지 않은 청구서입니다.") + + + + ,E402("청구서 조회 결과가 없습니다.") + ,E404("생년월일이 일치하지 않습니다.") + + + + ,E403("납부 가능 금액이 없습니다.") + ,E501("납부불가 - 납부 가능금액 초과") + ,E502("납부불가 - 납부 대상 없음") + ,E506("납부기한이 경과하였습니다.") + ,E601("수납처리실패 - 납부요청 정보 조회 실패") + + + + ,ERR505("응답 데이터 Json 파싱 오류") + ,ERR601("API서버 응답 오류") + ,ERR999("기타 오류") + ; + + private final String code; + private final String codeNm; + BillKkoErrCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/BillKkoPay.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/BillKkoPay.java new file mode 100644 index 0000000..75d00ac --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/BillKkoPay.java @@ -0,0 +1,117 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillBaseEntity; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.persistence.*; + +@Entity +@Getter +@ToString +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_bill_kko", schema = "", catalog = "") +@Schema(name = "BillKkoPay") +public class BillKkoPay extends BillBaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.TABLE, generator = "BillKko_Generator") + @TableGenerator(table = "ens_seq_generator", name = "BillKko_Generator" + , pkColumnName = "seq_name", pkColumnValue = "BillKko_id" + , initialValue = 0, allocationSize = 200) + @Schema(required = true, title = "PK", example = " ") + private Long billId; + + + @Schema(required = false, title = "청구 연월", example = " ") + @Column(name = "billed_year_month", nullable = true) + @Setter + private String billedYearMonth; + @Schema(required = false, title = "동일 고객번호 구분 값", example = " ") + @Column(name = "ordinal", nullable = true) + @Setter + private String ordinal; + @Schema(required = false, title = "개별 청구서를 식별하는 키 값", example = " ") + @Column(name = "biller_notice_key", nullable = true) + @Setter + private String billerNoticeKey; + @Schema(required = false, title = "URL 만료일", example = "20200130235959") + @Column(name = "expire_at", nullable = true) + @Setter + private String expireAt; + @Schema(required = false, title = "API 호출 시 함께 전달할 JSON형태의 문자열", example = " ") + @Column(name = "parameters", nullable = true) + @Lob + @Setter + private String parameters; + @Schema(required = false, title = "청구서조회/납부가능여부/납부결과 API Url정보 JSON형태의 문자열", example = " \"custom_url\": {\n" + + " \"notice_url\" : \" https://test-api.dozn.co.kr/kakao/notice\",\n" + + " \"prepay_url\": \"https://test-api.dozn.co.kr/kakao/prepay\",\n" + + " \"pay_result_url\": \" https://test-api.dozn.co.kr/kakao/pay-result\"\n" + + " }") + @Column(name = "custom_url", nullable = true, length = 500) + @Setter + private String customUrl; + @Schema(required = false, title = "청구서URL", example = " ") + @Column(name = "url", nullable = true) + @Setter + private String url; + /* ===================================== + * 결제진행 - PayNotice 단계 + ===================================== */ + @Schema(required = false, title = "청구서명", example = "테스트청구서") + @Column(name = "title", nullable = true) + @Setter + private String title; + @Schema(required = false, title = "납부 요청금액", example = "1000") + @Column(name = "amount", nullable = true) + @Setter + private Integer amount; + @Schema(required = false, title = "비과세 금액", example = "0") + @Column(name = "tax_free_amount", nullable = true) + @Setter + private Integer taxFreeAmount; + @Schema(required = false, title = "부가세 금액", example = "0") + @Column(name = "vat_amount", nullable = true) + @Setter + private Integer vatAmount; + @Schema(required = false, title = "납기 안내타입", example = "D1") + @Column(name = "expire_type", nullable = true, length = 10) + @Setter + private String expireType; + @Schema(required = false, title = "첫번째 납기일", example = "20230212") + @Column(name = "pay_expire_date", nullable = true, length = 8) + @Setter + private String payExpireDate; + @Schema(required = false, title = "두번째 납기일", example = "20230212") + @Column(name = "second_pay_expire_date", nullable = true, length = 8) + @Setter + private String secondPayExpireDate; + @Schema(required = false, title = "계좌송금수단 사용 시 계좌정보", example = " ") + @Lob + @Column(name = "bank_accounts", nullable = true) + @Setter + private String bankAccounts; + @Schema(required = false, title = "청구서 상세정보", example = " ") + @Lob + @Column(name = "details", nullable = true) + @Setter + private String details; + @Schema(required = false, title = "결제일시(YYYYMMDDHH24MISS)", example = "20190220161656") + @Column(name = "last_paid_at", nullable = true, length = 14) + @Setter + private String lastPaidAt; + @Schema(required = false, title = "결제번호", example = "2748877") + @Column(name = "last_pay_id", nullable = true) + @Setter + private Integer lastPayId; + + @Embedded + @Setter + private FieldError error; + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillKkoPayRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillKkoPayRepository.java new file mode 100644 index 0000000..6040273 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillKkoPayRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.repository; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.BillKkoPay; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface BillKkoPayRepository extends JpaRepository { + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoApiRespDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoApiRespDTO.java new file mode 100644 index 0000000..f3a8695 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoApiRespDTO.java @@ -0,0 +1,47 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.code.BillKkoErrCd; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +@Getter +@ToString +@EqualsAndHashCode +@Schema(name = "KkoBillPayApiRespVO") +public class BillKkoApiRespDTO { + + @Schema(title = "응답코드", example = " ") + private String res_code; + + @Schema(title = "응답메시지", example = " ") + private String message; + + @Schema(title = "응답데이터", example = " ") + private T data; + + + @Builder(builderClassName = "okBuilder", builderMethodName = "okBuilder") + BillKkoApiRespDTO(T data) { + this.res_code = BillKkoErrCd.OK.getCode(); + this.message = BillKkoErrCd.OK.getCodeNm(); + this.data = data; + } + + @Builder(builderClassName = "errBuilder", builderMethodName = "errBuilder") + BillKkoApiRespDTO(String resCode, String message) { + this.res_code = resCode; + this.message = message; + this.data = null; + } + + @Builder(builderClassName = "errDataBuilder", builderMethodName = "errDataBuilder") + BillKkoApiRespDTO(String resCode, String message, T data) { + this.res_code = resCode; + this.message = message; + this.data = data; + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoPayResultData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoPayResultData.java new file mode 100644 index 0000000..c2ba333 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoPayResultData.java @@ -0,0 +1,52 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +import java.util.Map; + +@Getter +@ToString +@EqualsAndHashCode +@Schema(name = "BillKkoPayResultData") +public class BillKkoPayResultData { + + @Schema(required = true, title = "사용자 식별키", example = " ") + private String biller_user_key; + @Schema(required = false, title = "청구연월(YYYYMM 형식), 없을 시 생략", example = " ") + private String billed_year_month; + @Schema(required = false, title = "동일 고객번호, 청구 연월의 복수 개 청구서 발생 등 몇 번째 청구인지 구분을 위해 사용", example = " ") + private String ordinal; + @Schema(required = false, title = "개별 청구서를 식별하는 키 값", example = " ") + private String biller_notice_key; + @Schema(required = false, title = "URL 생성 시 전달한 파라미터", example = " ") + private Map parameters; + @Schema(required = true, title = "결제수단(CARD/MONEY/MONEY_TRANSFER)", example = " ") + private String pay_by; + @Schema(required = true, title = "결제타입(P:결제, C:취소)", example = " ") + private String pay_type; + @Schema(required = false, title = "결제수단 상세1. 카드인 경우 카드번호 앞 6자리", example = " ") + private String pay_detail1; + @Schema(required = false, title = "결제수단 상세2. 카드사 구분 코드", example = " ") + private String pay_detail2; + @Schema(required = false, title = "결제수단 상세3. 공백", example = " ") + private String pay_detail3; + @Schema(required = true, title = "납부요청 금액", example = " ") + private String amount; + @Schema(required = true, title = "거래구분이 P 인 경우 양수(결제금액), C 인 경우 음수(-취소금액)", example = " ") + private String pay_amount; + @Schema(required = true, title = "결제 수수료 금액 부과구분(BEFORE: 선취, AFTER: 후취, NONE: 부과 안함)", example = " ") + private String pay_fee_type; + @Schema(required = true, title = "결제 수수료 금액_공급가액", example = " ") + private String pay_fee; + @Schema(required = true, title = "결제 수수료 금액_부가세", example = " ") + private String pay_fee_tax; + @Schema(required = false, title = "정산예정일(YYYYMMDD)", example = " ") + private String adjust_date; + @Schema(required = true, title = "결제일시(YYYYMMDDHH24MISS)", example = " ") + private String paid_at; + @Schema(required = true, title = "카카오페이 결제번호", example = " ") + private String pay_id; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/presentation/KkoPayProcessController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/presentation/KkoPayProcessController.java new file mode 100644 index 0000000..68b8bf2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/presentation/KkoPayProcessController.java @@ -0,0 +1,92 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.presentation; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.KkoPayProcessService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.PayController; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@Tag(name = "KkoPayProcessController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class KkoPayProcessController implements PayController, Map> { + + private final KkoPayProcessService kkoPayProcessService; + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "청구서링크 생성" + , value = "{\"billUid\":\"청구서UID\"}") + }) + }) + @Operation(summary = "청구서링크 생성") + @PostMapping(value = "/bill/kko/pay/gnrurl", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity gnrUrl(@RequestBody Map param) { + return new ResponseEntity(kkoPayProcessService.gnrUrl(param), HttpStatus.OK); + } + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "결제정보 요청" + , value = "{\"data\":{\"biller_user_key\":\"빌러유저키\",\"biller_notice_key\":\"청구서UID\",\"user_birth\":\"19861128\",\"parameters\":{\"파라미터1\":\"8자이내값\"}}}") + }) + }) + @Operation(summary = "납부(결제)정보 요청") + @PostMapping(value = "/bill/kko/pay/notice", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity payNotice(@RequestBody Map param) { + return new ResponseEntity(kkoPayProcessService.payNotice(param), HttpStatus.OK); + } + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "납부(결제)가능여부 확인" + , value = "{\"data\":{\"biller_user_key\":\"빌러유저키\",\"biller_notice_key\":\"청구서UID\",\"amount\":29000,\"parameters\":{\"파라미터1\":\"8자이내값\"}}}") + }) + }) + @Operation(summary = "납부(결제)가능여부 확인") + @PostMapping(value = "/bill/kko/pay/able", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity payAble(@RequestBody Map param) { + return new ResponseEntity(kkoPayProcessService.payAble(param), HttpStatus.OK); + } + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "결과전달" + , value = "{\"data\":{\"biller_user_key\":\"빌러유저키\",\"biller_notice_key\":\"청구서UID\",\"parameters\":{\"파라미터1\":\"8자이내값\"},\"pay_by\":\"MONEY\",\"pay_type\":\"P\",\"pay_detail1\":\"\",\"pay_detail2\":\"\",\"amount\":20000,\"pay_amount\":20000,\"pay_fee_type\":\"BEFORE\",\"pay_fee\":150,\"pay_fee_tax\":15,\"paid_at\":\"20190220161656\",\"pay_id\":2748877}}") + }) + }) + @Operation(summary = "납부(결제)결과 전달") + @PostMapping(value = "/bill/kko/pay/result", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity payResult(@RequestBody Map param) { + return new ResponseEntity(kkoPayProcessService.payResult(param), HttpStatus.OK); + } + + + @Operation(summary = "결제취소") + @PostMapping(value = "/bill/kko/pay/cancel", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity payCancel(Map param) { + return new ResponseEntity(kkoPayProcessService.payCancel(param), HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/presentation/KkoPayUseSysSampleController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/presentation/KkoPayUseSysSampleController.java new file mode 100644 index 0000000..3fdb081 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/presentation/KkoPayUseSysSampleController.java @@ -0,0 +1,195 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.presentation; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.KkoPayNoticeRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.KkoPayUrlRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.PayUseSysController; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import com.google.gson.Gson; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +@Tag(name = "KkoPayUseSysSampleController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class KkoPayUseSysSampleController implements PayUseSysController> { + + private Gson gson = new Gson(); + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "청구서링크생성 정보" + , value = "{\"data\":{\"billerUserKey\":\"빌러유저키\"}}") + }) + }) + @Operation(summary = "청구서링크생성 정보 샘플") + @PostMapping(value = "/bill/kko/sample/gnrUrl", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity gnrUrl(@RequestBody Map param) { + log.info("[Request Data] {}", param.toString()); + + + /* ============================================ + * [정상 응답코드] + * OK + * [실패 응답코드] + * GRNURL_FIND_FAILED + ============================================ */ + PayUseSysResCd resCd = PayUseSysResCd.OK; + + + String expireAt = "20231231235959"; + KkoPayUrlRespData data = KkoPayUrlRespData.builder() + .billedYearMonth(null) + .ordinal(null) + .expireAt(expireAt) + .parameters(null) + .build(); + Map result = new HashMap<>(); + result.put("res_code", resCd.getCode()); + result.put("message", resCd.getCodeNm()); + result.put("data", data); + + return new ResponseEntity>(result, HttpStatus.OK); + } + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "납부(결제)정보" + , value = "{\"data\":{\"biller_user_key\":\"빌러유저키\",\"user_birth\":\"\",\"parameters\":{\"some_param\":\"\"}}}"), + }) + }) + @Operation(summary = "납부(결제)정보 샘플") + @PostMapping(value = "/bill/kko/sample/paynotice", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity> payNotice(@RequestBody Map param) { + log.info("[Request Data] {}", param.toString()); + + + + /* ============================================ + * [정상 응답코드] + * OK + * [실패 응답코드] + * NOT_FOUND_PAYDATA + * PAYDATA_FIND_FAILED + ============================================ */ + PayUseSysResCd resCd = PayUseSysResCd.OK; + + + String payExpireDate = "20231231"; + KkoPayNoticeRespData data = KkoPayNoticeRespData.builder() + .title("테스트 청구서") + .amount(1000) + .taxFreeAmount(null) + .vatAmount(null) + .expireType("D1") + .payExpireDate(payExpireDate) + .secondPayExpireDate(null) + .bankAccounts(null) + .details(null) + .build(); + Map result = new HashMap<>(); + result.put("res_code", resCd.getCode()); + result.put("message", resCd.getCodeNm()); + result.put("data", data); + + return new ResponseEntity>(result, HttpStatus.OK); + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "납부(결제)가능여부" + , value = "{\"data\":{\"biller_user_key\":\"빌러유저키\",\"amount\":29000,\"parameters\":{\"pay_rqt_seq\":\"KT00000001\"}}}") + }) + }) + @Operation(summary = "납부(결제)가능여부 샘플") + @PostMapping(value = "/bill/kko/sample/payable", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity> payAble(@RequestBody Map param) { + log.info("[Request Data] {}", param.toString()); + + + /* ============================================ + * [정상 응답코드] + * OK + * [실패 응답코드] + * NO_AMOUNT_PAYABLE + * OVERPAYABLE_AMOUNT + * NO_TARGET_PAYABLE + * EXPIRED_DATE + * FAILED_CHECK_INFO + ============================================ */ + PayUseSysResCd resCd = PayUseSysResCd.OK; + + + Map result = new HashMap<>(); + result.put("res_code", resCd.getCode()); + result.put("message", resCd.getCodeNm()); + result.put("data", null); + + + return new ResponseEntity>(result, HttpStatus.OK); + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "납부(결제)결과" + , value = "{\"data\":{\"biller_user_key\":\"빌러유저키\",\"parameters\":{\"pay_rqt_seq\":\"KT00000001\"},\"pay_by\":\"MONEY\",\"pay_type\":\"P\",\"pay_detail1\":\"\",\"pay_detail2\":\"\",\"amount\":20000,\"pay_amount\":20000,\"pay_fee_type\":\"BEFORE\",\"pay_fee\":150,\"pay_fee_tax\":15,\"paid_at\":\"20190220161656\",\"pay_id\":2748877}}") + }) + }) + @Operation(summary = "납부(결제)결과 샘플") + @PostMapping(value = "/bill/kko/sample/payresult", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity> payResult(@RequestBody Map param) { + log.info("[Request Data] {}", param.toString()); + + PayUseSysResCd resCd = PayUseSysResCd.OK; + + + Map result = new HashMap<>(); + result.put("res_code", resCd.getCode()); + result.put("message", resCd.getCodeNm()); + result.put("data", null); + + return new ResponseEntity>(result, HttpStatus.OK); + } + + + // @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { +// @Content(mediaType = "application/json", examples = { +// @ExampleObject(name = "Sample Example..." +// , summary = "결제취소정보" +// , value = "{}") +// }) +// }) + @Operation(summary = "결제취소정보 샘플") + @PostMapping(value = "/bill/kko/sample/cancelresult", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity> payCancel(Map param) { + throw new EnsException(EnsErrCd.SERVICE_NOT_SUPPORTED, EnsErrCd.SERVICE_NOT_SUPPORTED.getCodeNm()); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/KkoPayProcessService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/KkoPayProcessService.java new file mode 100644 index 0000000..bc6d3d4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/KkoPayProcessService.java @@ -0,0 +1,102 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.BillKkoPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.KkoPayAbleService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.KkoPayNoticeService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.KkoPayResultService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.KkoPayUrlService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.KkoPayNoticeRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.Pay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.PayProcessService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayAbleData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayNoticeData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayResultData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayUrlData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.template.PayHelper; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Log4j2 +@RequiredArgsConstructor +@Service +public class KkoPayProcessService implements PayProcessService> { + private final KkoPayUrlService kkoPayUrlService; + private final KkoPayNoticeService kkoPayNoticeService; + private final KkoPayAbleService kkoPayAbleService; + private final KkoPayResultService kkoPayResultService; + + + @Override + public PayApiRespDTO gnrUrl(Map data) { + + String billUid = (String) data.get("billUid"); + + + Pay>> pay = PayHelper., String, PayApiRespDTO>>builder() + .param(billUid) + .payHelperService(kkoPayUrlService) + .build(); + + + pay.exec(); + + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payNotice(Map data) { + + Pay> pay = PayHelper., Map, PayApiRespDTO>builder() + .param(data) + .payHelperService(kkoPayNoticeService) + .build(); + + + pay.exec(); + + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payAble(Map data) { + + + Pay>> pay = PayHelper., Map, PayApiRespDTO>>builder() + .param(data) + .payHelperService(kkoPayAbleService) + .build(); + + + pay.exec(); + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payResult(Map data) { + + + Pay>> pay = PayHelper., Map, PayApiRespDTO>>builder() + .param(data) + .payHelperService(kkoPayResultService) + .build(); + + + pay.exec(); + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payCancel(Map data) { + throw new EnsException(EnsErrCd.SERVICE_NOT_SUPPORTED, EnsErrCd.SERVICE_NOT_SUPPORTED.getCodeNm()); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/KkoPayRepairService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/KkoPayRepairService.java new file mode 100644 index 0000000..74364ce --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/KkoPayRepairService.java @@ -0,0 +1,143 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service; + +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.repair.kit.RepairKkoPayResultTransferFail; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.RepairPayResultService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.model.RepairPayRsltFwdFailSearchDTO; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Service +@RequiredArgsConstructor +public class KkoPayRepairService implements RepairPayResultService { + + private final JPAQueryFactory query; + private final PayUseSysApi payUseSysApi; + private final BillHistRepository billHistRepository; + + + @Override + @Transactional(readOnly = true) + public Map> findTransferFailedPayResultDataList(RepairPayRsltFwdFailSearchDTO searchDTO) { + Map> mResultByOrg = new HashMap<>(); + RepairKkoPayResultTransferFail.builder() + .query(query) + .searchDTO(searchDTO) + .build() + .findDatas() + .forEach(failData -> { + /** + * 응답데이터 구조 + * { + * "기관코드" { + * "orgCd": "aaaa", + * "orgNm": "sdafsf", + * "billSe": { + * "nvBp": [ + * { "billerUserKey": "aaaaaaaaaaaaa" }, + * { "billerUserKey": "bbbbbbbbbbbbb" } + * ], + * "kkoBp": [ + * { "billerUserKey": "fffffffffffff" } + * ] + * } + * } + * } + */ + Map mOrg = mResultByOrg.get(failData.getOrgCd()); + if (mOrg == null) { + mOrg = new HashMap<>(); + mOrg.put("orgCd", failData.getOrgCd()); + mOrg.put("orgNm", failData.getOrgNm()); + Map data = new HashMap<>(); + data.put("billerUserKey", failData.getBillerUserKey()); + List> datas = new ArrayList<>(); + datas.add(data); + Map billSe = new HashMap<>(); + billSe.put(failData.getBillSe().getCode(), datas); + mOrg.put("billSe", billSe); + mResultByOrg.put(failData.getOrgCd(), mOrg); + } else { + Map billSe = (Map) mOrg.get("billSe"); + List> datas = (List>) billSe.getOrDefault(failData.getBillSe().getCode(), new ArrayList<>()); + Map data = new HashMap<>(); + data.put("billerUserKey", failData.getBillerUserKey()); + datas.add(data); + billSe.put(failData.getBillSe().getCode(), datas); + } + }); + return mResultByOrg; + } + + @Override + public Map> sendTransferFailedPayResultDataList(RepairPayRsltFwdFailSearchDTO searchDTO) { + Map> mResultByOrg = new HashMap<>(); + RepairKkoPayResultTransferFail.builder() + .query(query) + .searchDTO(searchDTO) + .build() + .transferData(payUseSysApi, billHistRepository) + .forEach(billHist -> { + /** + * 응답데이터 구조 + * { + * "기관코드" { + * "orgCd": "aaaa", + * "orgNm": "sdafsf", + * "billSe": { + * "nvBp": [ + * { "billerUserKey": "aaaaaaaaaaaaa", "code": "OK", "message": "성공" }, + * { "billerUserKey": "bbbbbbbbbbbbb", "code": "OK", "message": "성공" } + * ], + * "kkoBp": [ + * { "billerUserKey": "fffffffffffff", "code": "FAILED_SAVE_PAYRSLT", "message": "납부(결제)결과 저장 실패" } + * ] + * } + * } + * } + */ + Map mOrg = mResultByOrg.get(billHist.getOrgMng().getOrgCd()); + FieldError error = billHist.getError() == null ? FieldError.initBuilder().errorCode(EnsErrCd.OK.getCode()).errorMessage(EnsErrCd.OK.getCodeNm()).build() : billHist.getError(); + if (mOrg == null) { + + mOrg = new HashMap<>(); + mOrg.put("orgCd", billHist.getOrgMng().getOrgCd()); + mOrg.put("orgNm", billHist.getOrgMng().getOrgNm()); + Map data = new HashMap<>(); + data.put("billerUserKey", billHist.getLinkedUuid()); + data.put("code", error.getErrorCode()); + data.put("message", error.getErrorMessage()); + List> datas = new ArrayList<>(); + datas.add(data); + Map billSe = new HashMap<>(); + billSe.put(billHist.getBillSe().getCode(), datas); + mOrg.put("billSe", billSe); + mResultByOrg.put(billHist.getOrgMng().getOrgCd(), mOrg); + } else { + Map billSe = (Map) mOrg.get("billSe"); + List> datas = (List>) billSe.getOrDefault(billHist.getBillSe().getCode(), new ArrayList<>()); + Map data = new HashMap<>(); + data.put("billerUserKey", billHist.getLinkedUuid()); + data.put("code", error.getErrorCode()); + data.put("message", error.getErrorMessage()); + datas.add(data); + billSe.put(billHist.getBillSe().getCode(), datas); + } + }); + + + return mResultByOrg; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/KkoPaymentTriggerService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/KkoPaymentTriggerService.java new file mode 100644 index 0000000..845c533 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/KkoPaymentTriggerService.java @@ -0,0 +1,66 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.BillKkoPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.QBillKkoPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.repository.BillKkoPayRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.trigger.PaymentTriggerServiceTemplate; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + + +@Slf4j +@RequiredArgsConstructor +@Service(value = "kkoPaymentTriggerService") +public class KkoPaymentTriggerService extends PaymentTriggerServiceTemplate { + private final KkoPayProcessService kkoPayProcessService; + private final JPAQueryFactory query; + private final BillKkoPayRepository billKkoPayRepository; + + @Override + protected boolean existsBill(String billUid) { + return query.selectFrom(QBillKkoPay.billKkoPay) + .where(QBillKkoPay.billKkoPay.billUid.eq(billUid)) + .fetchCount() > 0; + } + + @Override + protected void generateBill(Bill bill) { + billKkoPayRepository.save(BillKkoPay.builder() + .billUid(bill.getBillUid()) + .billerUserKey(bill.getBillerUserKey()) + .build()); + } + + @Override + protected Map getPayInfo(Map param) { + final Bill bill = (Bill) param.getOrDefault(PTriggerDataKeys.bill, new Bill()); + final String billUid = (String) param.getOrDefault(PTriggerDataKeys.billUid, ""); + + + Map p = new HashMap<>(); + p.put("billUid", billUid); + PayApiRespDTO payApiRespDTO = kkoPayProcessService.gnrUrl(p); + if (PayUseSysResCd.OK.getCode().equals(payApiRespDTO.getResCode())) { + Map data = (Map) payApiRespDTO.getData(); + Map resultInfo = new HashMap<>(); + resultInfo.put("url", data.get("url")); + + return resultInfo; + } else { + throw new EnsException(EnsErrCd.RESPONSED_FAILURE_CODE, String.format("%s\n[실패사유]\n -.코드: %s\n -.메시지: %s", EnsErrCd.RESPONSED_FAILURE_CODE.getCodeNm(), payApiRespDTO.getResCode(), payApiRespDTO.getMessage())); + } + + + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/KkoPayAbleService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/KkoPayAbleService.java new file mode 100644 index 0000000..7c21d3a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/KkoPayAbleService.java @@ -0,0 +1,261 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.BillKkoPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.QBillKkoPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.repository.BillKkoPayRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.QBill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayAbleService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayAbleData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.ReqAndRespInf; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Service +public class KkoPayAbleService implements PayAbleService, Map, PayApiRespDTO>> { + private final BillKkoPayRepository billKkoPayRepository; + + private final JPAQueryFactory query; + private final PayUseSysApi payUseSysApi; + private final BillHistRepository billHistRepository; + + private Gson gson = new Gson(); + + private enum KkoErrCd { + E403(PayUseSysResCd.NO_AMOUNT_PAYABLE), + E501(PayUseSysResCd.OVERPAYABLE_AMOUNT), + E502(PayUseSysResCd.NO_TARGET_PAYABLE), + E506(PayUseSysResCd.EXPIRED_DATE), + E601(PayUseSysResCd.FAILED_CHECK_INFO), + ; + @Getter + private PayUseSysResCd payUseSysResCd; + + KkoErrCd(PayUseSysResCd payUseSysResCd) { + this.payUseSysResCd = payUseSysResCd; + } + + static public KkoErrCd payUseSysResCdOf(String payUseSysResCd) { + KkoErrCd result = null; + for (KkoErrCd kkoErrCd : KkoErrCd.values()) { + if (kkoErrCd.getPayUseSysResCd().getCode().equals(payUseSysResCd)) { + result = kkoErrCd; + break; + } + } + return result; + } + } + + @Override + public PayAbleData getData(Map reqParam) { + + Map data = (Map) reqParam.getOrDefault("data", new HashMap<>()); + String billerUserKey = (String) data.get("biller_user_key"); + String billedYearMonth = (String) data.get("billed_year_month"); + String ordinal = (String) data.get("ordinal"); + String billerNoticeKey = (String) data.get("biller_notice_key"); + Map parameters = (Map) data.getOrDefault("parameters", new HashMap<>()); + Integer amount = (Integer) data.get("amount"); + + BillKkoPay billKkoPay = query.selectFrom(QBillKkoPay.billKkoPay) + .where(QBillKkoPay.billKkoPay.billerNoticeKey.eq(billerNoticeKey)) + .fetchOne(); + String billUid = billKkoPay == null ? null : billKkoPay.getBillUid(); + if (billUid == null) billUid = ""; + Bill bill = query.selectFrom(QBill.bill) + .innerJoin(QBill.bill.orgMng, QOrgMng.orgMng).fetchJoin() + .where(QBill.bill.billUid.eq(billUid)) + .fetchOne(); + + return PayAbleData.builder() + .bill(bill) + .billDetail(billKkoPay) + .build(); + } + + @Override + public void validate(Map reqParam, PayAbleData data) { + Map m = (Map) reqParam.getOrDefault("data", new HashMap<>()); + + if (CmmnUtil.isEmpty(m.get("biller_user_key"))) + throw new EnsException(EnsErrCd.NO_REQUIRED_PARAM, "빌러유저키는 필수값 입니다."); + if (CmmnUtil.isEmpty(m.get("biller_notice_key"))) + throw new EnsException(EnsErrCd.NO_REQUIRED_PARAM, "청구서식별키는 필수값 입니다."); + if (CmmnUtil.isEmpty(m.get("amount"))) + throw new EnsException(EnsErrCd.NO_REQUIRED_PARAM, "납부요청금액 필수값 입니다."); + + if (CmmnUtil.isEmpty(data.getBill())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 자료가 없습니다."); + if (CmmnUtil.isEmpty(data.getBillDetail())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 상세 자료가 없습니다."); + } + + @Override + public void callApi(Map reqParam, PayAbleData data) { + Bill bill = data.getBill(); + OrgMng orgMng = bill.getOrgMng(); + BillKkoPay billKkoPay = data.getBillDetail(); + + + + final String useSysUrl = orgMng.getKkoBpPrepayApi(); + + + Optional.of(reqParam) + .map(param -> createMessage(param)) + .map(message -> loadReqData(data, useSysUrl, message)) + .map(message -> payUseSysApi.payNotice(useSysUrl, message, null)) + .map(response -> loadRespData(data, response)) + .map(response -> checkResponse(response)) + ; + + } + + private Map createMessage(Map reqParam) { +// Map data = (Map) reqParam.getOrDefault("data", new HashMap<>()); +// Map param = new HashMap<>(); +// param.put("biller_user_key", data.get("biller_user_key")); +// param.put("billed_year_month", data.get("billed_year_month")); +// param.put("ordinal", data.get("ordinal")); +// param.put("biller_notice_key", data.get("biller_notice_key")); +// param.put("parameters", data.get("parameters")); +// param.put("amount", data.get("amount")); +// return param; + return reqParam; + } + + private Map loadReqData(PayAbleData data, String url, Map param) { + + data.getReqAndRespInf().setUrl(url); + data.getReqAndRespInf().setReqData(gson.toJson(param)); + return param; + } + + private ResponseEntity loadRespData(PayAbleData data, ResponseEntity response) { + + data.getReqAndRespInf().setRespRawData(response.getBody()); + return response; + } + + + private PayApiRespDTO> checkResponse(ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + PayApiRespDTO> result = null; + try { + result = gson.fromJson(response.getBody(), new TypeToken>>() { + }.getType()); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RESPONSE, EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + } + + try { + PayUseSysResCd.valueOf(result.getResCode()); + } catch (Exception ex) { + PayApiRespDTO> finalResult = result; + + if (Arrays.stream(KkoErrCd.values()).noneMatch(kkoErrCd -> kkoErrCd.name().equals(finalResult.getResCode()))) + throw new EnsException(EnsErrCd.INVALID_RES_CODE, EnsErrCd.INVALID_RES_CODE.getCodeNm(), ex); + } + + return result; + } + + @Override + public PayApiRespDTO> generateResult(Map reqParam, PayAbleData data, EnsException e) { + if (e == null) { + Gson gson = new Gson(); + final String respRawData = data.getReqAndRespInf().getRespRawData(); + + PayApiRespDTO> resp = gson.fromJson(respRawData, new TypeToken>>() { + }.getType()); + + String resCode = resp.getResCode(); + String matchResCode = KkoErrCd.payUseSysResCdOf(resCode).name(); + if (matchResCode != null) resCode = matchResCode; + + return PayApiRespDTO.>errDataBuilder() + .resCode(resCode) + .message(resp.getMessage()) + .data(resp.getData()) + .build(); + } else { + return PayApiRespDTO.>errDataBuilder() + .resCode(e.getErrCd().getCode()) + .message(e.getMessage()) + .data(null) + .build(); + } + } + + @Override + public void saveHist(Map reqParam, PayAbleData data, EnsException e) { + saveHistByUseSysPayAble(reqParam, data, e); + + if (e != null) { + if (data.getBillDetail() != null) { + data.getBillDetail().setError(FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()); + billKkoPayRepository.save(data.getBillDetail()); + } + } else { + data.getBillDetail().setError(FieldError.initBuilder().build()); + billKkoPayRepository.save(data.getBillDetail()); + } + } + + public void saveHistByUseSysPayAble(Map reqParam, PayAbleData data, EnsException e) { + ReqAndRespInf reqAndRespInf = data.getReqAndRespInf(); + + BillHist billHist = BillHist.builder() + .billUid(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getBillUid()) + .billSe(BillSeCd.bpKko) + .reqSe(BillReqSeCd.US_PREPAY) + .orgMng(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getOrgMng()) + .linkedUuid(CmmnUtil.isEmpty(data.getBillDetail()) ? null : data.getBillDetail().getBillerUserKey()) + .requestData(reqAndRespInf.getReqData()) + .responseData(reqAndRespInf.getRespRawData()) + .error(e == null + ? FieldError.initBuilder().build() + : FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()) + .build(); + + billHistRepository.save(billHist); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/KkoPayNoticeService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/KkoPayNoticeService.java new file mode 100644 index 0000000..0e79fd5 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/KkoPayNoticeService.java @@ -0,0 +1,287 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.BillKkoPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.QBillKkoPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.repository.BillKkoPayRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.KkoPayNoticeRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillLogSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.QBill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayNoticeService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayNoticeData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.ReqAndRespInf; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Service +public class KkoPayNoticeService implements PayNoticeService, Map, PayApiRespDTO> { + + private final JPAQueryFactory query; + private final PayUseSysApi payUseSysApi; + private final BillKkoPayRepository billKkoPayRepository; + private final BillHistRepository billHistRepository; + private Gson gson = new Gson(); + + + private enum KkoErrCd { + E402(PayUseSysResCd.NOT_FOUND_PAYDATA), + E404(PayUseSysResCd.PAYDATA_FIND_FAILED), + ; + @Getter + private PayUseSysResCd payUseSysResCd; + + KkoErrCd(PayUseSysResCd payUseSysResCd) { + this.payUseSysResCd = payUseSysResCd; + } + + static public KkoErrCd payUseSysResCdOf(String payUseSysResCd) { + KkoErrCd result = null; + for (KkoErrCd kkoErrCd : KkoErrCd.values()) { + if (kkoErrCd.getPayUseSysResCd().getCode().equals(payUseSysResCd)) { + result = kkoErrCd; + break; + } + } + return result; + } + } + + @Override + public PayNoticeData getData(Map reqParam) { + + Map data = (Map) reqParam.getOrDefault("data", new HashMap<>()); + String billerUserKey = (String) data.get("biller_user_key"); + String billerNoticeKey = (String) data.get("biller_notice_key"); + String userBirth = (String) data.get("user_birth"); + Map parameters = (Map) data.getOrDefault("parameters", new HashMap<>()); + String orgCd = (String) parameters.get("orgCd"); + + BillKkoPay billKkoPay = query.selectFrom(QBillKkoPay.billKkoPay) + .where(QBillKkoPay.billKkoPay.billerNoticeKey.eq(billerNoticeKey)) + .fetchOne(); + String billUid = billKkoPay == null ? null : billKkoPay.getBillUid(); + if (billUid == null) billUid = ""; + Bill bill = query.selectFrom(QBill.bill) + .innerJoin(QBill.bill.orgMng, QOrgMng.orgMng).fetchJoin() + .where(QBill.bill.billUid.eq(billUid)) + .fetchOne(); + + return PayNoticeData.builder() + .bill(bill) + .billDetail(billKkoPay) + .build(); + } + + @Override + public void validate(Map reqParam, PayNoticeData data) { + Map m = (Map) reqParam.getOrDefault("data", new HashMap<>()); + + if (CmmnUtil.isEmpty(m.get("biller_user_key"))) + throw new EnsException(EnsErrCd.NO_REQUIRED_PARAM, "빌러유저키는 필수값 입니다."); + if (CmmnUtil.isEmpty(m.get("biller_notice_key"))) + throw new EnsException(EnsErrCd.NO_REQUIRED_PARAM, "청구서식별키는 필수값 입니다."); + + if (CmmnUtil.isEmpty(data.getBill())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 자료가 없습니다."); + if (CmmnUtil.isEmpty(data.getBillDetail())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 상세 자료가 없습니다."); + if (!data.getBillDetail().getBillerUserKey().equals(m.get("biller_user_key"))) + throw new EnsException(EnsErrCd.INVALID_DATA, "요청과 실제 빌러유저키가 일치하지 않습니다."); + } + + @Override + public void callApi(Map reqParam, PayNoticeData data) { + Bill bill = data.getBill(); + OrgMng orgMng = bill.getOrgMng(); + BillKkoPay billKkoPay = data.getBillDetail(); + + + final String useSysUrl = orgMng.getKkoBpNoticeApi(); + + + Optional.of(billKkoPay.getBillerUserKey()) + .map(billerUserKey -> createMessage(reqParam)) + .map(param -> loadReqData(data, useSysUrl, param)) + .map(param -> payUseSysApi.payNotice(useSysUrl, param, null)) + .map(response -> loadRespData(data, response)) + .map(response -> checkResponse(response)) + .map(document -> savePayNoticeInfo(data, document)) + ; + + } + + private Map createMessage(Map reqParam) { +// Map m = (Map) reqParam.getOrDefault("data", new HashMap<>()); +// Map mParam = new HashMap<>(); +// mParam.put("billerUserKey", m.get("biller_user_key")); +// mParam.put("userBirth", m.get("user_birth")); +// return mParam; + return reqParam; + } + + private Map loadReqData(PayNoticeData data, String url, Map param) { + + data.getReqAndRespInf().setUrl(url); + data.getReqAndRespInf().setReqData(CmmnUtil.toJsonString(param)); + return param; + } + + private ResponseEntity loadRespData(PayNoticeData data, ResponseEntity response) { + + data.getReqAndRespInf().setRespRawData(response.getBody()); + return response; + } + + + private PayApiRespDTO checkResponse(ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, "["+ BillLogSeCd.US +"] " + EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + PayApiRespDTO result = null; + try { + result = gson.fromJson(response.getBody(), new TypeToken>() { + }.getType()); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RESPONSE, "["+ BillLogSeCd.US +"] " + EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + } + + try { + PayUseSysResCd.valueOf(result.getResCode()); + } catch (Exception ex) { + PayApiRespDTO finalResult = result; + + if (Arrays.stream(KkoErrCd.values()).noneMatch(kkoErrCd -> kkoErrCd.name().equals(finalResult.getResCode()))) + throw new EnsException(EnsErrCd.INVALID_RES_CODE, "["+ BillLogSeCd.US +"] " + EnsErrCd.INVALID_RES_CODE.getCodeNm(), ex); + } + if (!PayUseSysResCd.OK.getCode().equals(result.getResCode())) { + result.setMessage("["+ BillLogSeCd.US +"] " + result.getMessage()); + throw new EnsException(EnsErrCd.RESPONSED_FAILURE_CODE, EnsErrCd.RESPONSED_FAILURE_CODE.getCodeNm(), result); + } + + return result; + } + + private PayApiRespDTO savePayNoticeInfo(PayNoticeData data, PayApiRespDTO document) { + KkoPayNoticeRespData noticeData = document.getData(); + + data.getBillDetail().setTitle(noticeData.getTitle()); + data.getBillDetail().setAmount(noticeData.getAmount()); + data.getBillDetail().setTaxFreeAmount(noticeData.getTaxFreeAmount()); + data.getBillDetail().setVatAmount(noticeData.getVatAmount()); + data.getBillDetail().setExpireType(noticeData.getExpireType()); + data.getBillDetail().setPayExpireDate(noticeData.getPayExpireDate()); + data.getBillDetail().setSecondPayExpireDate(noticeData.getSecondPayExpireDate()); + data.getBillDetail().setBankAccounts(CmmnUtil.isEmpty(noticeData.getBankAccounts()) ? null : gson.toJson(noticeData.getBankAccounts())); + data.getBillDetail().setDetails(CmmnUtil.isEmpty(noticeData.getDetails()) ? null : gson.toJson(noticeData.getDetails())); + data.getBillDetail().setError(FieldError.initBuilder().build()); + + billKkoPayRepository.save(data.getBillDetail()); + + return document; + } + + @Override + public PayApiRespDTO generateResult(Map reqParam, PayNoticeData data, EnsException e) { + if (e == null) { + Gson gson = new Gson(); + final String respRawData = data.getReqAndRespInf().getRespRawData(); + + PayApiRespDTO resp = gson.fromJson(respRawData, new TypeToken>() { + }.getType()); + + String resCode = resp.getResCode(); + String matchResCode = KkoErrCd.payUseSysResCdOf(resCode).name(); + if (matchResCode != null) resCode = matchResCode; + + return PayApiRespDTO.errDataBuilder() + .resCode(resCode) + .message(resp.getMessage()) + .data(resp.getData()) + .build(); + } else { + if (EnsErrCd.RESPONSED_FAILURE_CODE.equals(e.getErrCd())) { + PayApiRespDTO respDTO = (PayApiRespDTO) e.getData(); + + String resCode = respDTO.getResCode(); + String matchResCode = KkoErrCd.payUseSysResCdOf(resCode).name(); + if (matchResCode != null) resCode = matchResCode; + return PayApiRespDTO.errDataBuilder() + .resCode(resCode) + .message(respDTO.getMessage()) + .data(null) + .build(); + } else { + return PayApiRespDTO.errDataBuilder() + .resCode(e.getErrCd().getCode()) + .message(e.getMessage()) + .data(null) + .build(); + } + } + } + + @Override + public void saveHist(Map reqParam, PayNoticeData data, EnsException e) { + saveHistByUseSysNotice(reqParam, data, e); + + if (e != null) { + if (data.getBillDetail() != null) { + data.getBillDetail().setError(FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()); + billKkoPayRepository.save(data.getBillDetail()); + } + } + } + + private void saveHistByUseSysNotice(Map reqParam, PayNoticeData data, EnsException e) { + ReqAndRespInf reqAndRespInf = data.getReqAndRespInf(); + + BillHist billHist = BillHist.builder() + .billUid(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getBillUid()) + .billSe(BillSeCd.bpKko) + .reqSe(BillReqSeCd.US_NOTICE) + .orgMng(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getOrgMng()) + .linkedUuid(CmmnUtil.isEmpty(data.getBillDetail()) ? null : data.getBillDetail().getBillerUserKey()) + .requestData(reqAndRespInf.getReqData()) + .responseData(reqAndRespInf.getRespRawData()) + .error(e == null + ? FieldError.initBuilder().build() + : FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()) + .build(); + + billHistRepository.save(billHist); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/KkoPayResultService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/KkoPayResultService.java new file mode 100644 index 0000000..d7bd09b --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/KkoPayResultService.java @@ -0,0 +1,233 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.BillKkoPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.QBillKkoPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.repository.BillKkoPayRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.KkoPayResultReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PaidTypeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.QBill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayResultService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayResultData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.ReqAndRespInf; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Service +public class KkoPayResultService implements PayResultService, Map, PayApiRespDTO>> { + + private final JPAQueryFactory query; + private final PayUseSysApi payUseSysApi; + private final BillRepository billRepository; + private final BillKkoPayRepository billKkoPayRepository; + private final BillHistRepository billHistRepository; + + private Gson gson = new Gson(); + + @Override + public PayResultData getData(Map reqParam) { + + Map data = (Map) reqParam.getOrDefault("data", new HashMap<>()); + String billerNoticeKey = (String) data.get("biller_notice_key"); + Map parameters = (Map) data.getOrDefault("parameters", new HashMap<>()); + + BillKkoPay billKkoPay = query.selectFrom(QBillKkoPay.billKkoPay) + .where(QBillKkoPay.billKkoPay.billerNoticeKey.eq(billerNoticeKey)) + .fetchOne(); + String billUid = billKkoPay == null ? null : billKkoPay.getBillUid(); + if (billUid == null) billUid = ""; + Bill bill = query.selectFrom(QBill.bill) + .innerJoin(QBill.bill.orgMng, QOrgMng.orgMng).fetchJoin() + .where(QBill.bill.billUid.eq(billUid)) + .fetchOne(); + + return PayResultData.builder() + .bill(bill) + .billDetail(billKkoPay) + .build(); + } + + @Override + public void validate(Map reqParam, PayResultData data) { + + if (CmmnUtil.isEmpty(data.getBill())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 자료가 없습니다."); + if (CmmnUtil.isEmpty(data.getBillDetail())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 상세 자료가 없습니다."); + } + + @Override + public void callApi(Map reqParam, PayResultData data) { + Bill bill = data.getBill(); + OrgMng orgMng = bill.getOrgMng(); + + + final String useSysUrl = orgMng.getKkoBpPayresultApi(); + + + Optional.of(savePaidInfo(data, reqParam)) + .map(param -> loadReqData(data, useSysUrl, param)) + .map(param -> createMessage(param)) + .map(message -> payUseSysApi.payResult(useSysUrl, message, null)) + .map(response -> loadRespData(data, response)) + .map(response -> checkResponse(response))//API 응답 검증 + ; + } + + private Map savePaidInfo(PayResultData data, Map reqParam) { + Map reqData = (Map) reqParam.getOrDefault("data", new HashMap<>()); + final String paidAt = CmmnUtil.isEmpty(reqData.get("paid_at")) ? data.getBillDetail().getLastPaidAt() : (String) reqData.get("paid_at"); + final Integer payId = CmmnUtil.isEmpty(reqData.get("pay_id")) ? data.getBillDetail().getLastPayId() : (Integer) reqData.get("pay_id"); + + + + data.getBill().setPaidAt(true); + data.getBill().setPaidType(PaidTypeCd.kakaoPay); + data.getBill().setPaidDt(paidAt); + billRepository.save(data.getBill()); + + + data.getBillDetail().setLastPaidAt(paidAt); + data.getBillDetail().setLastPayId(payId); + data.getBillDetail().setError(FieldError.initBuilder().build()); + billKkoPayRepository.save(data.getBillDetail()); + + + return reqParam; + } + + + private Map loadReqData(PayResultData data, String url, Map param) { + + data.getReqAndRespInf().setUrl(url); + data.getReqAndRespInf().setReqData(CmmnUtil.toJsonString(param)); + return param; + } + + private Map createMessage(Map reqParam) { +// return reqParam; + Map data = (Map) reqParam.getOrDefault("data", new HashMap<>()); + KkoPayResultReqData kkoPayResultReqData = gson.fromJson(gson.toJson(data), KkoPayResultReqData.class); + Map result = new HashMap<>(); + result.put("data", kkoPayResultReqData); + return result; + } + + private ResponseEntity loadRespData(PayResultData data, ResponseEntity response) { + + data.getReqAndRespInf().setRespRawData(response.getBody()); + return response; + } + + private PayApiRespDTO> checkResponse(ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + PayApiRespDTO> result = null; + try { + result = gson.fromJson(response.getBody(), PayApiRespDTO.class); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RESPONSE, EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + } + + try { + PayUseSysResCd.valueOf(result.getResCode()); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RES_CODE, EnsErrCd.INVALID_RES_CODE.getCodeNm(), ex); + } + + return result; + } + + + @Override + public PayApiRespDTO> generateResult(Map reqParam, PayResultData data, EnsException e) { + if (e == null) { + final String respRawData = data.getReqAndRespInf().getRespRawData(); + return gson.fromJson(respRawData, PayApiRespDTO.class); + } else { + return PayApiRespDTO.>errDataBuilder() + .resCode(e.getErrCd().getCode()) + .message(e.getMessage()) + .data(null) + .build(); + } + } + + @Override + public void saveHist(Map reqParam, PayResultData data, EnsException e) { + saveHistByUseSysPayResult(reqParam, data, e); + + if (e != null) { + if (data.getBillDetail() != null) { + data.getBillDetail().setError(FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()); + billKkoPayRepository.save(data.getBillDetail()); + } + } + + } + + private void saveHistByUseSysPayResult(Map reqParam, PayResultData data, EnsException e) { + + ReqAndRespInf reqAndRespInf = data.getReqAndRespInf(); + + String requestData = reqAndRespInf.getReqData(); + if (e != null) { + switch (e.getErrCd()) { + case NO_DATA_FOUND: + case INVALID_REQUEST: + requestData = gson.toJson(reqParam); + break; + } + } + + + BillHist billHist = BillHist.builder() + .billUid(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getBillUid()) + .billSe(BillSeCd.bpKko) + .reqSe(BillReqSeCd.US_PAYRSLT) + .orgMng(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getOrgMng()) + .linkedUuid(CmmnUtil.isEmpty(data.getBillDetail()) ? null : data.getBillDetail().getBillerUserKey()) + .requestData(requestData) + .responseData(reqAndRespInf.getRespRawData()) + .error(e == null + ? FieldError.initBuilder().build() + : FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()) + .build(); + + billHistRepository.save(billHist); + + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/KkoPayUrlService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/KkoPayUrlService.java new file mode 100644 index 0000000..036d640 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/KkoPayUrlService.java @@ -0,0 +1,421 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.api.BillKkoPayApiSpec; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.BillKkoPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.QBillKkoPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.repository.BillKkoPayRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.KkoPayUrlRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillLogSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.QBill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayUrlService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayUrlData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.ReqAndRespInf; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Service +public class KkoPayUrlService implements PayUrlService, String, PayApiRespDTO>> { + + private final JPAQueryFactory query; + private final BillKkoPayApiSpec billKkoPayApi; + private final BillKkoPayRepository billKkoPayRepository; + private final BillHistRepository billHistRepository; + private final PayUseSysApi payUseSysApi; + + private Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + + private enum DataKeys { + gnrUrlReqMessage, + gnrUrlRespMessage, + gnrReUrlReqMessage, + gnrReUrlRespMessage, + } + + @Override + public PayUrlData getData(String billUid) { + if (billUid == null) billUid = ""; + Bill bill = query.selectFrom(QBill.bill) + .innerJoin(QBill.bill.orgMng, QOrgMng.orgMng).fetchJoin() + .where(QBill.bill.billUid.eq(billUid)) + .fetchOne(); + BillKkoPay billKkoPay = query.selectFrom(QBillKkoPay.billKkoPay) + .where(QBillKkoPay.billKkoPay.billUid.eq(billUid)) + .fetchOne(); + + return PayUrlData.builder() + .bill(bill) + .billDetail(billKkoPay) + .build(); + } + + @Override + public void validate(String billUid, PayUrlData data) { + + if (CmmnUtil.isEmpty(data.getBill())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 자료가 없습니다."); + if (CmmnUtil.isEmpty(data.getBillDetail())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 상세 자료가 없습니다."); + if (!CmmnUtil.isEmpty(data.getBillDetail().getLastPayId())) + throw new EnsException(EnsErrCd.PAYMENT_ALREADY_CMPLTED, "결제가 완료된 자료 입니다."); + if (!CmmnUtil.isEmpty(data.getBillDetail().getUrl())) + throw new EnsException(EnsErrCd.URL_ALREADY_CREATED, "결제URL이 생성된 자료 입니다."); + } + + @Override + public void callApi(String billUid, PayUrlData data) { + Bill bill = data.getBill(); + OrgMng orgMng = bill.getOrgMng(); + + + final String useSysUrl = orgMng.getKkoBpUrlApi(); + final String billerCode = orgMng.getKkoBpBillerCode(); + final String authorization = orgMng.getKkoBpAuthorization(); + + + + Optional.ofNullable(data.getBillDetail()) + .map(billKkoPay -> createMessage(billKkoPay.getBillerUserKey())) + .map(param -> loadReqData(data, useSysUrl, param)) + .map(param -> payUseSysApi.payUrl(useSysUrl, param, null)) + .map(response -> loadRespData(data, response)) + .map(response -> checkResponse(response)) + .map(document -> savePayUrlInfo(data, document)) + .map(document -> createGnrUrlMessage(data, document)) + .map(param -> loadGnrUrlReqData(data, param)) + .map(param -> billKkoPayApi.url(billerCode, authorization, param)) + .map(response -> loadGnrUrlRespData(data, response)) + .map(response -> checkGnrUrlResponse(false, response)) + .map(respData -> saveUrl(data, respData)) + .filter(respData -> respData == null) + .map(respData -> loadGnrReUrlReqData(data)) + .map(param -> billKkoPayApi.reUrl(billerCode, authorization, param)) + .map(response -> checkGnrUrlResponse(true, response)) + .map(respData -> saveUrl(data, respData)) + ; + } + + private Map createMessage(String billerUserKey) { + Map data = new HashMap<>(); + data.put("billerUserKey", billerUserKey); + Map param = new HashMap<>(); + param.put("data", data); + return param; + } + + private Map loadReqData(PayUrlData data, String url, Map param) { + + data.getReqAndRespInf().setUrl(url); + data.getReqAndRespInf().setReqData(CmmnUtil.toJsonString(param)); + return param; + } + + private ResponseEntity loadRespData(PayUrlData data, ResponseEntity response) { + + data.getReqAndRespInf().setRespRawData(response.getBody()); + return response; + } + + + private PayApiRespDTO checkResponse(ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, "["+ BillLogSeCd.US +"] " + EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + PayApiRespDTO result = null; + try { + result = gson.fromJson(response.getBody(), new TypeToken>() { + }.getType()); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RESPONSE, "["+ BillLogSeCd.US +"] " + EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + } + + try { + PayUseSysResCd.valueOf(result.getResCode()); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RES_CODE, "["+ BillLogSeCd.US +"] " + EnsErrCd.INVALID_RES_CODE.getCodeNm(), ex); + } + if (!PayUseSysResCd.OK.getCode().equals(result.getResCode())) { + result.setMessage("["+ BillLogSeCd.US +"] " + result.getMessage()); + throw new EnsException(EnsErrCd.RESPONSED_FAILURE_CODE, EnsErrCd.RESPONSED_FAILURE_CODE.getCodeNm(), result); + } + + return result; + } + + private PayApiRespDTO savePayUrlInfo(PayUrlData data, PayApiRespDTO document) { + final KkoPayUrlRespData urlData = document.getData(); + + data.getBillDetail().setBilledYearMonth(urlData.getBilledYearMonth()); + data.getBillDetail().setOrdinal(urlData.getOrdinal()); + data.getBillDetail().setBillerNoticeKey(data.getBillDetail().getBillUid()); + data.getBillDetail().setExpireAt(urlData.getExpireAt()); + data.getBillDetail().setParameters(CmmnUtil.isEmpty(urlData.getParameters()) ? null : gson.toJson(urlData.getParameters())); + data.getBillDetail().setCustomUrl(CmmnUtil.isEmpty(urlData.getCustomUrl()) ? null : gson.toJson(urlData.getCustomUrl())); + + billKkoPayRepository.save(data.getBillDetail()); + + return document; + } + + private String createGnrUrlMessage(PayUrlData data, PayApiRespDTO document) { + final OrgMng orgMng = data.getBill().getOrgMng(); + final BillKkoPay billKkoPay = data.getBillDetail(); + final KkoPayUrlRespData urlData = document.getData(); + + Map parameters = null; + parameters = CmmnUtil.isEmpty(urlData.getParameters()) ? new HashMap<>() : urlData.getParameters(); + parameters.put("orgCd", orgMng == null ? null : orgMng.getOrgCd()); + + Map param = new HashMap(); + param.put("biller_user_key", billKkoPay.getBillerUserKey()); //[필수] 기관에서 관리하는 해당 고객번호 혹은 계약번호 + param.put("billed_year_month", urlData.getBilledYearMonth()); //[선택] 청구 연월(YYYYMM) 형식, 없을 시 생략 + param.put("ordinal", urlData.getOrdinal()); //[선택] 동일 고객번호, 청구 연월의 복수개 청구서 발생 등 몇번째 청구인지 구분 + // 중요 : biller_notice_key 사용 할 경우 청구서 조회, 납부 가능 조회 응답에도 필수로 포함, 아니면 오류로 결제 진행이 안됨 + /*param.put("biller_notice_key", billKkoPay.getBillerNoticeKey());*///[선택] 개별 청구서를 식별하는 키 값. 처리 결과 조회에 사용되므로, 유니크한 값을 가지도록 생성 + param.put("expire_at", urlData.getExpireAt()); //[필수] URL 만료일, YYYYMMDDHH24MISS + param.put("parameters", parameters); //[선택] key/value 형태의 청구서 조회 등 API 호출 시 함께 전달할 값 +// param.put("parameters", urlData.getParameters()); //[선택] key/value 형태의 청구서 조회 등 API 호출 시 함께 전달할 값 + param.put("custom_url", urlData.getCustomUrl()); //[선택] 사용자가 청구서 결제 시 호출(KKO -> 이용시스템)할 청구서조회/납부가능조회/납부결과전달 API URL + + + Map m = new HashMap(); + m.put("data", param); + + return gson.toJson(m); + } + + private String loadGnrUrlReqData(PayUrlData data, String message) { + + data.getReqAndRespInf().getEtc().put(DataKeys.gnrUrlReqMessage.name(), message); + + return message; + } + + private ResponseEntity loadGnrUrlRespData(PayUrlData data, ResponseEntity response) { + + data.getReqAndRespInf().getEtc().put(DataKeys.gnrUrlRespMessage.name(), response.getBody()); + return response; + } + + private PayApiRespDTO> checkGnrUrlResponse(boolean isReurl, ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, "["+ BillLogSeCd.VD +"] " + EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + if (!isReurl && response.getBody().contains("Read timed out")) + return null; + PayApiRespDTO> result = null; + try { + result = gson.fromJson(response.getBody(), new TypeToken>>() { + }.getType()); + } catch (Exception ex) { + if (isReurl) + throw new EnsException(EnsErrCd.INVALID_RESPONSE, "["+ BillLogSeCd.VD +"] " + EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + else + return null; + } + + if (!"OK".equals(result.getResCode())) + if (!isReurl && "E818".equals(result.getResCode())) + return null; + else { + result.setMessage("["+ BillLogSeCd.VD +"] " + result.getMessage()); + throw new EnsException(EnsErrCd.RESPONSED_FAILURE_CODE, EnsErrCd.RESPONSED_FAILURE_CODE.getCodeNm(), result); + } + + return result; + } + + private PayApiRespDTO> saveUrl(PayUrlData data, PayApiRespDTO> respData) { + if (!CmmnUtil.isEmpty(respData)) { + Map body = respData.getData(); + data.getBillDetail().setUrl((String) body.get("url")); + data.getBillDetail().setError(FieldError.initBuilder().build()); + billKkoPayRepository.save(data.getBillDetail()); + } + + return respData; + } + + private String loadGnrReUrlReqData(PayUrlData data) { + + final String message = (String) data.getReqAndRespInf().getEtc().get(DataKeys.gnrReUrlReqMessage.name()); + data.getReqAndRespInf().getEtc().put(DataKeys.gnrReUrlReqMessage.name(), message); + + return message; + } + + @Override + public PayApiRespDTO> generateResult(String billUid, PayUrlData data, EnsException e) { + if (e == null) { + final String urlResponse = (String) data.getReqAndRespInf().getEtc().get(DataKeys.gnrUrlRespMessage.name()); + final String reurlResponse = (String) data.getReqAndRespInf().getEtc().get(DataKeys.gnrReUrlRespMessage.name()); + if (CmmnUtil.isEmpty(reurlResponse)) + return gson.fromJson(urlResponse, new TypeToken>>() { + }.getType()); + else + return gson.fromJson(reurlResponse, new TypeToken>>() { + }.getType()); + } else { + if (EnsErrCd.URL_ALREADY_CREATED.equals(e.getErrCd())) { + Map m = new HashMap<>(); + m.put("url", data.getBillDetail().getUrl()); + return PayApiRespDTO.>okBuilder() + .data(m) + .build(); + } else if (EnsErrCd.RESPONSED_FAILURE_CODE.equals(e.getErrCd())) { + PayApiRespDTO respDTO = (PayApiRespDTO) e.getData(); + return PayApiRespDTO.>errDataBuilder() + .resCode(respDTO.getResCode()) + .message(respDTO.getMessage()) + .data(null) + .build(); + } else { + return PayApiRespDTO.>errDataBuilder() + .resCode(e.getErrCd().getCode()) + .message(e.getMessage()) + .data(null) + .build(); + } + } + } + + @Override +// @Transactional(propagation = Propagation.REQUIRED) + public void saveHist(String billUid, PayUrlData data, EnsException e) { + saveHistByGetUrlInf(data, e); + saveHistByGnrUrl(data, e); + saveHistByGnrReUrl(data, e); + + if (e != null) { + if (data.getBillDetail() != null) { + data.getBillDetail().setError(FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()); + billKkoPayRepository.save(data.getBillDetail()); + } + } + } + + private void saveHistByGetUrlInf(PayUrlData data, EnsException e) { + + ReqAndRespInf reqAndRespInf = data.getReqAndRespInf(); + final String requestData = reqAndRespInf.getReqData(); + final String responseData = reqAndRespInf.getRespRawData(); + + if (!CmmnUtil.isEmpty(requestData)) { + BillHist billHist = BillHist.builder() + .billUid(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getBillUid()) + .billSe(BillSeCd.bpKko) + .reqSe(BillReqSeCd.US_URLINF) + .orgMng(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getOrgMng()) + .linkedUuid(CmmnUtil.isEmpty(data.getBillDetail()) ? null : data.getBillDetail().getBillerUserKey()) + .requestData(requestData) + .responseData(responseData) + .error(e == null + ? FieldError.initBuilder().build() + : FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()) + .build(); + + billHistRepository.save(billHist); + } + + } + + private void saveHistByGnrUrl(PayUrlData data, EnsException e) { + + ReqAndRespInf reqAndRespInf = data.getReqAndRespInf(); + final String requestData = (String) reqAndRespInf.getEtc().get(DataKeys.gnrUrlReqMessage.name()); + final String responseData = (String) reqAndRespInf.getEtc().get(DataKeys.gnrUrlRespMessage.name()); + + if (!CmmnUtil.isEmpty(requestData)) { + BillHist billHist = BillHist.builder() + .billUid(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getBillUid()) + .billSe(BillSeCd.bpKko) + .reqSe(BillReqSeCd.VD_URL) + .orgMng(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getOrgMng()) + .linkedUuid(CmmnUtil.isEmpty(data.getBillDetail()) ? null : data.getBillDetail().getBillerUserKey()) + .requestData(requestData) + .responseData(responseData) + .error(e == null + ? FieldError.initBuilder().build() + : FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()) + .build(); + + billHistRepository.save(billHist); + } + + } + + private void saveHistByGnrReUrl(PayUrlData data, EnsException e) { + + ReqAndRespInf reqAndRespInf = data.getReqAndRespInf(); + final String requestData = (String) reqAndRespInf.getEtc().get(DataKeys.gnrReUrlReqMessage.name()); + final String responseData = (String) reqAndRespInf.getEtc().get(DataKeys.gnrReUrlRespMessage.name()); + + if (!CmmnUtil.isEmpty(requestData)) { + BillHist billHist = BillHist.builder() + .billUid(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getBillUid()) + .billSe(BillSeCd.bpKko) + .reqSe(BillReqSeCd.VD_REURL) + .orgMng(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getOrgMng()) + .linkedUuid(CmmnUtil.isEmpty(data.getBillDetail()) ? null : data.getBillDetail().getBillerUserKey()) + .requestData(requestData) + .responseData(responseData) + .error(e == null + ? FieldError.initBuilder().build() + : FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()) + .build(); + + billHistRepository.save(billHist); + + if (e != null) { + if (data.getBillDetail() != null) { + data.getBillDetail().setError(FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()); + billKkoPayRepository.save(data.getBillDetail()); + } + } + } + + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/CustomUrl.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/CustomUrl.java new file mode 100644 index 0000000..9f1da94 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/CustomUrl.java @@ -0,0 +1,36 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@Builder +@Data +@Schema(name = "CustomUrl") +public class CustomUrl { + @NotEmpty(message = "청구서조회URL은 필수 입력값 입니다.") + @Schema(required = true, title = "청구서 조회 URL", example = "http://wwww.xit.co.kr/kakao/notice") + + @JsonAlias({"noticeUrl"}) + @SerializedName(value = "notice_url", alternate = {"noticeUrl"}) + private String noticeUrl; + + @NotEmpty(message = "납부가능조회URL은 필수 입력값 입니다.") + @Schema(required = true, title = "납부 가능 조회 URL", example = "http://wwww.xit.co.kr/kakao/prepay") + @JsonAlias({"prepayUrl"}) + @SerializedName(value = "prepay_url", alternate = {"prepayUrl"}) + private String prepayUrl; + + @NotEmpty(message = "납부결과전달URL은 필수 입력값 입니다.") + @Schema(required = true, title = "납부 결과 전달 URL", example = "http://wwww.xit.co.kr/kakao/pay-result") + @JsonAlias({"payResultUrl"}) + @SerializedName(value = "pay_result_url", alternate = {"payResultUrl"}) + private String payResultUrl; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/KkoPayBankAccounts.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/KkoPayBankAccounts.java new file mode 100644 index 0000000..02291c0 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/KkoPayBankAccounts.java @@ -0,0 +1,43 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.validation.constraints.NotBlank; + +/** + * 카카오페이 계좌송금수단 사용 시 계좌정보 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +@ToString +public class KkoPayBankAccounts { + + @NotBlank(message = "청구서명은 필수 입력값 입니다.") + @Schema(required = true, title = "청구서명", example = "테스트청구서") + @JsonProperty("bank_code") + @JsonAlias({"bankCode"}) + @SerializedName(value = "bank_code", alternate = {"bankCode"}) + private String bankCode; + @JsonProperty("account_no") + @JsonAlias({"accountNo"}) + @SerializedName(value = "account_no", alternate = {"accountNo"}) + private String accountNo; + @JsonProperty("holder_name") + @JsonAlias({"holderName"}) + @SerializedName(value = "holder_name", alternate = {"holderName"}) + private String holderName; + @JsonProperty("sender_name") + @JsonAlias({"senderName"}) + @SerializedName(value = "sender_name", alternate = {"senderName"}) + private String senderName; + @JsonProperty("account_type") + @JsonAlias({"accountType"}) + @SerializedName(value = "account_type", alternate = {"accountType"}) + private String accountType; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/KkoPayNoticeRespData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/KkoPayNoticeRespData.java new file mode 100644 index 0000000..cddb301 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/KkoPayNoticeRespData.java @@ -0,0 +1,68 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.validator.constraints.Length; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Map; + +/** + * 카카오페이 결제정보 응답데이터 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +@ToString +public class KkoPayNoticeRespData { + + @NotBlank(message = "청구서명은 필수 입력값 입니다.") + @Schema(required = true, title = "청구서명", example = "테스트청구서") + private String title; + @NotNull(message = "납부 요청금액은 필수 입력값 입니다.") + @Schema(required = true, title = "납부 요청금액", example = "1000") + private Integer amount; + @Schema(required = false, title = "비과세 금액", example = "0") + @JsonProperty("tax_free_amount") + @JsonAlias({"taxFreeAmount"}) + @SerializedName(value = "tax_free_amount", alternate = {"taxFreeAmount"}) + private Integer taxFreeAmount; + @Schema(required = false, title = "부가세 금액", example = "0") + @JsonProperty("vat_amount") + @JsonAlias({"vatAmount"}) + @SerializedName(value = "vat_amount", alternate = {"vatAmount"}) + private Integer vatAmount; + @Schema(required = false, title = "납기 안내타입", example = "D1") + @JsonProperty("expire_type") + @JsonAlias({"expireType"}) + @SerializedName(value = "expire_type", alternate = {"expireType"}) + private String expireType; + @NotNull(message = "첫번째 납기일은 필수 입력값 입니다.") + @Length(max = 8, message = "첫번째 납기일의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "첫번째 납기일", example = "20230212") + @JsonProperty("pay_expire_date") + @JsonAlias({"payExpireDate"}) + @SerializedName(value = "pay_expire_date", alternate = {"payExpireDate"}) + private String payExpireDate; + @Length(max = 8, message = "두번째 납기일의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "두번째 납기일", example = "20230212") + @JsonProperty("second_pay_expire_date") + @JsonAlias({"secondPayExpireDate"}) + @SerializedName(value = "second_pay_expire_date", alternate = {"secondPayExpireDate"}) + private String secondPayExpireDate; + @Valid + @Schema(required = false, title = "계좌송금수단 사용 시 계좌정보", example = " ") + @JsonProperty("bank_accounts") + @JsonAlias({"bankAccounts"}) + @SerializedName(value = "bank_accounts", alternate = {"bankAccounts"}) + private List bankAccounts; + @Schema(required = false, title = "청구서 상세정보", example = " ") + private List> details; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/KkoPayResultReqData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/KkoPayResultReqData.java new file mode 100644 index 0000000..f814954 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/KkoPayResultReqData.java @@ -0,0 +1,124 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import java.util.Map; + +@Getter +@ToString +@EqualsAndHashCode +@Schema(name = "KkoPayResultReqData") +public class KkoPayResultReqData { + + @Length(max = 50, message = "사용자 식별키의 최대 길이를 초과 했습니다.") + @NotBlank( message = "사용자 식별키는 필수 조건 입니다.") + @Schema(required = true, title = "사용자 식별키", example = " ") + @JsonProperty("biller_user_key") + @JsonAlias({"billerUserKey"}) + @SerializedName(value = "biller_user_key", alternate = {"billerUserKey"}) + private String billerUserKey; + @Length(max = 6, message = "청구연월의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "청구연월(YYYYMM 형식), 없을 시 생략", example = " ") + @JsonProperty("billed_year_month") + @JsonAlias({"billedYearMonth"}) + @SerializedName(value = "billed_year_month", alternate = {"billedYearMonth"}) + private String billedYearMonth; + @Length(max = 24, message = "동일 고객번호의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "동일 고객번호, 청구 연월의 복수 개 청구서 발생 등 몇 번째 청구인지 구분을 위해 사용", example = " ") + private String ordinal; + @Length(max = 80, message = "개별 청구서 식별키의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "개별 청구서를 식별하는 키 값", example = " ") + @JsonProperty("biller_notice_key") + @JsonAlias({"billerNoticeKey"}) + @SerializedName(value = "biller_notice_key", alternate = {"billerNoticeKey"}) + private String billerNoticeKey; + @Schema(required = false, title = "URL 생성 시 전달한 파라미터", example = " ") + private Map parameters; + @NotBlank(message = "결제수단은 필수 조건 입니다.") + @Schema(required = true, title = "결제수단(CARD/MONEY/MONEY_TRANSFER)", example = " ") + @JsonProperty("pay_by") + @JsonAlias({"payBy"}) + @SerializedName(value = "pay_by", alternate = {"payBy"}) + private String payBy; + @NotBlank(message = "결제타입은 필수 조건 입니다.") + @Length(max = 1, message = "결제타입의 최대길이를 초과 했습니다.") + @Pattern(regexp = "(P|C)", message = "결제타입의 값은 P 또는 C 만 입력 하실 수 있습니다.") + @Schema(required = true, title = "결제타입(P:결제, C:취소)", example = " ") + @JsonProperty("pay_type") + @JsonAlias({"payType"}) + @SerializedName(value = "pay_type", alternate = {"payType"}) + private String payType; + @Length(max = 6, message = "결제수단 상세1의 최대길이를 초과 했습니다.") + @Schema(required = false, title = "결제수단 상세1(카드번호 앞 6자리). 카드인 경우 카드번호 앞 6자리", example = " ") + @JsonProperty("pay_detail1") + @JsonAlias({"payDetail1"}) + @SerializedName(value = "pay_detail1", alternate = {"payDetail1"}) + private String payDetail1; + @Length(max = 20, message = "결제수단 상세2(카드사 구분 코드)의 최대길이를 초과 했습니다.") + @Schema(required = false, title = "결제수단 상세2. 카드사 구분 코드", example = " ") + @JsonProperty("pay_detail2") + @JsonAlias({"payDetail2"}) + @SerializedName(value = "pay_detail2", alternate = {"payDetail2"}) + private String payDetail2; + @Schema(required = false, title = "결제수단 상세3. 공백", example = " ") + @JsonProperty("pay_detail3") + @JsonAlias({"payDetail3"}) + @SerializedName(value = "pay_detail3", alternate = {"payDetail3"}) + private String payDetail3; + @NotNull(message = "납부요청 금액은 필수 조건 입니다.") + @Schema(required = true, title = "납부요청 금액", example = " ") + private Integer amount; + @NotNull(message = "결제금액/취소금액은 필수 조건 입니다.") + @Schema(required = true, title = "거래구분이 P 인 경우 양수(결제금액), C 인 경우 음수(-취소금액)", example = " ") + @JsonProperty("pay_amount") + @JsonAlias({"payAmount"}) + @SerializedName(value = "pay_amount", alternate = {"payAmount"}) + private Integer payAmount; + @Length(max = 10, message = "결제 수수료 부과구분은 필수 조건 입니다.") + @Schema(required = true, title = "결제 수수료 금액 부과구분(BEFORE: 선취, AFTER: 후취, NONE: 부과 안함)", example = " ") + @JsonProperty("pay_fee_type") + @JsonAlias({"payFeeType"}) + @SerializedName(value = "pay_fee_type", alternate = {"payFeeType"}) + private String payFeeType; + @NotNull(message = "결제 수수료 공급가액은 필수 조건 입니다.") + @Schema(required = true, title = "결제 수수료 금액_공급가액", example = " ") + @JsonProperty("pay_fee") + @JsonAlias({"payFee"}) + @SerializedName(value = "pay_fee", alternate = {"payFee"}) + private Integer payFee; + @NotNull(message = "결제 수수료 부가세는 필수 조건 입니다.") + @Schema(required = true, title = "결제 수수료 금액_부가세", example = " ") + @JsonProperty("pay_fee_tax") + @JsonAlias({"payFeeTax"}) + @SerializedName(value = "pay_fee_tax", alternate = {"payFeeTax"}) + private Integer payFeeTax; + @Length(max = 8, message = "정산예정일의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "정산예정일(YYYYMMDD)", example = " ") + @JsonProperty("adjust_date") + @JsonAlias({"adjustDate"}) + @SerializedName(value = "adjust_date", alternate = {"adjustDate"}) + private String adjustDate; + @NotBlank(message = "결제일시는 필수 조건 입니다.") + @Length(max = 8, message = "결제일시의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "결제일시(YYYYMMDDHH24MISS)", example = " ") + @JsonProperty("paid_at") + @JsonAlias({"paidAt"}) + @SerializedName(value = "paid_at", alternate = {"paidAt"}) + private String paidAt; + @NotNull(message = "카카오페이 결제번호는 필수 조건 입니다.") + @Schema(required = true, title = "카카오페이 결제번호", example = " ") + @JsonProperty("pay_id") + @JsonAlias({"payId"}) + @SerializedName(value = "pay_id", alternate = {"payId"}) + private Integer payId; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/KkoPayUrlRespData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/KkoPayUrlRespData.java new file mode 100644 index 0000000..fab2c04 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/process/model/KkoPayUrlRespData.java @@ -0,0 +1,46 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import java.util.Map; + +/** + * 카카오페이 결제정보 응답데이터 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +@ToString +public class KkoPayUrlRespData { + @Schema(required = false, title = "청구 연월", example = " ") + @JsonProperty("billed_year_month") + @JsonAlias({"billedYearMonth"}) + @SerializedName(value = "billed_year_month", alternate = {"billedYearMonth"}) + private String billedYearMonth; + + @Schema(required = false, title = "동일 고객번호 구분 값", example = " ") + private String ordinal; + + @NotBlank(message = "URL 만료일은 필수 조건 입니다.") + @Schema(required = true, title = "URL 만료일", example = "20200130235959") + @JsonProperty("expire_at") + @JsonAlias({"expireAt"}) + @SerializedName(value = "expire_at", alternate = {"expireAt"}) + private String expireAt; + + @Schema(required = false, title = "API 호출 시 함께 전달할 JSON형태의 문자열", example = " ") + private Map parameters; + + @Valid + @JsonProperty("custom_url") + @JsonAlias({"customUrl"}) + @SerializedName(value = "custom_url", alternate = {"customUrl"}) + private CustomUrl customUrl; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/repair/kit/RepairKkoPayResultTransferFail.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/repair/kit/RepairKkoPayResultTransferFail.java new file mode 100644 index 0000000..f29ec3e --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/repair/kit/RepairKkoPayResultTransferFail.java @@ -0,0 +1,27 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.repair.kit; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.kit.RepairPayResultTransferFail; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.model.RepairPayRsltFwdFailSearchDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.Builder; + + +public class RepairKkoPayResultTransferFail extends RepairPayResultTransferFail { + @Builder + public RepairKkoPayResultTransferFail(JPAQueryFactory query, RepairPayRsltFwdFailSearchDTO searchDTO) { + this.query = query; + this.searchDTO = searchDTO; + } + + @Override + protected String getPayResultApiUrl(OrgMng orgMng) { + return orgMng.getKkoBpPayresultApi(); + } + + @Override + protected BillSeCd getBillSeCd() { + return BillSeCd.bpKko; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/api/BillNvEasyPayApi.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/api/BillNvEasyPayApi.java new file mode 100644 index 0000000..d11c6bd --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/api/BillNvEasyPayApi.java @@ -0,0 +1,265 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.api; + +import cokr.xit.ens.core.utils.CmmnUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.*; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import java.net.URI; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Component +//@Profile({"!local-test"}) +public class BillNvEasyPayApi implements BillNvEasyPayApiSpec { + + @Value("${contract.naver.pay.easy.host}") + private String HOST; + @Value("${contract.naver.pay.easy.api.pay-apply}") + private String API_PAY_APPLY; + @Value("${contract.naver.pay.easy.api.pay-cancel}") + private String API_PAY_CANCEL; + @Value("${contract.naver.pay.easy.api.pay-hist}") + private String API_PAY_HIST; + @Value("${contract.naver.pay.easy.api.purchase-confirm}") + private String API_PURCHASE_CONFIRM; + @Value("${contract.naver.pay.easy.api.point-save}") + private String API_POINT_SAVE; + @Value("${contract.naver.pay.easy.api.cash-amount}") + private String API_CASH_AMOUNT; + + + /** + *
메소드 설명: API 호출
+     * 
+ * + * @param method + * @param url + * @param body + * @param headers + * @return ResponseEntity 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 4. + * @apiNote: 사이트 참조 https://e2e2e2.tistory.com/15 + */ + private ResponseEntity callApi(HttpMethod method, String url, Object body, HttpHeaders headers) { + + StringBuffer sb = new StringBuffer(); + ResponseEntity responseEntity = null; + try { + + HttpEntity entity = null; + UriComponents uri = null; + switch (method) { + case GET: + entity = new HttpEntity<>(headers); + uri = UriComponentsBuilder + .fromHttpUrl(String.format("%s?%s", url, body == null ? "" : body)) +// .encode(StandardCharsets.UTF_8) //"%"기호가 "%25"로 인코딩 발생하여 주석처리 함. + .build(false); + break; + case POST: + entity = new HttpEntity<>(body, headers); + uri = UriComponentsBuilder + .fromHttpUrl(url) + .encode(StandardCharsets.UTF_8) + .build(); + break; + + default: + break; + } + + + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + factory.setConnectTimeout(5000); + factory.setReadTimeout(60000); + RestTemplate restTemplate = new RestTemplate(factory); + sb.append("\n url => " + uri.toString()) + .append("\n method => " + method) + .append("\n headers => " + entity.getHeaders().toString()) + .append("\n body => " + entity.getBody()); + responseEntity = restTemplate.exchange(URI.create(uri.toString()), method, entity, String.class); + + /* + * HttpStatus 정보 확인 방법 + * -.코드: responseEntity.getStatusCodeValue() + * -.메시지: responseEntity.getStatusCode() + */ + + } catch (HttpServerErrorException e) { + responseEntity = new ResponseEntity(e.getResponseBodyAsString(), e.getStatusCode()); + log.error("call API 서버오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } catch (HttpClientErrorException e) { + responseEntity = new ResponseEntity(e.getResponseBodyAsString(), e.getStatusCode()); + log.error("call API 클라이언트오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } catch (RestClientException e) { + responseEntity = new ResponseEntity(e.getMessage(), HttpStatus.REQUEST_TIMEOUT); + log.error("RestAPI 호출 오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } catch (Exception e) { + responseEntity = new ResponseEntity(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + log.error("call API 기타오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e)); + } finally { + log.info("네이버페이 간편결제 API\n[ REQUEST ]-----------------------------------------------------------------------\n{}\n[ RESPONSE ]-----------------------------------------------------------------------\n{}", sb.toString(), responseEntity.getBody()); + } + + + return responseEntity; + } + + + @Override + public ResponseEntity payApply(String partnerId, String clientId, String clientSecret, LinkedMultiValueMap param) { + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_FORM_URLENCODED, Charset.forName("utf-8"))); + headers.set("X-Naver-Client-Id", clientId); + headers.set("X-Naver-Client-Secret", clientSecret); + headers.set("X-Xit-PartnerId", partnerId); + + + StringBuilder url = new StringBuilder() + .append(this.HOST) + .append(this.API_PAY_APPLY.replace("{partnerId}", partnerId == null ? "" : partnerId)); + + + MultiValueMap body = param; + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), body, headers); + return resp; + } + + @Override + public ResponseEntity payCancel(String partnerId, String clientId, String clientSecret, LinkedMultiValueMap param) { + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_FORM_URLENCODED, Charset.forName("utf-8"))); + headers.set("X-Naver-Client-Id", clientId); + headers.set("X-Naver-Client-Secret", clientSecret); + headers.set("X-Xit-PartnerId", partnerId); + + + StringBuilder url = new StringBuilder() + .append(this.HOST) + .append(this.API_PAY_CANCEL.replace("{partnerId}", partnerId == null ? "" : partnerId)); + + + MultiValueMap body = param; + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), body, headers); + return resp; + } + + @Override + public ResponseEntity payHist(String partnerId, String clientId, String clientSecret, Map param) { + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + headers.set("X-Naver-Client-Id", clientId); + headers.set("X-Naver-Client-Secret", clientSecret); + headers.set("X-Xit-PartnerId", partnerId); + + + StringBuilder url = new StringBuilder() + .append(this.HOST) + .append(this.API_PAY_HIST.replace("{partnerId}", partnerId == null ? "" : partnerId)); + + + String jsonStr = CmmnUtil.toJsonString(param); + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers); + return resp; + } + + @Override + public ResponseEntity purchaseConfirm(String partnerId, String clientId, String clientSecret, String paymentId, String requester) { + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_FORM_URLENCODED, Charset.forName("utf-8"))); + headers.set("X-Naver-Client-Id", clientId); + headers.set("X-Naver-Client-Secret", clientSecret); + headers.set("X-Xit-PartnerId", partnerId); + + + StringBuilder url = new StringBuilder() + .append(this.HOST) + .append(this.API_PURCHASE_CONFIRM.replace("{partnerId}", partnerId == null ? "" : partnerId)); + + + MultiValueMap param = new LinkedMultiValueMap<>(); + param.add("paymentId", paymentId); + param.add("requester", requester); + MultiValueMap body = param; + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), body, headers); + return resp; + } + + @Override + public ResponseEntity pointSave(String partnerId, String clientId, String clientSecret, String paymentId) { + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_FORM_URLENCODED, Charset.forName("utf-8"))); + headers.set("X-Naver-Client-Id", clientId); + headers.set("X-Naver-Client-Secret", clientSecret); + headers.set("X-Xit-PartnerId", partnerId); + + + StringBuilder url = new StringBuilder() + .append(this.HOST) + .append(this.API_POINT_SAVE.replace("{partnerId}", partnerId == null ? "" : partnerId)); + + + MultiValueMap param = new LinkedMultiValueMap<>(); + param.add("paymentId", paymentId); + MultiValueMap body = param; + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), body, headers); + return resp; + } + + @Override + public ResponseEntity cashAmount(String partnerId, String clientId, String clientSecret, ArrayList paymentIds) { + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + headers.set("X-Naver-Client-Id", clientId); + headers.set("X-Naver-Client-Secret", clientSecret); + headers.set("X-Xit-PartnerId", partnerId); + + + StringBuilder url = new StringBuilder() + .append(this.HOST) + .append(this.API_POINT_SAVE.replace("{partnerId}", partnerId == null ? "" : partnerId)); + + + Map> param = new HashMap<>(); + param.put("paymentIds", paymentIds); + String jsonStr = CmmnUtil.toJsonString(param); + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers); + return resp; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/api/BillNvEasyPayApiSpec.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/api/BillNvEasyPayApiSpec.java new file mode 100644 index 0000000..c3d63fc --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/api/BillNvEasyPayApiSpec.java @@ -0,0 +1,80 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.api; + +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; + +import java.util.ArrayList; +import java.util.Map; + +/** + * 네이버페이 간편결제 API + */ +public interface BillNvEasyPayApiSpec { + /** + * 결제 승인 + * + * @param partnerId 파트너 ID + * @param clientId 발급된 client id + * @param clientSecret 발급된 client secret + * @param param 요청파라미터 + * @return + */ + ResponseEntity payApply(String partnerId, String clientId, String clientSecret, LinkedMultiValueMap param); + + /** + * 결제취소 + * + * @param partnerId 파트너 ID + * @param clientId 발급된 client id + * @param clientSecret 발급된 client secret + * @param param 요청파라미터 + * @return + */ + ResponseEntity payCancel(String partnerId, String clientId, String clientSecret, LinkedMultiValueMap param); + + /** + * 결제내역조회 + * + * @param partnerId 파트너 ID + * @param clientId 발급된 client id + * @param clientSecret 발급된 client secret + * @param param 요청파라미터 + * @return + */ + ResponseEntity payHist(String partnerId, String clientId, String clientSecret, Map param); + + + /** + * 거래완료 + * + * @param partnerId 파트너 ID + * @param clientId 발급된 client id + * @param clientSecret 발급된 client secret + * @param paymentId 네이버페이 결제번호 + * @param requester 요청자(1:구매자, 2:가맹점 관리자). 구분이 애매한 경우 가맹점 관리자로 입력합니다. + * @return + */ + ResponseEntity purchaseConfirm(String partnerId, String clientId, String clientSecret, String paymentId, String requester); + + /** + * 포인트 적립 요청 + * + * @param partnerId 파트너 ID + * @param clientId 발급된 client id + * @param clientSecret 발급된 client secret + * @param paymentId 네이버페이 결제번호 + * @return + */ + ResponseEntity pointSave(String partnerId, String clientId, String clientSecret, String paymentId); + + /** + * 현금영수증 발행대상 금액조회 + * + * @param partnerId 파트너 ID + * @param clientId 발급된 client id + * @param clientSecret 발급된 client secret + * @param paymentIds 네이버페이 결제번호 목록 + * @return + */ + ResponseEntity cashAmount(String partnerId, String clientId, String clientSecret, ArrayList paymentIds); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/code/NvEpBankCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/code/NvEpBankCd.java new file mode 100644 index 0000000..a46b3f6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/code/NvEpBankCd.java @@ -0,0 +1,90 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.code; + +import cokr.xit.ens.core.code.CodeMapperType; +import lombok.Getter; + + +/** + *
    + *
  • 업무 그룹명: 네이버페이 간편결제API - 지원은행코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2023. 2. 07. 오후 1:57:43 + *
+ * + * @author 박민규 + */ + +public enum NvEpBankCd implements CodeMapperType { + B002("산업은행"), + B003("기업은행"), + B004("국민은행"), + B005("외환은행"), + B007("수협"), + B011("농협"), + B012("지역농축협"), + B020("우리은행"), + B023("SC제일은행"), + B027("씨티은행"), + B031("대구은행"), + B032("부산은행"), + B034("광주은행"), + B035("제주은행"), + B037("전북은행"), + B039("경남은행"), + B045("새마을금고"), + B048("신협"), + B050("저축은행"), + B071("우체국"), + B081("하나은행"), + B088("신한은행"), + B089("케이뱅크"), + B090("카카오뱅크"), + B092("토스뱅크"), + B102("대신저축은행"), + B103("에스비아이저축은행"), + B104("에이치케이저축은행"), + B105("웰컴저축은행"), + B106("신한저축은행"), + B209("유안타증권"), + B218("KB증권"), + B221("상상인증권"), + B222("한양증권"), + B223("리딩투자증권"), + B224("BNK투자증권"), + B225("IBK투자증권"), + B227("다올투자증권"), + B238("미래에셋"), + B240("삼성증권"), + B243("한국투자증권"), + B247("NH투자증권"), + B261("교보증권"), + B262("하이투자증권"), + B263("현대차증권"), + B264("키움증권"), + B265("이베스트투자증권"), + B266("SK증권"), + B267("대신증권"), + B269("한화증권"), + B270("하나금융투자"), + B278("신한금융투자"), + B279("DB금융투자"), + B280("유진투자증권"), + B287("메리츠증권"), + B288("카카오페이증권"), + B290("부국증권"), + B291("신영증권"), + B292("케이프투자증권"), + B293("한국증권금융"), + B294("한국포스증권"), + B295("우리종합금융"), + ; + @Getter + private String code; + @Getter + private String codeNm; + + NvEpBankCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/code/NvEpCardCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/code/NvEpCardCd.java new file mode 100644 index 0000000..6344d04 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/code/NvEpCardCd.java @@ -0,0 +1,44 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.code; + +import cokr.xit.ens.core.code.CodeMapperType; +import lombok.Getter; + + +/** + *
    + *
  • 업무 그룹명: 네이버페이 간편결제API - 지원카드코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2023. 2. 07. 오후 1:57:43 + *
+ * + * @author 박민규 + */ + +public enum NvEpCardCd implements CodeMapperType { + C0("신한"), + C1("비씨"), + C2("광주"), + C3("KB국민"), + C4("NH"), + C5("롯데"), + C6("산업"), + C7("삼성"), + C8("수협"), + C9("씨티"), + CA("외환"), + CB("우리"), + CC("전북"), + CD("제주"), + CF("하나-외환"), + CH("현대"), + ; + @Getter + private String code; + @Getter + private String codeNm; + + NvEpCardCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/entity/BillNvEasyPay.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/entity/BillNvEasyPay.java new file mode 100644 index 0000000..014d166 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/entity/BillNvEasyPay.java @@ -0,0 +1,83 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillBaseEntity; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.persistence.*; + +@Entity +@Getter +@ToString +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_bill_nv_ep", schema = "", catalog = "") +@Schema(name = "BillNvEasyPay") +public class BillNvEasyPay extends BillBaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.TABLE, generator = "BillNv_Generator") + @TableGenerator(table = "ens_seq_generator", name = "BillNv_Generator" + , pkColumnName = "seq_name", pkColumnValue = "BillNv_id" + , initialValue = 0, allocationSize = 200) + @Schema(required = true, title = "PK", example = " ") + private Long billId; + + + @Schema(required = true, title = "결제 타입", example = "normal") + @Column(name = "pay_type", nullable = false, length = 10) + private String payType; + + @Schema(required = true, title = "결제창 Open 타입", example = "page") + @Column(name = "open_type", nullable = false, length = 10) + private String openType; + + /* ===================================== + * 결제진행 - PayNotice 단계 + ===================================== */ + @Schema(required = false, title = "상품명", example = "테스트상품") + @Column(name = "product_name", nullable = true, length = 128) + @Setter + private String productName; + @Schema(required = false, title = "총 결제 금액", example = "1000") + @Column(name = "total_pay_amount", nullable = true) + @Setter + private Integer totalPayAmount; + @Schema(required = false, title = "과세 대상 금액", example = "1000") + @Column(name = "tax_scope_amount", nullable = true) + @Setter + private Integer taxScopeAmount; + @Schema(required = false, title = "면세 대상 금액", example = "0") + @Column(name = "tax_ex_scope_amount", nullable = true) + @Setter + private Integer taxExScopeAmount; + @Schema(required = false, title = "컵 보증금 대상 금액", example = "0") + @Column(name = "environment_deposit_amount", nullable = true) + @Setter + private Integer environmentDepositAmount; + @Lob + @Schema(required = false, title = "상품 목록", example = " ") + @Column(name = "product_items", nullable = true) + private String productItems; + @Schema(required = false, title = "리턴URL(이용자 결제완료 후 네이버측에서 승인 하기전 오인결제,이중결제 등을 예방하기 위해 가맹점 검증을 위한 가맹점URL)", example = " ") + @Column(name = "return_url", nullable = true, length = 1000) + @Setter + private String returnUrl; + @Schema(required = false, title = "결제번호", example = "20170201NP1043587746") + @Column(name = "last_payment_id", nullable = true, length = 100) + @Setter + private String lastPaymentId; + @Schema(required = false, title = "결제취소번호", example = "20230208NP1041112193") + @Column(name = "last_pay_hist_id", nullable = true, length = 100) + @Setter + private String lastPayHistId; + @Schema(required = false, title = "취소 결제번호", example = "20170201NP1043587746") + @Column(name = "last_cancel_payment_id", nullable = true, length = 100) + @Setter + private String lastCancelPaymentId; + @Embedded + @Setter + private FieldError error; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/entity/repository/BillNvEasyPayRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/entity/repository/BillNvEasyPayRepository.java new file mode 100644 index 0000000..0c86642 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/entity/repository/BillNvEasyPayRepository.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.repository; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.BillNvEasyPay; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface BillNvEasyPayRepository extends JpaRepository { + + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/model/BillNvAcptReqVO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/model/BillNvAcptReqVO.java new file mode 100644 index 0000000..3f12337 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/model/BillNvAcptReqVO.java @@ -0,0 +1,57 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.model; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; + +@Builder +@Getter +@Schema(name = "BillNvAcptReqVO") +public class BillNvAcptReqVO { + + @Length(max = 45, message = "청구서 유니크 아이디의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "청구서 유니크 아이디", example = " ") + @JsonProperty("billUid") + @JsonAlias({"bill_uid"}) + @SerializedName(value = "billUid", alternate = "bill_uid") + @Setter + private String billUid; + + @NotEmpty(message = "계약번호는 필수 입력값 입니다.") + @Length(max = 40, message = "계약번호의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "기관에서 관리하는 해당 고객번호 혹은 계약번호", example = " ") + @JsonProperty("billerUserKey") + @JsonAlias({"biller_user_key"}) + @SerializedName(value = "billerUserKey", alternate = "biller_user_key") + private String billerUserKey; + + +// @Pattern(regexp = "(normal|recurrent)", message = "결제타입은 normal(default) 또는 recurrent 만 입력 할 수 있습니다.") +// @Length(max = 10, message = "결제 타입의 최대 길이를 초과 했습니다.") +// @Schema(required = true, title = "결제 타입", example = "normal") +// @JsonAlias({"pay_type"}) +// private String payType; +// +// @Pattern(regexp = "(page|popup)", message = "결제창 Open 타입은 page(default) 또는 popup 만 입력 할 수 있습니다.") +// @Length(max = 10, message = "결제창 Open 타입의 최대 길이를 초과 했습니다.") +// @Schema(required = true, title = "결제창 Open 타입", example = "page") +// @JsonAlias({"open_type"}) +// private String openType; +// @NotBlank(message = "리턴URL는 필수조건 입니다.") +// @Length(max = 1000, message = "리턴URL의 최대 길이를 초과 했습니다.") +// @Schema(required = true, title = "네이버페이 결제 후 리턴URL", example = " ") +// @JsonProperty("returnUrl") +// @JsonAlias({"return_url"}) +// @SerializedName(value = "returnUrl", alternate = "return_url") +// private String returnUrl; +// @Schema(required = false, title = "상품 목록", example = " ") +// @JsonAlias({"product_items"}) +// private List> productItems; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/presentation/NvPayProcessController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/presentation/NvPayProcessController.java new file mode 100644 index 0000000..3e4c248 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/presentation/NvPayProcessController.java @@ -0,0 +1,96 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.presentation; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.NvPayProcessService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.PayController; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@Tag(name = "NvPayProcessController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class NvPayProcessController implements PayController, Map> { + + private final NvPayProcessService nvPayProcessService; + + + @Operation(summary = "청구서링크 생성") + @PostMapping(value = "/bill/nv/ep/gnrurl", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity gnrUrl(Map param) { + return new ResponseEntity(nvPayProcessService.gnrUrl(param), HttpStatus.OK); + } + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "결제정보 요청" + , value = "{\"billUid\":\"청구서UID\"}") + }) + }) + @Operation(summary = "납부(결제)정보 요청") + @PostMapping(value = "/bill/nv/ep/notice", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity payNotice(@RequestBody Map param) { + return new ResponseEntity(nvPayProcessService.payNotice(param), HttpStatus.OK); + } + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Success Example..." + , summary = "납부(결제)가능여부 확인" + , value = "{\"billUid\":\"청구서UID\",\"resultCode\":\"Success\",\"paymentId\":\"네이버페이 결제번호\"}"), + @ExampleObject(name = "Fail Example..." + , summary = "납부(결제)가능여부 확인" + , value = "{\"billUid\":\"청구서UID\",\"resultCode\":\"TimeExpired\",\"resultMessage\":\"결제 시간 초과(reserveId 생성 후 30분을 초과한 경우)\",\"reserveId\":\"결제예약ID\"}") + }) + }) + @Operation(summary = "납부(결제)가능여부 확인") + @PostMapping(value = "/bill/nv/ep/able", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity payAble(@RequestBody Map param) { + return new ResponseEntity(nvPayProcessService.payAble(param), HttpStatus.OK); + } + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "결과전달" + , value = "{\"code\":\"Success\",\"message\":\"detail message(optional)\",\"body\":{\"paymentId\":\"네이버페이 결제번호\",\"detail\":{\"productName\":\"샘플상품\",\"merchantId\":\"loginId\",\"merchantName\":\"가맹점명\",\"cardNo\":\"465887**********\",\"admissionYmdt\":\"20170201151722\",\"payHistId\":\"20170201NP1043587781\",\"totalPayAmount\":1000,\"primaryPayAmount\":1000,\"npointPayAmount\":0,\"giftCardAmount\":0,\"taxScopeAmount\":1000,\"taxExScopeAmount\":0,\"environmentDepositAmount\":0,\"primaryPayMeans\":\"CARD\",\"merchantPayKey\":\"청구서UID\",\"merchantUserKey\":\"빌러유저키\",\"cardCorpCode\":\"C0\",\"paymentId\":\"20170201NP1043587746\",\"admissionTypeCode\":\"01\",\"settleExpectAmount\":971,\"payCommissionAmount\":29,\"admissionState\":\"SUCCESS\",\"tradeConfirmYmdt\":\"20170201152510\",\"cardAuthNo\":\"17545616\",\"cardInstCount\":0,\"usedCardPoint\":false,\"bankCorpCode\":\"\",\"bankAccountNo\":\"\",\"settleExpected\":false,\"extraDeduction\":false,\"useCfmYmdt\":\"20180703\"}}}") + }) + }) + @Operation(summary = "납부(결제)결과 전달") + @PostMapping(value = "/bill/nv/ep/result", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity payResult(@RequestBody Map param) { + return new ResponseEntity(nvPayProcessService.payResult(param), HttpStatus.OK); + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "결제취소" + , value = "{\"billUid\":\"청구서UID\",\"cancelReason\":\"결제취소 테스트\",\"cancelRequester\":\"2\"}") + }) + }) + @Operation(summary = "결제취소") + @PostMapping(value = "/bill/nv/ep/cancel", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity payCancel(@RequestBody Map param) { + return new ResponseEntity(nvPayProcessService.payCancel(param), HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/presentation/NvPayUseSysSampleController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/presentation/NvPayUseSysSampleController.java new file mode 100644 index 0000000..9ca4cbb --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/presentation/NvPayUseSysSampleController.java @@ -0,0 +1,216 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.presentation; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.code.NvEpCtgyIdCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.code.NvEpCtgyTypeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.NvPayAbleReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.NvPayNoticeRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.config.notice.ProductItem; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.PayUseSysController; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.utility.RandomString; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Tag(name = "NvPayUseSysSampleController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class NvPayUseSysSampleController implements PayUseSysController> { + + @Value("${contract.naver.pay.easy.api.validate.host}") + private String BILL_HOST; + @Value("${contract.naver.pay.easy.api.validate.prepay}") + private String BILL_PAYABLE_URL; + + private Gson gson = new Gson(); + + + // @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { +// @Content(mediaType = "application/json", examples = { +// @ExampleObject(name = "Sample Example..." +// , summary = "청구서링크생성 정보" +// , value = "{}") +// }) +// }) + @Operation(summary = "청구서링크생성 정보 샘플") + @PostMapping(value = "/bill/nv/ep/sample/gnrUrl", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity gnrUrl(Map param) { + throw new EnsException(EnsErrCd.SERVICE_NOT_SUPPORTED, EnsErrCd.SERVICE_NOT_SUPPORTED.getCodeNm()); + } + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "납부(결제)정보" + , value = "{\"data\":{\"billerUserKey\":\"빌러유저키\"}}") + }) + }) + @Operation(summary = "납부(결제)정보 샘플") + @PostMapping(value = "/bill/nv/ep/sample/paynotice", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity> payNotice(@RequestBody Map param) { + log.info("[Request Data] {}", param.toString()); + Map reqData = (Map) param.getOrDefault("data", new HashMap<>()); + + + + /* ============================================ + * [정상 응답코드] + * OK + * [실패 응답코드] + * NOT_FOUND_PAYDATA + * PAYDATA_FIND_FAILED + ============================================ */ + PayUseSysResCd resCd = PayUseSysResCd.OK; + + + final String productName = "테스트 상품 - " + RandomString.make(7); + final int taxScopeAmount = 100; + final int taxExScopeAmount = 0; + final Integer environmentDepositAmount = null; + final int totalPayAmount = taxScopeAmount + taxExScopeAmount + (environmentDepositAmount == null ? 0 : environmentDepositAmount); + final List productItemList = Arrays.asList(ProductItem.builder() + .categoryType(NvEpCtgyTypeCd.ETC) + .categoryId(NvEpCtgyIdCd.ETC_ETC.getCode()) + .uid((String) reqData.get("billerUserKey")) + .name(productName) + .payReferrer(null) + .startDate(null) + .endDate(null) + .sellerId(null) + .count(1) + .build()); + final int productCount = productItemList.stream().map(productItem -> productItem.getCount()).reduce(Integer::sum).get(); + NvPayNoticeRespData data = NvPayNoticeRespData.builder() + .productName(productName) + .productCount(productCount) + .totalPayAmount(totalPayAmount) + .taxScopeAmount(taxScopeAmount) + .taxExScopeAmount(taxExScopeAmount) + .environmentDepositAmount(environmentDepositAmount) + .productItems(productItemList) + .returnUrl(BILL_HOST + BILL_PAYABLE_URL) + .purchaserName(null) + .purchaserBirthday(null) + .build(); + Map result = new HashMap<>(); + result.put("res_code", resCd.getCode()); + result.put("message", resCd.getCodeNm()); + result.put("data", data); + + return new ResponseEntity>(result, HttpStatus.OK); + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "납부(결제)가능여부" + , value = "{\"data\":{\"billerUserKey\":\"빌러유저키\",\"productName\":\"\",\"totalPayAmount\":1000,\"taxScopeAmount\":1000,\"taxExScopeAmount\":null}}") + }) + }) + @Operation(summary = "납부(결제)가능여부 샘플") + @PostMapping(value = "/bill/nv/ep/sample/payable", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity> payAble(@RequestBody Map param) { + + Map data = gson.fromJson(gson.toJson(param), new TypeToken>() { + }.getType()); + + log.info("[Request Data] {}", data.toString()); + + + /* ============================================ + * [정상 응답코드] + * OK + * [실패 응답코드] + * NO_AMOUNT_PAYABLE + * OVERPAYABLE_AMOUNT + * NO_TARGET_PAYABLE + * EXPIRED_DATE + * FAILED_CHECK_INFO + ============================================ */ + PayUseSysResCd resCd = PayUseSysResCd.OK; + + + Map result = new HashMap<>(); + result.put("res_code", resCd.getCode()); + result.put("message", resCd.getCodeNm()); + result.put("data", null); + + + return new ResponseEntity>(result, HttpStatus.OK); + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "납부(결제)결과" + , value = "{\"code\":\"Success\",\"message\":\"detail message(optional)\",\"body\":{\"paymentId\":\"네이버페이 결제번호\",\"detail\":{\"productName\":\"샘플상품\",\"merchantId\":\"loginId\",\"merchantName\":\"가맹점명\",\"cardNo\":\"465887**********\",\"admissionYmdt\":\"20170201151722\",\"payHistId\":\"20170201NP1043587781\",\"totalPayAmount\":1000,\"primaryPayAmount\":1000,\"npointPayAmount\":0,\"giftCardAmount\":0,\"taxScopeAmount\":1000,\"taxExScopeAmount\":0,\"environmentDepositAmount\":0,\"primaryPayMeans\":\"CARD\",\"merchantPayKey\":\"청구서UID\",\"merchantUserKey\":\"빌러유저키\",\"cardCorpCode\":\"C0\",\"paymentId\":\"20170201NP1043587746\",\"admissionTypeCode\":\"01\",\"settleExpectAmount\":971,\"payCommissionAmount\":29,\"admissionState\":\"SUCCESS\",\"tradeConfirmYmdt\":\"20170201152510\",\"cardAuthNo\":\"17545616\",\"cardInstCount\":0,\"usedCardPoint\":false,\"bankCorpCode\":\"\",\"bankAccountNo\":\"\",\"settleExpected\":false,\"extraDeduction\":false,\"useCfmYmdt\":\"20180703\"}}}") + }) + }) + @Operation(summary = "납부(결제)결과 샘플") + @PostMapping(value = "/bill/nv/ep/sample/payresult", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity> payResult(@RequestBody Map param) { + log.info("[Request Data] {}", param.toString()); + + PayUseSysResCd resCd = PayUseSysResCd.OK; + + + Map result = new HashMap<>(); + result.put("res_code", resCd.getCode()); + result.put("message", resCd.getCodeNm()); + result.put("data", null); + + return new ResponseEntity>(result, HttpStatus.OK); + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "결제취소정보" + , value = "{\"code\":\"Success\",\"message\":\"detail message(optional)\",\"body\":{\"responseCount\":1,\"totalCount\":1,\"totalPageCount\":1,\"currentPageNumber\":1,\"list\":[{\"cardAuthNo\":\"00000000\",\"bankAccountNo\":\"\",\"bankCorpCode\":\"\",\"paymentId\":\"20170000NP1000229665\",\"cardCorpCode\":\"C0\",\"cardInstCount\":0,\"usedCardPoint\":false,\"settleInfo\":{\"primaryCommissionAmount\":30,\"npointCommissionAmount\":20,\"giftCardCommissionAmount\":0,\"primarySettleAmount\":470,\"npointSettleAmount\":480,\"giftCardSettleAmount\":0,\"totalSettleAmount\":850,\"totalCommissionAmount\":50,\"settleCreated\":true},\"merchantName\":\"나의가맹점\",\"productName\":\"나의상품\",\"payHistId\":\"20170000NP1000229668\",\"merchantId\":\"MID12345\",\"admissionYmdt\":\"20170914163930\",\"tradeConfirmYmdt\":\"20170915163956\",\"totalPayAmount\":1000,\"merchantPayKey\":\"orderKey-91516397\",\"merchantUserKey\":\"빌러유저키\",\"admissionTypeCode\":\"01\",\"primaryPayMeans\":\"CARD\",\"admissionState\":\"SUCCESS\",\"primaryPayAmount\":500,\"npointPayAmount\":500,\"giftCardPayAmount\":0,\"taxScopeAmount\":1000,\"taxExScopeAmount\":0,\"environmentDepositAmount\":0,\"cardNo\":\"123456**********\",\"extraDeduction\":false,\"useCfmYmdt\":\"20180703\"}]}}") + }) + }) + @Operation(summary = "결제취소정보 샘플") + @PostMapping(value = "/bill/nv/ep/sample/cancelresult", produces = MediaType.APPLICATION_JSON_VALUE) + @Override + public ResponseEntity> payCancel(@RequestBody Map param) { + log.info("[Request Data] {}", param.toString()); + + PayUseSysResCd resCd = PayUseSysResCd.OK; + + + Map result = new HashMap<>(); + result.put("res_code", resCd.getCode()); + result.put("message", resCd.getCodeNm()); + result.put("data", null); + + return new ResponseEntity>(result, HttpStatus.OK); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/presentation/NvPaymentPageController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/presentation/NvPaymentPageController.java new file mode 100644 index 0000000..5f1ca17 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/presentation/NvPaymentPageController.java @@ -0,0 +1,84 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.presentation; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.NvPayProcessService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.Map; + +@Tag(name = "NvPaymentPageController") +@Slf4j +@RequiredArgsConstructor +@Controller +public class NvPaymentPageController { + private final NvPayProcessService nvPayProcessService; + + @GetMapping(value = "/bill/nv/ep/test/page") + public String nvEpTestPage(ModelMap model) { + + return "modules/bill/nvEpTest"; + } + + @Parameter(name = "flag", example = "ok", in = ParameterIn.PATH) + @Operation(summary = "네이버페이 납부(결제)결과 테스트페이지 출력") + @GetMapping(value = "/bill/nv/ep/test/rslt/prnt/{flag}") + public String nvEpTestRsltPrnt(@PathVariable String flag, ModelMap modelMap) throws JsonProcessingException { + Gson gson = new Gson(); + + if ("ok".equals(flag)) { + Map param = gson.fromJson("{\"code\":\"Success\",\"message\":\"성공\",\"body\":{\"paymentId\":\"20230206NP1041083209\",\"detail\":{\"paymentId\":\"20230206NP1041083209\",\"payHistId\":\"20230206NP1041083231\",\"merchantName\":\"민자도로 관리지원센터_테스트\",\"merchantId\":\"np_mtbfw423545\",\"merchantPayKey\":\"gamengUserKey-00001\",\"merchantUserKey\":\"gamengUserKey-00001\",\"admissionTypeCode\":\"01\",\"admissionYmdt\":\"20230206142529\",\"tradeConfirmYmdt\":\"20230206142529\",\"admissionState\":\"SUCCESS\",\"totalPayAmount\":100,\"primaryPayAmount\":0,\"npointPayAmount\":100,\"giftCardAmount\":0,\"taxScopeAmount\":100,\"taxExScopeAmount\":0,\"environmentDepositAmount\":0,\"primaryPayMeans\":\"CARD\",\"cardCorpCode\":\"C3\",\"cardNo\":\"5570-****-****-****\",\"cardAuthNo\":\"\",\"cardInstCount\":3,\"usedCardPoint\":false,\"bankCorpCode\":\"020\",\"bankAccountNo\":\"1002-***-***-***\",\"productName\":\"테스트상품\",\"settleExpected\":false,\"settleExpectAmount\":0,\"payCommissionAmount\":0,\"merchantExtraParameter\":\"\",\"extraDeduction\":false,\"useCfmYmdt\":\"\"}},\"LPGEX\":\"TnYSG\"}", new TypeToken>() { + }.getType()); + modelMap.putAll(param); + } else if ("fail".equals(flag)) { + modelMap.put("code", PayUseSysResCd.NO_TARGET_PAYABLE.getCode()); + modelMap.put("message", PayUseSysResCd.NO_TARGET_PAYABLE.getCodeNm()); + } else { + throw new EnsException(EnsErrCd.ERR405, "유효하지 않은 요청 입니다"); + } + + return "modules/bill/nvEpApply"; + } + + @Parameters({ + @Parameter(name = "billUid", example = "청구서UID", required = true, in = ParameterIn.QUERY), + @Parameter(name = "paymentId", example = "결제번호", required = true, in = ParameterIn.QUERY), + @Parameter(name = "resultCode", example = "Success", required = true, in = ParameterIn.QUERY), + @Parameter(name = "resultMessage", example = "성공", required = false, in = ParameterIn.QUERY), + @Parameter(name = "reserveId", example = "결제 예약ID", required = false, in = ParameterIn.QUERY) + }) + @Operation(summary = "네이버페이 간편결제 승인") + @GetMapping(value = "/bill/nv/ep/apply") + public String nvEpApply(@RequestParam Map param, ModelMap modelMap) { + PayApiRespDTO payApiRespDTO = nvPayProcessService.payAble(param); + + StringBuffer message = new StringBuffer(); + if (PayUseSysResCd.OK.getCode().equals(payApiRespDTO.getResCode())) { + if (payApiRespDTO.getData() != null) + modelMap.putAll((Map) payApiRespDTO.getData()); + } else { + modelMap.put("code", payApiRespDTO.getResCode()); + modelMap.put("message", payApiRespDTO.getMessage()); + } + + return "modules/bill/nvEpApply"; + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/NvPayProcessService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/NvPayProcessService.java new file mode 100644 index 0000000..612327b --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/NvPayProcessService.java @@ -0,0 +1,99 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.BillNvEasyPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.NvPayAbleService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.NvPayCancelService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.NvPayNoticeService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.NvPayResultService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.NvPayNoticeRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.Pay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.PayProcessService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayAbleData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayCancelData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayNoticeData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayResultData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.template.PayHelper; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Log4j2 +@RequiredArgsConstructor +@Service +public class NvPayProcessService implements PayProcessService> { + private final NvPayNoticeService nvPayNoticeService; + private final NvPayAbleService nvPayAbleService; + private final NvPayResultService nvPayResultService; + private final NvPayCancelService nvPayCancelService; + + @Override + public PayApiRespDTO gnrUrl(Map stringObjectMap) { + throw new EnsException(EnsErrCd.SERVICE_NOT_SUPPORTED, EnsErrCd.SERVICE_NOT_SUPPORTED.getCodeNm()); + } + + @Override + public PayApiRespDTO payNotice(Map data) { + String billUid = (String) data.get("billUid"); + + + Pay> pay = PayHelper., String, PayApiRespDTO>builder() + .param(billUid) + .payHelperService(nvPayNoticeService) + .build(); + + + pay.exec(); + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payAble(Map data) { + + + Pay>> pay = PayHelper., Map, PayApiRespDTO>>builder() + .param(data) + .payHelperService(nvPayAbleService) + .build(); + + + pay.exec(); + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payResult(Map data) { + + + Pay>> pay = PayHelper., Map, PayApiRespDTO>>builder() + .param(data) + .payHelperService(nvPayResultService) + .build(); + + + pay.exec(); + + return pay.getResult(); + } + + @Override + public PayApiRespDTO payCancel(Map data) { + + + Pay>> pay = PayHelper., Map, PayApiRespDTO>>builder() + .param(data) + .payHelperService(nvPayCancelService) + .build(); + + + pay.exec(); + + return pay.getResult(); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/NvPayRepairService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/NvPayRepairService.java new file mode 100644 index 0000000..083333c --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/NvPayRepairService.java @@ -0,0 +1,139 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.repair.kit.RepairNvPayResultTransferFail; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.RepairPayResultService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.model.RepairPayRsltFwdFailSearchDTO; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Service +@RequiredArgsConstructor +public class NvPayRepairService implements RepairPayResultService { + + private final JPAQueryFactory query; + private final PayUseSysApi payUseSysApi; + private final BillHistRepository billHistRepository; + + + @Override + @Transactional(readOnly = true) + public Map> findTransferFailedPayResultDataList(RepairPayRsltFwdFailSearchDTO searchDTO) { + Map> mResultByOrg = new HashMap<>(); + RepairNvPayResultTransferFail.builder() + .query(query) + .searchDTO(searchDTO) + .build() + .findDatas() + .forEach(failData -> { + /** + * 응답데이터 구조 + * { + * "기관코드" { + * "orgCd": "aaaa", + * "orgNm": "sdafsf", + * "billSe": { + * "nvBp": [ + * { "billerUserKey": "aaaaaaaaaaaaa" }, + * { "billerUserKey": "bbbbbbbbbbbbb" } + * ], + * "kkoBp": [ + * { "billerUserKey": "fffffffffffff" } + * ] + * } + * } + * } + */ + Map mOrg = mResultByOrg.get(failData.getOrgCd()); + if (mOrg == null) { + mOrg = new HashMap<>(); + mOrg.put("orgCd", failData.getOrgCd()); + mOrg.put("orgNm", failData.getOrgNm()); + Map data = new HashMap<>(); + data.put("billerUserKey", failData.getBillerUserKey()); + List> datas = new ArrayList<>(); + datas.add(data); + Map billSe = new HashMap<>(); + billSe.put(failData.getBillSe().getCode(), datas); + mOrg.put("billSe", billSe); + mResultByOrg.put(failData.getOrgCd(), mOrg); + } else { + Map billSe = (Map) mOrg.get("billSe"); + List> datas = (List>) billSe.getOrDefault(failData.getBillSe().getCode(), new ArrayList<>()); + Map data = new HashMap<>(); + data.put("billerUserKey", failData.getBillerUserKey()); + datas.add(data); + billSe.put(failData.getBillSe().getCode(), datas); + } + }); + + + return mResultByOrg; + } + + @Override + public Map> sendTransferFailedPayResultDataList(RepairPayRsltFwdFailSearchDTO searchDTO) { + Map> mResultByOrg = new HashMap<>(); + RepairNvPayResultTransferFail.builder() + .query(query) + .searchDTO(searchDTO) + .build() + .transferData(payUseSysApi, billHistRepository) + .forEach(billHist -> { + /** + * 응답데이터 구조 + * { + * "기관코드" { + * "orgCd": "aaaa", + * "orgNm": "sdafsf", + * "billSe": { + * "nvBp": [ + * { "billerUserKey": "aaaaaaaaaaaaa", "code": "OK", "message": "성공" }, + * { "billerUserKey": "bbbbbbbbbbbbb", "code": "OK", "message": "성공" } + * ], + * "kkoBp": [ + * { "billerUserKey": "fffffffffffff", "code": "FAILED_SAVE_PAYRSLT", "message": "납부(결제)결과 저장 실패" } + * ] + * } + * } + * } + */ + Map mOrg = mResultByOrg.get(billHist.getOrgMng().getOrgCd()); + if (mOrg == null) { + mOrg = new HashMap<>(); + mOrg.put("orgCd", billHist.getOrgMng().getOrgCd()); + mOrg.put("orgNm", billHist.getOrgMng().getOrgNm()); + Map data = new HashMap<>(); + data.put("billerUserKey", billHist.getLinkedUuid()); + data.put("code", billHist.getError().getErrorCode()); + data.put("message", billHist.getError().getErrorMessage()); + List> datas = new ArrayList<>(); + datas.add(data); + Map billSe = new HashMap<>(); + billSe.put(billHist.getBillSe().getCode(), datas); + mOrg.put("billSe", billSe); + mResultByOrg.put(billHist.getOrgMng().getOrgCd(), mOrg); + } else { + Map billSe = (Map) mOrg.get("billSe"); + List> datas = (List>) billSe.getOrDefault(billHist.getBillSe().getCode(), new ArrayList<>()); + Map data = new HashMap<>(); + data.put("billerUserKey", billHist.getLinkedUuid()); + data.put("code", billHist.getError().getErrorCode()); + data.put("message", billHist.getError().getErrorMessage()); + datas.add(data); + billSe.put(billHist.getBillSe().getCode(), datas); + } + }); + return mResultByOrg; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/NvPaymentTriggerService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/NvPaymentTriggerService.java new file mode 100644 index 0000000..37967ee --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/NvPaymentTriggerService.java @@ -0,0 +1,87 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.BillNvEasyPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.QBillNvEasyPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.repository.BillNvEasyPayRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.trigger.PaymentTriggerServiceTemplate; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Service(value = "nvPaymentTriggerService") +public class NvPaymentTriggerService extends PaymentTriggerServiceTemplate { + private final NvPayProcessService nvPayProcessService; + private final JPAQueryFactory query; + private final BillNvEasyPayRepository billNvEasyPayRepository; + @Value("${contract.naver.pay.easy.ep-sdk-mode}") + private String EP_SDK_MODE; + + @Override + protected boolean existsBill(String billUid) { + return query.selectFrom(QBillNvEasyPay.billNvEasyPay) + .where(QBillNvEasyPay.billNvEasyPay.billUid.eq(billUid)) + .fetchCount() > 0; + } + + @Override + protected void generateBill(Bill bill) { + billNvEasyPayRepository.save(BillNvEasyPay.builder() + .billUid(bill.getBillUid()) + .billerUserKey(bill.getBillerUserKey()) + .payType("normal") + .openType("page") + .build()); + } + + @Override + protected Map getPayInfo(Map param) { + final Bill bill = (Bill) param.getOrDefault(PTriggerDataKeys.bill, new Bill()); + final String billUid = (String) param.getOrDefault(PTriggerDataKeys.billUid, ""); + + + if (CmmnUtil.isEmpty(bill.getOrgMng().getNvBpClientId())) + throw new EnsException(EnsErrCd.INVALID_DATA, "네이버 간편결제 계약정보가 없습니다."); + + + Map p = new HashMap<>(); + p.put("billUid", billUid); + PayApiRespDTO payApiRespDTO = nvPayProcessService.payNotice(p); + if (!PayUseSysResCd.OK.getCode().equals(payApiRespDTO.getResCode())) + throw new EnsException(EnsErrCd.RESPONSED_FAILURE_CODE, String.format("%s\n[실패사유]\n -.코드: %s\n -.메시지: %s", EnsErrCd.RESPONSED_FAILURE_CODE.getCodeNm(), payApiRespDTO.getResCode(), payApiRespDTO.getMessage())); + + BillNvEasyPay billNvEasyPay = Optional.ofNullable(query.selectFrom(QBillNvEasyPay.billNvEasyPay) + .where(QBillNvEasyPay.billNvEasyPay.billUid.eq(billUid)) + .fetchOne()) + .orElseThrow(() -> new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 자료가 없습니다.")); + + + + Map resultInfo = new HashMap<>(); + resultInfo.put("mode", EP_SDK_MODE); + resultInfo.put("payType", billNvEasyPay.getPayType()); + resultInfo.put("openType", billNvEasyPay.getOpenType()); + resultInfo.put("clientId", bill.getOrgMng().getNvBpClientId()); + resultInfo.put("billUid", billUid); + resultInfo.put("merchantUserKey", billNvEasyPay.getBillerUserKey()); + resultInfo.put("merchantPayKey", billNvEasyPay.getBillUid()); + resultInfo.put("payinf", payApiRespDTO.getData()); + + return resultInfo; + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/NvPayAbleService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/NvPayAbleService.java new file mode 100644 index 0000000..404bf33 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/NvPayAbleService.java @@ -0,0 +1,380 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.utils.MapDeserailizer; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.api.BillNvEasyPayApiSpec; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.BillNvEasyPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.QBillNvEasyPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.repository.BillNvEasyPayRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.NvPayAbleReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.NvPayApplyRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillLogSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.QBill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.Pay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayAbleService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayAbleData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayCancelData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.ReqAndRespInf; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.template.PayHelper; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Service +public class NvPayAbleService implements PayAbleService, Map, PayApiRespDTO>> { + private final BillNvEasyPayRepository billNvEasyPayRepository; + + private final JPAQueryFactory query; + private final BillNvEasyPayApiSpec billNvEasyPayApi; + private final PayUseSysApi payUseSysApi; + private final BillHistRepository billHistRepository; + private final NvPayCancelService nvPayCancelService; + private final NvPayResultService nvPayResultService; + + // private Gson gson = new Gson(); + private Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).disableHtmlEscaping().create(); + + + private enum DataKeys { + payApplyReqMessage, + payApplyRespMessage, + } + + @Override + public PayAbleData getData(Map reqParam) { + String billUid = (String) reqParam.getOrDefault("billUid", ""); + + Bill bill = query.selectFrom(QBill.bill) + .innerJoin(QBill.bill.orgMng, QOrgMng.orgMng).fetchJoin() + .where(QBill.bill.billUid.eq(billUid)) + .fetchOne(); + BillNvEasyPay billNvEasyPay = query.selectFrom(QBillNvEasyPay.billNvEasyPay) + .where(QBillNvEasyPay.billNvEasyPay.billUid.eq(billUid)) + .fetchOne(); + + return PayAbleData.builder() + .bill(bill) + .billDetail(billNvEasyPay) + .build(); + } + + @Override + public void validate(Map reqParam, PayAbleData data) { + + if (CmmnUtil.isEmpty(reqParam.get("resultCode"))) + throw new EnsException(EnsErrCd.NO_REQUIRED_PARAM, "결과코드는 필수값 입니다."); + if (!"Success".equals(reqParam.get("resultCode"))) +// throw new EnsException(EnsErrCd.INVALID_REQUEST, String.format("[%s] %s %s", BillLogSeCd.VD, reqParam.get("resultCode"), reqParam.get("resultMessage"))); + //2023.03.09 네이버페이 검수 결과 - 결제창 실패응답 화면에 resultMessage 원문만 노출 요함 + throw new EnsException(EnsErrCd.INVALID_REQUEST, String.format("[%s] %s", BillLogSeCd.VD, reqParam.get("resultMessage"))); + if (CmmnUtil.isEmpty(reqParam.get("billUid"))) + throw new EnsException(EnsErrCd.NO_REQUIRED_PARAM, "청구서UID는 필수값 입니다."); + if (CmmnUtil.isEmpty(reqParam.get("paymentId"))) + throw new EnsException(EnsErrCd.NO_REQUIRED_PARAM, "결제ID는 필수값 입니다."); + + if (CmmnUtil.isEmpty(data.getBill())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 자료가 없습니다."); + if (CmmnUtil.isEmpty(data.getBillDetail())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 상세 자료가 없습니다."); + } + + @Override + public void callApi(Map reqParam, PayAbleData data) { + Bill bill = data.getBill(); + OrgMng orgMng = bill.getOrgMng(); + + + final String partnerId = orgMng.getNvBpPartnerId(); + final String clientId = orgMng.getNvBpClientId(); + final String clientSecret = orgMng.getNvBpClientSecret(); + final String useSysUrl = orgMng.getNvBpPrepayApi(); + final String paymentId = (String) reqParam.get("paymentId"); + LinkedMultiValueMap reqData = new LinkedMultiValueMap<>(); + reqData.add("paymentId", paymentId); + + + Optional.of(data.getBillDetail()) + .map(billDetail -> createMessage(billDetail)) + .map(param -> loadReqData(data, useSysUrl, param)) + .map(param -> payUseSysApi.payAble(useSysUrl, param, null)) + .map(response -> loadRespData(data, response)) + .map(response -> checkResponse(response)) + .map(respDto -> loadPayApplyReqData(data, reqData)) + .map(respDto -> billNvEasyPayApi.payApply(partnerId, clientId, clientSecret, reqData)) + .map(response -> loadPayApplyRespData(data, response)) + .map(response -> checkApplyResponse(response)) + .map(respDto -> { + try { + + validateApplyData(data, respDto); + } catch (EnsException e) { + + callPayCancelService(data, respDto, e); + throw e; + } + return respDto; + }) + .map(respDto -> callPayResultService(respDto)) + ; + } + + protected Map createMessage(BillNvEasyPay billDetail) { + NvPayAbleReqData nvPayAbleReqData = NvPayAbleReqData.builder() + .billerUserKey(billDetail.getBillerUserKey()) + .productName(billDetail.getProductName()) + .taxExScopeAmount(billDetail.getTaxExScopeAmount()) + .taxScopeAmount(billDetail.getTaxScopeAmount()) + .totalPayAmount(billDetail.getTotalPayAmount()) + .build(); + Map m = new HashMap<>(); + m.put("data", nvPayAbleReqData); + return m; + } + + protected Map loadReqData(PayAbleData data, String url, Map param) { + + data.getReqAndRespInf().setUrl(url); + data.getReqAndRespInf().setReqData(CmmnUtil.toJsonString(param)); + + return gson.fromJson(gson.toJson(param), Map.class); + } + + protected ResponseEntity loadRespData(PayAbleData data, ResponseEntity response) { + + data.getReqAndRespInf().setRespRawData(response.getBody()); + return response; + } + + protected PayApiRespDTO> checkResponse(ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, "[" + BillLogSeCd.US + "] " + EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + PayApiRespDTO> result = null; + try { + result = gson.fromJson(response.getBody(), PayApiRespDTO.class); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RESPONSE, "[" + BillLogSeCd.US + "] " + EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + } + + try { + PayUseSysResCd.valueOf(result.getResCode()); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RES_CODE, "[" + BillLogSeCd.US + "] " + EnsErrCd.INVALID_RES_CODE.getCodeNm(), ex); + } + if (!PayUseSysResCd.OK.getCode().equals(result.getResCode())) { + result.setMessage("[" + BillLogSeCd.US + "] " + result.getMessage()); + throw new EnsException(EnsErrCd.RESPONSED_FAILURE_CODE, EnsErrCd.RESPONSED_FAILURE_CODE.getCodeNm(), result); + } + + return result; + } + + protected LinkedMultiValueMap loadPayApplyReqData(PayAbleData data, LinkedMultiValueMap reqData) { + data.getReqAndRespInf().getEtc().put(DataKeys.payApplyReqMessage.name(), gson.toJson(reqData)); + return reqData; + } + + protected ResponseEntity loadPayApplyRespData(PayAbleData data, ResponseEntity response) { + data.getReqAndRespInf().getEtc().put(DataKeys.payApplyRespMessage.name(), response.getBody()); + return response; + } + + protected PayApiRespDTO checkApplyResponse(ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, "[" + BillLogSeCd.VD + "] " + EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + PayApiRespDTO result = null; + try { + result = gson.fromJson(response.getBody(), new TypeToken>() { + }.getType()); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RESPONSE, "[" + BillLogSeCd.VD + "] " + EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + } + + if (!"Success".equals(result.getResCode())) { + result.setMessage("[" + BillLogSeCd.VD + "] " + result.getMessage()); + throw new EnsException(EnsErrCd.RESPONSED_FAILURE_CODE, EnsErrCd.RESPONSED_FAILURE_CODE.getCodeNm(), result); + } + + return result; + } + + protected void validateApplyData(PayAbleData data, PayApiRespDTO respDTO) { + final BillNvEasyPay billNvEasyPay = data.getBillDetail(); + if (!billNvEasyPay.getTotalPayAmount().equals(respDTO.getData().getDetail().getTotalPayAmount())) + throw new EnsException(EnsErrCd.INVALID_RES_DATA, "요청한 총결제금액과 결제승인된 금액이 상이 합니다."); + if (!billNvEasyPay.getTaxScopeAmount().equals(respDTO.getData().getDetail().getTaxScopeAmount())) + throw new EnsException(EnsErrCd.INVALID_RES_DATA, "요청한 과세금액과 결제승인된 금액이 상이 합니다."); + if (!billNvEasyPay.getTaxExScopeAmount().equals(respDTO.getData().getDetail().getTaxExScopeAmount())) + throw new EnsException(EnsErrCd.INVALID_RES_DATA, "요청한 면세금액과 결제승인된 금액이 상이 합니다."); + } + + protected void callPayCancelService(PayAbleData data, PayApiRespDTO respDTO, EnsException e) { + + data.getBillDetail().setLastPaymentId(respDTO.getData().getPaymentId()); + data.getBillDetail().setTotalPayAmount(respDTO.getData().getDetail().getTotalPayAmount()); + data.getBillDetail().setTaxScopeAmount(respDTO.getData().getDetail().getTaxScopeAmount()); + data.getBillDetail().setTaxExScopeAmount(respDTO.getData().getDetail().getTaxExScopeAmount()); + data.getBillDetail().setEnvironmentDepositAmount(respDTO.getData().getDetail().getEnvironmentDepositAmount()); + billNvEasyPayRepository.save(data.getBillDetail()); + + + Map param = new HashMap<>(); + param.put("billUid", data.getBillDetail().getBillUid()); + param.put("cancelReason", e.getMessage()); + param.put("cancelRequester", "2"); + + Pay>> pay = PayHelper., Map, PayApiRespDTO>>builder() + .param(param) + .payHelperService(nvPayCancelService) + .build(); + + pay.exec(); + } + + + protected PayApiRespDTO> callPayResultService(PayApiRespDTO respDTO) { + Map param = new HashMap<>(); + param.put("code", respDTO.getResCode()); + param.put("message", respDTO.getMessage()); + param.put("body", gson.fromJson(gson.toJson(respDTO.getData()), Map.class)); + + Pay>> pay = PayHelper., Map, PayApiRespDTO>>builder() + .param(param) + .payHelperService(nvPayResultService) + .build(); + pay.exec(); + + return pay.getResult(); + } + + + @Override + public PayApiRespDTO> generateResult(Map reqParam, PayAbleData data, EnsException e) { + if (e == null) { + final String respRawData = (String) data.getReqAndRespInf().getEtc().get(DataKeys.payApplyRespMessage.name()); + Map result = gson.fromJson(respRawData, Map.class); + return PayApiRespDTO.>okBuilder() + .data(result) + .build(); + } else { + if (EnsErrCd.RESPONSED_FAILURE_CODE.equals(e.getErrCd())) { + PayApiRespDTO respDTO = (PayApiRespDTO) e.getData(); + return respDTO; + } else { + return PayApiRespDTO.>errDataBuilder() + .resCode(e.getErrCd().getCode()) + .message(e.getMessage()) + .data(null) + .build(); + } + } + } + + @Override + public void saveHist(Map reqParam, PayAbleData data, EnsException e) { + saveHistByUseSysPayAble(reqParam, data, e); + saveHistByPayApply(data, e); + + + if (e != null) { + if (data.getBillDetail() != null) { + data.getBillDetail().setError(FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()); + billNvEasyPayRepository.save(data.getBillDetail()); + } + } else { + data.getBillDetail().setError(FieldError.initBuilder().build()); + billNvEasyPayRepository.save(data.getBillDetail()); + } + } + + + protected void saveHistByUseSysPayAble(Map reqParam, PayAbleData data, EnsException e) { + ReqAndRespInf reqAndRespInf = data.getReqAndRespInf(); + + String requestData = reqAndRespInf.getReqData(); + if (e != null) { + switch (e.getErrCd()) { + case NO_DATA_FOUND: + case NO_REQUIRED_PARAM: + case INVALID_REQUEST: + requestData = gson.toJson(reqParam); + break; + } + } + BillHist billHist = BillHist.builder() + .billUid(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getBillUid()) + .billSe(BillSeCd.bpNv) + .reqSe(BillReqSeCd.US_PREPAY) + .orgMng(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getOrgMng()) + .linkedUuid(CmmnUtil.isEmpty(data.getBillDetail()) ? null : data.getBillDetail().getBillerUserKey()) + .requestData(requestData) + .responseData(reqAndRespInf.getRespRawData()) + .error(e == null + ? FieldError.initBuilder().build() + : FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()) + .build(); + + billHistRepository.save(billHist); + } + + protected void saveHistByPayApply(PayAbleData data, EnsException e) { + ReqAndRespInf reqAndRespInf = data.getReqAndRespInf(); + final String requestData = (String) reqAndRespInf.getEtc().get(DataKeys.payApplyReqMessage.name()); + final String responseData = (String) reqAndRespInf.getEtc().get(DataKeys.payApplyRespMessage.name()); + + if (!CmmnUtil.isEmpty(requestData)) { + BillHist billHist = BillHist.builder() + .billUid(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getBillUid()) + .billSe(BillSeCd.bpNv) + .reqSe(BillReqSeCd.VD_PAYAPPLY) + .orgMng(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getOrgMng()) + .linkedUuid(CmmnUtil.isEmpty(data.getBillDetail()) ? null : data.getBillDetail().getBillerUserKey()) + .requestData(requestData) + .responseData(responseData) + .error(e == null + ? FieldError.initBuilder().build() + : FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()) + .build(); + + billHistRepository.save(billHist); + } + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/NvPayCancelService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/NvPayCancelService.java new file mode 100644 index 0000000..8725186 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/NvPayCancelService.java @@ -0,0 +1,308 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.utils.MapDeserailizer; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.api.BillNvEasyPayApiSpec; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.BillNvEasyPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.QBillNvEasyPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.repository.BillNvEasyPayRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PaidTypeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.QBill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayCancelService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayCancelData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.ReqAndRespInf; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; + +@Slf4j +@RequiredArgsConstructor +@Service +public class NvPayCancelService implements PayCancelService, Map, PayApiRespDTO>> { + + private final JPAQueryFactory query; + private final BillNvEasyPayApiSpec billNvEasyPayApi; + private final BillRepository billRepository; + private final BillNvEasyPayRepository billNvEasyPayRepository; + private final BillHistRepository billHistRepository; + private final PayUseSysApi payUseSysApi; + + private Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).create(); + + private enum DataKeys { + useSysPayCancelReqMessage, + useSysPayCancelRespMessage, + } + + @Override + public PayCancelData getData(Map reqParam) { + String billUid = (String) reqParam.getOrDefault("billUid", ""); + + Bill bill = query.selectFrom(QBill.bill) + .innerJoin(QBill.bill.orgMng, QOrgMng.orgMng).fetchJoin() + .where(QBill.bill.billUid.eq(billUid)) + .fetchOne(); + BillNvEasyPay billNvEasyPay = query.selectFrom(QBillNvEasyPay.billNvEasyPay) + .where(QBillNvEasyPay.billNvEasyPay.billUid.eq(billUid)) + .fetchOne(); + + return PayCancelData.builder() + .bill(bill) + .billDetail(billNvEasyPay) + .build(); + } + + @Override + public void validate(Map reqParam, PayCancelData data) { + + if (CmmnUtil.isEmpty(reqParam.get("billUid"))) + throw new EnsException(EnsErrCd.NO_REQUIRED_PARAM, "청구서UID는 필수값 입니다."); + if (CmmnUtil.isEmpty(reqParam.get("cancelReason"))) + throw new EnsException(EnsErrCd.NO_REQUIRED_PARAM, "취소사유는 필수값 입니다."); + if (String.valueOf(reqParam.get("cancelReason")).length() > 80) + throw new EnsException(EnsErrCd.INVALID_REQUEST, "취소사유는 최대 80자까지 가능 합니다."); + if (CmmnUtil.isEmpty(reqParam.get("cancelRequester"))) + throw new EnsException(EnsErrCd.NO_REQUIRED_PARAM, "취소요청자는 필수값 입니다."); + if (!("1".equals(reqParam.get("cancelRequester")) || "2".equals(reqParam.get("cancelRequester")))) + throw new EnsException(EnsErrCd.INVALID_REQUEST, "유효하지 않은 취소요청자 구분값 입니다."); //1:구매자, 2:가맹점 관리자 - 애매할 경우 가맹점관리자로 설정 + + if (CmmnUtil.isEmpty(data.getBill())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 자료가 없습니다."); + if (CmmnUtil.isEmpty(data.getBillDetail())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 상세 자료가 없습니다."); + if (CmmnUtil.isEmpty(data.getBillDetail().getLastPaymentId())) + throw new EnsException(EnsErrCd.INVALID_DATA, "미결제(또는 결제취소) 자료 입니다."); + final Integer sumAmount = data.getBillDetail().getTaxScopeAmount() + data.getBillDetail().getTaxExScopeAmount() + (data.getBillDetail().getEnvironmentDepositAmount() == null ? 0 : data.getBillDetail().getEnvironmentDepositAmount()); + if (!data.getBillDetail().getTotalPayAmount().equals(sumAmount)) + throw new EnsException(EnsErrCd.INVALID_DATA, "결제금액과 세부(과세/면세/컵보증금)금액 합계 불일치."); + } + + @Override + public void callApi(Map reqParam, PayCancelData data) { + Bill bill = data.getBill(); + OrgMng orgMng = bill.getOrgMng(); + BillNvEasyPay billNvEasyPay = data.getBillDetail(); + + + final String partnerId = orgMng.getNvBpPartnerId(); + final String clientId = orgMng.getNvBpClientId(); + final String clientSecret = orgMng.getNvBpClientSecret(); + + final String useSysUrl = orgMng.getNvBpPaycancelApi(); + AtomicReference> fwdData = new AtomicReference<>(); + + + + Optional.of(createMessage(reqParam, billNvEasyPay)) + .map(param -> loadReqData(data, param)) + .map(param -> billNvEasyPayApi.payCancel(partnerId, clientId, clientSecret, param)) + .map(response -> loadRespData(data, response)) + .map(response -> checkResponse(response)) + .map(respData -> savePayCancelInfo(data, respData)) + .filter(respData -> useSysUrl != null) + .map(respData -> { + fwdData.set(respData); + return respData; + }) + .map(respData -> loadFwdUseSysPayCancelReqData(data, respData)) + .map(respData -> payUseSysApi.payCancelResult(useSysUrl, respData, null)) + .map(response -> loadFwdUseSysPayCancelRespData(data, response)) + ; + + } + + protected LinkedMultiValueMap createMessage(Map reqParam, BillNvEasyPay billNvEasyPay) { + LinkedMultiValueMap reqData = new LinkedMultiValueMap<>(); + reqData.add("paymentId", billNvEasyPay.getLastPaymentId()); + reqData.add("merchantUserKey", billNvEasyPay.getBillerUserKey()); + reqData.add("cancelReason", reqParam.get("cancelReason")); + reqData.add("cancelRequester", reqParam.get("cancelRequester")); + reqData.add("cancelAmount", billNvEasyPay.getTotalPayAmount()); + reqData.add("taxScopeAmount", billNvEasyPay.getTaxScopeAmount()); + reqData.add("taxExScopeAmount", billNvEasyPay.getTaxExScopeAmount()); + if (!CmmnUtil.isEmpty(billNvEasyPay.getEnvironmentDepositAmount())) + reqData.add("environmentDepositAmount", billNvEasyPay.getEnvironmentDepositAmount()); + reqData.add("doCompareRest", 0); + reqData.add("expectedRestAmount", null); + return reqData; + } + + protected LinkedMultiValueMap loadReqData(PayCancelData data, LinkedMultiValueMap param) { + + data.getReqAndRespInf().setUrl(""); + data.getReqAndRespInf().setReqData(CmmnUtil.toJsonString(param)); + + return param; + } + + protected ResponseEntity loadRespData(PayCancelData data, ResponseEntity response) { + + data.getReqAndRespInf().setRespRawData(response.getBody()); + return response; + } + + protected Map checkResponse(ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + Map result = null; + try { + result = gson.fromJson(response.getBody(), Map.class); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RESPONSE, EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + } + + //※응답코드 중 CancelNotComplete는 네이버페이 취소 진행 중 상태로 빠른 시일 내에 자동 취소될 예정이므로 가맹점에서는 취소 성공으로 처리 필요 + if (!("Success".equals(result.get("code")) || "CancelNotComplete".equals(result.get("code")))) +// throw new EnsException(EnsErrCd.RESPONSED_FAILURE_CODE, String.format("[%s] %s", result.get("code"), result.get("message"))); + //2023.03.09 네이버페이 검수 결과 - 결제창 실패응답 화면에 resultMessage 원문만 노출 요함 + throw new EnsException(EnsErrCd.RESPONSED_FAILURE_CODE, (String) result.get("message")); + + return result; + } + + protected Map savePayCancelInfo(PayCancelData data, Map respData) { + + Map body = (Map) respData.getOrDefault("body", new HashMap<>()); + final String cancelYmdt = (String) body.get("cancelYmdt"); + + + if (PaidTypeCd.naverPay.equals(data.getBill().getPaidType())) { + data.getBill().setPaidAt(false); + data.getBill().setPaidType(PaidTypeCd.naverPay); + data.getBill().setPaidCancelDt(cancelYmdt); + billRepository.save(data.getBill()); + } + + + data.getBillDetail().setLastPaymentId(null); + data.getBillDetail().setLastPayHistId((String) body.get("payHistId")); + data.getBillDetail().setLastCancelPaymentId((String) body.get("paymentId")); + data.getBillDetail().setError(FieldError.initBuilder().build()); + billNvEasyPayRepository.save(data.getBillDetail()); + + return respData; + } + + protected Map loadFwdUseSysPayCancelReqData(PayCancelData data, Map respData) { + data.getReqAndRespInf().getEtc().put(DataKeys.useSysPayCancelReqMessage.name(), gson.toJson(respData)); + return respData; + } + + protected ResponseEntity loadFwdUseSysPayCancelRespData(PayCancelData data, ResponseEntity response) { + data.getReqAndRespInf().getEtc().put(DataKeys.useSysPayCancelRespMessage.name(), response.getBody()); + return response; + } + + + @Override + public PayApiRespDTO> generateResult(Map reqParam, PayCancelData data, EnsException e) { + if (e == null) { + Gson gson = new Gson(); + final String respRawData = data.getReqAndRespInf().getRespRawData(); + return PayApiRespDTO.>errDataBuilder() + .resCode(PayUseSysResCd.OK.getCode()) + .message(PayUseSysResCd.OK.getCodeNm()) + .data(gson.fromJson(respRawData, Map.class)) + .build(); + } else { + return PayApiRespDTO.>errDataBuilder() + .resCode(e.getErrCd().getCode()) + .message(e.getMessage()) + .data(null) + .build(); + } + } + + @Override + public void saveHist(Map reqParam, PayCancelData data, EnsException e) { + saveHistByPayCancel(reqParam, data, e); + saveHistByFwdUseSysPayCancel(data, e); + + + if (e != null) { + if (data.getBillDetail() != null) { + data.getBillDetail().setError(FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()); + billNvEasyPayRepository.save(data.getBillDetail()); + } + } + + } + + protected void saveHistByPayCancel(Map reqParam, PayCancelData data, EnsException e) { + ReqAndRespInf reqAndRespInf = data.getReqAndRespInf(); + + BillHist billHist = BillHist.builder() + .billUid(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getBillUid()) + .billSe(BillSeCd.bpNv) + .reqSe(BillReqSeCd.VD_PAYCANCEL) + .orgMng(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getOrgMng()) + .linkedUuid(CmmnUtil.isEmpty(data.getBillDetail()) ? null : data.getBillDetail().getBillerUserKey()) + .requestData(reqAndRespInf.getReqData()) + .responseData(reqAndRespInf.getRespRawData()) + .error(e == null + ? FieldError.initBuilder().build() + : FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()) + .build(); + + billHistRepository.save(billHist); + } + + protected void saveHistByFwdUseSysPayCancel(PayCancelData data, EnsException e) { + ReqAndRespInf reqAndRespInf = data.getReqAndRespInf(); + final String requestData = (String) reqAndRespInf.getEtc().get(DataKeys.useSysPayCancelReqMessage.name()); + final String responseData = (String) reqAndRespInf.getEtc().get(DataKeys.useSysPayCancelRespMessage.name()); + + if (!CmmnUtil.isEmpty(requestData)) { + BillHist billHist = BillHist.builder() + .billUid(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getBillUid()) + .billSe(BillSeCd.bpNv) + .reqSe(BillReqSeCd.US_CANCELRSLT) + .orgMng(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getOrgMng()) + .linkedUuid(CmmnUtil.isEmpty(data.getBillDetail()) ? null : data.getBillDetail().getBillerUserKey()) + .requestData(requestData) + .responseData(responseData) + .error(e == null + ? FieldError.initBuilder().build() + : FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()) + .build(); + + billHistRepository.save(billHist); + } + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/NvPayNoticeService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/NvPayNoticeService.java new file mode 100644 index 0000000..ae888e3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/NvPayNoticeService.java @@ -0,0 +1,485 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.BillNvEasyPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.QBillNvEasyPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.repository.BillNvEasyPayRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.code.NvEpCtgyIdCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.code.NvEpCtgyTypeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.code.NvEpPayReferrerCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.NvPayNoticeRespData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillLogSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.QBill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayNoticeService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayNoticeData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.ReqAndRespInf; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@RequiredArgsConstructor +@Service +public class NvPayNoticeService implements PayNoticeService, String, PayApiRespDTO> { + + private final JPAQueryFactory query; + private final PayUseSysApi payUseSysApi; + private final BillNvEasyPayRepository billNvEasyPayRepository; + private final BillHistRepository billHistRepository; + + private Gson gson = new Gson(); + + @Override + public PayNoticeData getData(String billUid) { + if (billUid == null) billUid = ""; + Bill bill = query.selectFrom(QBill.bill) + .innerJoin(QBill.bill.orgMng, QOrgMng.orgMng).fetchJoin() + .where(QBill.bill.billUid.eq(billUid)) + .fetchOne(); + BillNvEasyPay billNvEasyPay = query.selectFrom(QBillNvEasyPay.billNvEasyPay) + .where(QBillNvEasyPay.billNvEasyPay.billUid.eq(billUid)) + .fetchOne(); + + return PayNoticeData.builder() + .bill(bill) + .billDetail(billNvEasyPay) + .build(); + } + + @Override + public void validate(String billUid, PayNoticeData data) { + + if (CmmnUtil.isEmpty(data.getBill())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 자료가 없습니다."); + if (CmmnUtil.isEmpty(data.getBillDetail())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 상세 자료가 없습니다."); + if (!CmmnUtil.isEmpty(data.getBillDetail().getLastPaymentId())) + throw new EnsException(EnsErrCd.PAYMENT_ALREADY_CMPLTED, "결제가 완료된 자료 입니다."); + } + + @Override + public void callApi(String billUid, PayNoticeData data) { + Bill bill = data.getBill(); + OrgMng orgMng = bill.getOrgMng(); + BillNvEasyPay billNvEasyPay = data.getBillDetail(); + + + final String useSysUrl = orgMng.getNvBpNoticeApi(); + + + Optional.of(billNvEasyPay.getBillerUserKey()) + .map(billerUserKey -> createMessage(billerUserKey)) + .map(param -> loadReqData(data, useSysUrl, param)) + .map(param -> payUseSysApi.payNotice(useSysUrl, param, null)) + .map(response -> loadRespData(data, response)) + .map(response -> checkResponse(response)) + .map(respDTO -> validateData(respDTO)) + .map(respDTO -> savePayNoticeInfo(data, respDTO)) + ; + + } + + protected Map createMessage(String billerUserKey) { + Map data = new HashMap<>(); + data.put("billerUserKey", billerUserKey); + Map param = new HashMap<>(); + param.put("data", data); + return param; + } + + protected Map loadReqData(PayNoticeData data, String url, Map param) { + + data.getReqAndRespInf().setUrl(url); + data.getReqAndRespInf().setReqData(CmmnUtil.toJsonString(param)); + return param; + } + + protected ResponseEntity loadRespData(PayNoticeData data, ResponseEntity response) { + + data.getReqAndRespInf().setRespRawData(response.getBody()); + return response; + } + + + protected PayApiRespDTO checkResponse(ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, "[" + BillLogSeCd.US + "] " + EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + PayApiRespDTO result = null; + try { + result = gson.fromJson(response.getBody(), new TypeToken>() { + }.getType()); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RESPONSE, "[" + BillLogSeCd.US + "] " + EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + } + + try { + PayUseSysResCd.valueOf(result.getResCode()); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RES_CODE, "[" + BillLogSeCd.US + "] " + EnsErrCd.INVALID_RES_CODE.getCodeNm(), ex); + } + if (!PayUseSysResCd.OK.getCode().equals(result.getResCode())) { + result.setMessage("[" + BillLogSeCd.US + "] " + result.getMessage()); + throw new EnsException(EnsErrCd.RESPONSED_FAILURE_CODE, EnsErrCd.RESPONSED_FAILURE_CODE.getCodeNm(), result); + } + + return result; + } + + protected PayApiRespDTO validateData(PayApiRespDTO respDTO) { + final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + Set> list = validator.validate(respDTO.getData()); + if (list.size() > 0) { + throw new EnsException(EnsErrCd.INVALID_RES_DATA, EnsErrCd.INVALID_RES_DATA.getCodeNm(), list.stream() + .map(row -> String.format("%s [ %s ]", row.getMessageTemplate(), row.getPropertyPath())) + .collect(Collectors.toList())); + } + + Optional.ofNullable(respDTO.getData()) + .filter(respData -> respData != null) + .map(respData -> validProductCount(respData)) + .map(respData -> validMinimumTotalPayAmount(respData)) + .map(respData -> validTaxAndTaxExAmount(respData)) + .map(respData -> validRequirePurchaserNameAndBirthday(respData)) + .map(respData -> validRequireExtraDeduction(respData)) + .map(respData -> validRequireUseCfmYmdt(respData)) + .map(respData -> validProductItems(respData)) + .map(respData -> validFieldTypeCdInProductItems(respData)) + .map(respData -> validFieldTypeCdInPayReferrer(respData)) + .map(respData -> validRequireNameAndCountInProductItems(respData)) + .map(respData -> validRequireStartAndEndDate(respData)) + ; + + + return respDTO; + } + + /** + * + * productCount(상품 수량)은 총 수량으로 전달하는지 확인 + * ex. "A 상품 2개 + B 상품 1개 + 사은품 1개"의 경우 productCount(상품 수량) 4로 전달 + * + * + * @param respData + * @return + */ + private NvPayNoticeRespData validProductCount(NvPayNoticeRespData respData) { + final Integer productCount = respData.getProductCount(); + final Integer sumCount = respData.getProductItems().stream() + .map(productItem -> productItem.getCount()) + .reduce(Integer::sum) + .orElseGet(() -> 0); + if (!productCount.equals(sumCount)) + throw new EnsException(EnsErrCd.INVALID_RES_DATA, String.format("상품수량과 결제상품수량 합계가 일치하지 않습니다.(상품수량: %d 실제합계: %d)", productCount, sumCount)); + + return respData; + } + + /** + * + * totalPayAmount 최소 결제금액(100원)에 대한 예외처리 확인 + * (가맹점 주문서 페이지 총 결제금액이 100원 미만일 경우 결제창 호출을 지양하고, 최소 결제금액에 대한 사용자 안내 처리 필요) + * + * + * @param respData + * @return + */ + private NvPayNoticeRespData validMinimumTotalPayAmount(NvPayNoticeRespData respData) { + if (respData.getTotalPayAmount() < 100) + throw new EnsException(EnsErrCd.INVALID_RES_DATA, "최소 결제금액은 100원 입니다."); + + return respData; + } + + /** + * + * taxScopeAmount(과세), taxExScopeAmount(면세) 해당 금액 확인 + * + * + * @param respData + * @return + */ + private NvPayNoticeRespData validTaxAndTaxExAmount(NvPayNoticeRespData respData) { + final Integer totalPayAmount = respData.getTotalPayAmount(); + final Integer sumAmount = respData.getTaxScopeAmount() + respData.getTaxExScopeAmount() + (respData.getEnvironmentDepositAmount() == null ? 0 : respData.getEnvironmentDepositAmount()); + if (!totalPayAmount.equals(sumAmount)) + throw new EnsException(EnsErrCd.INVALID_RES_DATA, "결제금액과 세부(과세/면세/컵보증금)금액 합계 불일치."); + + return respData; + } + + /** + * + * purchaserName, purchaserBirthday (구매자 성명, 생년월일) 결제 상품이 보험 및 게임 업종 등인 경우 필수 전달하는지 확인 + * + * + * @param respData + * @return + */ + private NvPayNoticeRespData validRequirePurchaserNameAndBirthday(NvPayNoticeRespData respData) { + boolean isTarget = respData.getProductItems().stream().anyMatch(productItem -> NvEpCtgyTypeCd.INSURANCE.equals(productItem.getCategoryType())); + if (isTarget) + if (CmmnUtil.isEmpty(respData.getPurchaserName()) || CmmnUtil.isEmpty(respData.getPurchaserBirthday())) + throw new EnsException(EnsErrCd.INVALID_RES_DATA, "구매자 성명/생년월일 정보가 없습니다. (보험 및 위험 업종인 경우 필수)"); + + return respData; + } + + /** + * + * 도서/공연비 소득공제 대상 가맹점인 경우 extraDeduction 전달하는지 확인 + * (true : 대상, false : 비 대상) + * + * + * @param respData + * @return + */ + private NvPayNoticeRespData validRequireExtraDeduction(NvPayNoticeRespData respData) { + /** + * TODO 향후 소득공제 대상 가맹점 여부 관리 필요 시 네이버페이와 협의된 계약사항에 해당 하므로 아래의 해결안 참고 + * 해결안 1. ENS 에서 가맹/비가맹점 관리 + * -. 기관관리 테이블(ENS_ORG_MNG)에 컬럼 추가 + * 해결안 2. 이용시스템으로부터 데이터 응답 + * -. 응답데이터 클래스(NvPayNoticeRespData) 에 필드 추가 + */ + return respData; + } + + /** + * + * 가맹점 타입이 이용완료일 정산 또는 이용완료일 포인트 적립인 경우 useCfmYmdt 전달하는지 확인 + * + * + * @param respData + * @return + */ + private NvPayNoticeRespData validRequireUseCfmYmdt(NvPayNoticeRespData respData) { + /** + * TODO 향후 정산/포인트적립 기준 관리 필요 시 네이버페이와 협의된 계약사항에 해당 하므로 아래의 해결안 참고 + * 해결안 1. ENS 에서 정산/포인트적립 기준 관리 + * -. 기관관리 테이블(ENS_ORG_MNG)에 컬럼 추가 + * 해결안 2. 이용시스템으로부터 데이터 응답 + * -. 응답데이터 클래스(NvPayNoticeRespData) 에 필드 추가 + * + * ※ 정산/포인트적립 기준 항목 참고 + * -. 정산 기준: 결제일, 이용완료일, 거래완료일 + * -. 포인트적립 기준: 결제일 기준 자동적립, 이용완료일 기준 적립, 포인트 적립 요청 API 적립, 거래 완료 API 적립, 포인트 적립 대상 아님 + */ + return respData; + } + + /** + * + * productItems 상품정보 개발 유무 확인 + * (categoryType, categoryId, uid, payReferrer 값 등) + * + * + * @param respData + * @return + */ + private NvPayNoticeRespData validProductItems(NvPayNoticeRespData respData) { + /** + * TODO 선행처리하는 Spring Validation 으로 대체 함. 향후 필요 시 로직 추가 + */ + return respData; + } + + /** + * + * categoryType, categoryId, uid 값이 상품정보 연동가이드 (Naverpay_Payments_Product_Items_Integration_Guide) 식별값으로 전달하는지 확인 + * + * + * @param respData + * @return + */ + private NvPayNoticeRespData validFieldTypeCdInProductItems(NvPayNoticeRespData respData) { + respData.getProductItems() + .forEach(productItem -> { + final String ctgyId = productItem.getCategoryType().getCode() + "_" + productItem.getCategoryId(); + if (Arrays.stream(NvEpCtgyIdCd.values()).noneMatch(cd -> cd.getCode().equals(ctgyId))) + throw new EnsException(EnsErrCd.INVALID_RES_DATA, "유효하지 않은 결제상품 분류 입니다."); + if (!productItem.getCategoryType().equals(NvEpCtgyIdCd.valueOf(ctgyId).getCategoryTypeCd())) + throw new EnsException(EnsErrCd.INVALID_RES_DATA, "결제상품 유형의 분류가 유효하지 않습니다."); + if (NvEpCtgyTypeCd.INSURANCE.equals(productItem.getCategoryType())) { + if (Arrays.asList("001", "002", "003", "004", "005", "006", "007", "008", "009", "010", "011", "012", "013", "014", "015", "016") + .stream() + .noneMatch(uid -> uid.equals(productItem.getUid()))) + throw new EnsException(EnsErrCd.INVALID_RES_DATA, "보험상품의 식별값이 유효하지 않습니다."); + } + }); + + return respData; + } + + /** + * + * payReferrer 값이 상품정보 연동가이드(Naverpay_Payments_Product_Items_Integration_Guide) 식별값으로 전달하는지 확인 + * + * + * @param respData + * @return + */ + private NvPayNoticeRespData validFieldTypeCdInPayReferrer(NvPayNoticeRespData respData) { + respData.getProductItems().stream() + .filter(productItem -> !CmmnUtil.isEmpty(productItem.getPayReferrer())) + .forEach(productItem -> { + try { + NvEpPayReferrerCd.valueOf(productItem.getPayReferrer()); + } catch (Exception e) { + throw new EnsException(EnsErrCd.INVALID_RES_DATA, "유효하지 않은 유입경로 입니다."); + } + }); + return respData; + } + + /** + * + * productItems 상품정보 내 name(상품명), count(결제 상품 개수) 확인 + * + * + * @param respData + * @return + */ + private NvPayNoticeRespData validRequireNameAndCountInProductItems(NvPayNoticeRespData respData) { + /** + * TODO 선행처리하는 Spring Validation 으로 대체 함. 향후 필요 시 로직 추가 + */ + return respData; + } + + /** + * + * startDate(시작일), endDate(종료일) 필드는 결제상품이 공연, 영화, 보험, 여행, 항공, 숙박 등인 경우 입력을 권장 + * + * + * @param respData + * @return + */ + private NvPayNoticeRespData validRequireStartAndEndDate(NvPayNoticeRespData respData) { + respData.getProductItems().stream() + .filter(productItem -> + NvEpCtgyTypeCd.PLAY.equals(productItem.getCategoryType()) + || NvEpCtgyTypeCd.MOVIE.equals(productItem.getCategoryType()) + || NvEpCtgyTypeCd.INSURANCE.equals(productItem.getCategoryType()) + || NvEpCtgyTypeCd.TRAVEL.equals(productItem.getCategoryType()) + || NvEpCtgyTypeCd.FLIGHT.equals(productItem.getCategoryType()) + ) + .filter(productItem -> CmmnUtil.isEmpty(productItem.getStartDate()) || CmmnUtil.isEmpty(productItem.getEndDate())) + .forEach(productItem -> { + throw new EnsException(EnsErrCd.INVALID_RES_DATA, "시작일(또는 종료일)이 없습니다. (공연/영화/보험/여행/항공 상품인 경우 필수)"); + }); + + + return respData; + } + + protected PayApiRespDTO savePayNoticeInfo(PayNoticeData data, PayApiRespDTO respDTO) { + NvPayNoticeRespData noticeData = respDTO.getData(); + + data.getBillDetail().setProductName(noticeData.getProductName()); + data.getBillDetail().setTotalPayAmount(noticeData.getTotalPayAmount()); + data.getBillDetail().setTaxScopeAmount(noticeData.getTaxScopeAmount()); + data.getBillDetail().setTaxExScopeAmount(noticeData.getTaxExScopeAmount()); + data.getBillDetail().setEnvironmentDepositAmount(noticeData.getEnvironmentDepositAmount()); + data.getBillDetail().setReturnUrl(noticeData.getReturnUrl()); + data.getBillDetail().setError(FieldError.initBuilder().build()); + billNvEasyPayRepository.save(data.getBillDetail()); + + return respDTO; + } + + @Override + public PayApiRespDTO generateResult(String billUid, PayNoticeData data, EnsException e) { + if (e == null) { + Gson gson = new Gson(); + final String respRawData = data.getReqAndRespInf().getRespRawData(); + return gson.fromJson(respRawData, new TypeToken>() { + }.getType()); + } else { + if (EnsErrCd.RESPONSED_FAILURE_CODE.equals(e.getErrCd())) { + PayApiRespDTO respDTO = (PayApiRespDTO) e.getData(); + return PayApiRespDTO.errDataBuilder() + .resCode(respDTO.getResCode()) + .message(respDTO.getMessage()) + .data(null) + .build(); + } else { + return PayApiRespDTO.errDataBuilder() + .resCode(e.getErrCd().getCode()) + .message(e.getMessage()) + .data(null) + .build(); + } + } + } + + @Override + public void saveHist(String billUid, PayNoticeData data, EnsException e) { + saveHistByUseSysNotice(billUid, data, e); + + if (e != null) { + if (data.getBillDetail() != null) { + data.getBillDetail().setError(FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()); + billNvEasyPayRepository.save(data.getBillDetail()); + } + } + } + + private void saveHistByUseSysNotice(String billUid, PayNoticeData data, EnsException e) { + ReqAndRespInf reqAndRespInf = data.getReqAndRespInf(); + + String errDetail = ""; + if (e != null) + if (EnsErrCd.INVALID_RES_DATA.equals(e.getErrCd())) { + if (e.getData() != null && e.getData() instanceof List) + errDetail = gson.toJson(e.getData()); + } + + BillHist billHist = BillHist.builder() + .billUid(billUid) + .billSe(BillSeCd.bpNv) + .reqSe(BillReqSeCd.US_NOTICE) + .orgMng(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getOrgMng()) + .linkedUuid(CmmnUtil.isEmpty(data.getBillDetail()) ? null : data.getBillDetail().getBillerUserKey()) + .requestData(reqAndRespInf.getReqData()) + .responseData(reqAndRespInf.getRespRawData()) + .error(e == null + ? FieldError.initBuilder().build() + : FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage() + errDetail) + .build()) + .build(); + + billHistRepository.save(billHist); + + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/NvPayResultService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/NvPayResultService.java new file mode 100644 index 0000000..e941365 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/NvPayResultService.java @@ -0,0 +1,299 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process; + +import cokr.xit.ens.biz.iup.domain.TbNaverPayResult; +import cokr.xit.ens.biz.iup.domain.repository.TbNaverPayResultRepository; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.BillNvEasyPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.QBillNvEasyPay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.entity.repository.BillNvEasyPayRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.NvPayResultDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.NvPayResultReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PaidTypeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.QBill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayResultService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.PayResultData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model.ReqAndRespInf; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RequiredArgsConstructor +@Service +public class NvPayResultService implements PayResultService, Map, PayApiRespDTO>> { + private final BillNvEasyPayRepository billNvEasyPayRepository; + + private final JPAQueryFactory query; + private final PayUseSysApi payUseSysApi; + private final BillRepository billRepository; + private final BillHistRepository billHistRepository; + private final TbNaverPayResultRepository tbNaverPayResultRepository; + + private Gson gson = new Gson(); + + @Override + public PayResultData getData(Map reqParam) { + Map body = (Map) reqParam.getOrDefault("body", new HashMap<>()); + Map detail = (Map) body.getOrDefault("detail", new HashMap<>()); +// final String paymentId = (String) body.getOrDefault("paymentId", ""); +// final String billerUserKey = (String) detail.getOrDefault("merchantUserKey", ""); + final String billUid = (String) detail.getOrDefault("merchantPayKey", ""); + + BillNvEasyPay billNvEasyPay = query.selectFrom(QBillNvEasyPay.billNvEasyPay) +// .where(QBillNvEasyPay.billNvEasyPay.lastPaymentId.eq(paymentId) +// .and(QBillNvEasyPay.billNvEasyPay.billerUserKey.eq(billerUserKey)) +// ) + .where(QBillNvEasyPay.billNvEasyPay.billUid.eq(billUid)) + .fetchOne(); + Bill bill = null; + if (billNvEasyPay != null) + bill = query.selectFrom(QBill.bill) + .innerJoin(QBill.bill.orgMng, QOrgMng.orgMng).fetchJoin() + .where(QBill.bill.billUid.eq(billNvEasyPay.getBillUid())) + .fetchOne(); + return PayResultData.builder() + .bill(bill) + .billDetail(billNvEasyPay) + .build(); + } + + @Override + public void validate(Map reqParam, PayResultData data) { + + if (!"Success".equals(reqParam.get("code"))) + throw new EnsException(EnsErrCd.INVALID_REQUEST, String.format("[%s] %s", reqParam.get("code"), reqParam.get("message"))); + + if (CmmnUtil.isEmpty(data.getBill())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 자료가 없습니다."); + if (CmmnUtil.isEmpty(data.getBillDetail())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "일치하는 청구서 상세 자료가 없습니다."); + } + + @Override + public void callApi(Map reqParam, PayResultData data) { + Bill bill = data.getBill(); + OrgMng orgMng = bill.getOrgMng(); + + + final String useSysUrl = orgMng.getNvBpPayresultApi(); + + log.info("********** NV savePaidInfo reqParam : " + reqParam); + + Optional.ofNullable(gson.fromJson(gson.toJson(reqParam.get("body")), NvPayResultReqData.class)) + .map(nvPayResultReqData -> toEntity(nvPayResultReqData)) + .map(entity -> savePayResult(entity)); + + + Optional.of(savePaidInfo(data, reqParam)) + .map(param -> loadReqData(data, useSysUrl, param)) + .map(param -> createMessage(param)) + .map(param -> payUseSysApi.payResult(useSysUrl, param, null)) + .map(response -> loadRespData(data, response)) + .map(response -> checkResponse(response)) + ; + } + + protected Map savePaidInfo(PayResultData data, Map reqParam) { + Map body = (Map) reqParam.getOrDefault("body", new HashMap<>()); + Map detail = (Map) body.getOrDefault("detail", new HashMap<>()); + final String admissionYmdt = (String) detail.get("admissionYmdt"); + final String paymentId = (String) body.getOrDefault("paymentId", ""); + + + + data.getBill().setPaidAt(true); + data.getBill().setPaidType(PaidTypeCd.naverPay); + data.getBill().setPaidDt(admissionYmdt); + billRepository.save(data.getBill()); + + + data.getBillDetail().setLastPaymentId(paymentId); + data.getBillDetail().setError(FieldError.initBuilder().build()); + billNvEasyPayRepository.save(data.getBillDetail()); + + return reqParam; + } + + + protected Map loadReqData(PayResultData data, String url, Map param) { + + data.getReqAndRespInf().setUrl(url); + data.getReqAndRespInf().setReqData(CmmnUtil.toJsonString(param)); + return param; + } + + protected Map createMessage(Map reqParam) { + return reqParam; + } + + + protected ResponseEntity loadRespData(PayResultData data, ResponseEntity response) { + + data.getReqAndRespInf().setRespRawData(response.getBody()); + return response; + } + + protected PayApiRespDTO> checkResponse(ResponseEntity response) { + + if (!HttpStatus.OK.equals(response.getStatusCode())) + throw new EnsException(EnsErrCd.API_COMM_ERROR, EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString(), response.getBody()); + + PayApiRespDTO> result = null; + try { + result = gson.fromJson(response.getBody(), PayApiRespDTO.class); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RESPONSE, EnsErrCd.INVALID_RESPONSE.getCodeNm(), ex); + } + + try { + PayUseSysResCd.valueOf(result.getResCode()); + } catch (Exception ex) { + throw new EnsException(EnsErrCd.INVALID_RES_CODE, EnsErrCd.INVALID_RES_CODE.getCodeNm(), ex); + } + + return result; + } + + + @Override + public PayApiRespDTO> generateResult(Map reqParam, PayResultData data, EnsException e) { + if (e == null) { + final String respRawData = data.getReqAndRespInf().getRespRawData(); + return gson.fromJson(respRawData, PayApiRespDTO.class); + } else { + return PayApiRespDTO.>errDataBuilder() + .resCode(e.getErrCd().getCode()) + .message(e.getMessage()) + .data(null) + .build(); + } + } + + @Override + public void saveHist(Map reqParam, PayResultData data, EnsException e) { + saveHistByUseSysPayResult(reqParam, data, e); + + if (e != null) { + if (data.getBillDetail() != null) { + data.getBillDetail().setError(FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()); + billNvEasyPayRepository.save(data.getBillDetail()); + } + } + + } + + protected void saveHistByUseSysPayResult(Map reqParam, PayResultData data, EnsException e) { + ReqAndRespInf reqAndRespInf = data.getReqAndRespInf(); + + String requestData = reqAndRespInf.getReqData(); + if (e != null) { + switch (e.getErrCd()) { + case NO_DATA_FOUND: + case INVALID_REQUEST: + requestData = gson.toJson(reqParam); + break; + } + } + + + BillHist billHist = BillHist.builder() + .billUid(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getBillUid()) + .billSe(BillSeCd.bpNv) + .reqSe(BillReqSeCd.US_PAYRSLT) + .orgMng(CmmnUtil.isEmpty(data.getBill()) ? null : data.getBill().getOrgMng()) + .linkedUuid(CmmnUtil.isEmpty(data.getBillDetail()) ? null : data.getBillDetail().getBillerUserKey()) + .requestData(requestData) + .responseData(reqAndRespInf.getRespRawData()) + .error(e == null + ? FieldError.initBuilder().build() + : FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()) + .build(); + + billHistRepository.save(billHist); + } + + private TbNaverPayResult toEntity(NvPayResultReqData nvPayResultReqData) { + NvPayResultDetail detail = nvPayResultReqData.getDetail(); + final String billerUserKey = detail.getMerchantUserKey(); + + final String jobSe = "EL".equals(billerUserKey.substring(0, 2)) ? "2" : "1"; + + return TbNaverPayResult.builder() + .dataId(billerUserKey) + .jobSe(jobSe) + .paymentId(detail.getPaymentId()) + .payHistId(detail.getPayHistId()) + .merchantId(detail.getMerchantId()) + .merchantName(detail.getMerchantName()) + .merchantPayKey(detail.getMerchantPayKey()) + .merchantUserKey(detail.getMerchantUserKey()) + .admissionTypeCode(detail.getAdmissionTypeCode()) + .admissionYmdt(detail.getAdmissionYmdt()) + .tradeConfirmYmdt(detail.getTradeConfirmYmdt()) + .admissionState(detail.getAdmissionState()) + .totalPayAmount(detail.getTotalPayAmount()) + .primaryPayAmount(detail.getPrimaryPayAmount()) + .npointPayAmount(detail.getNpointPayAmount()) + .giftCardAmount(detail.getGiftCardAmount()) + .taxScopeAmount(detail.getTaxScopeAmount()) + .taxExScopeAmount(detail.getTaxExScopeAmount()) + .environmentDepositAmount(detail.getEnvironmentDepositAmount()) + .primaryPayMeans(detail.getPrimaryPayMeans()) + .cardCorpCode(detail.getCardCorpCode()) + .cardNo(detail.getCardNo()) + .cardAuthNo(detail.getCardAuthNo()) + .cardInstCount(detail.getCardInstCount()) + .usedCardPoint(detail.getUsedCardPoint()) + .bankCorpCode(detail.getBankCorpCode()) + .bankAccountNo(detail.getBankAccountNo()) + .productName(detail.getProductName()) + .settleExpected(detail.getSettleExpected()) + .settleExpectAmount(detail.getSettleExpectAmount()) + .payCommissionAmount(detail.getPayCommissionAmount()) + .extraDeduction(detail.getExtraDeduction()) + .useCfmYmdt(detail.getUseCfmYmdt()) + .merchantExtraParameter(detail.getMerchantExtraParameter()) + .userIdentifier(detail.getUserIdentifier()) + .payResultProcessSttus("0") +// .creatDt() + .crtr("ENS_SYS") +// .updtDt() +// .updusr() + .build(); + + } + + private TbNaverPayResult savePayResult(TbNaverPayResult entity) { + + tbNaverPayResultRepository.save(entity); + return entity; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/code/NvEpCtgyIdCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/code/NvEpCtgyIdCd.java new file mode 100644 index 0000000..ed8a190 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/code/NvEpCtgyIdCd.java @@ -0,0 +1,69 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.code; + +import cokr.xit.ens.core.code.CodeMapperType; +import lombok.Getter; + + +/** + *
    + *
  • 업무 그룹명: 네이버페이 간편결제API - 결제상품 분류
  • + *
  • 설 명:
  • + *
  • 작성일: 2023. 2. 22. 오후 2:47:43 + *
+ * + * @author 박민규 + */ + +public enum NvEpCtgyIdCd implements CodeMapperType { + BOOK_GENERAL("일반 도서", NvEpCtgyTypeCd.BOOK), + BOOK_EBOOK("전자책", NvEpCtgyTypeCd.BOOK), + BOOK_USED("중고 도서", NvEpCtgyTypeCd.BOOK), + MUSIC_CD("음악 CD", NvEpCtgyTypeCd.MUSIC), + MUSIC_LP("음악 LP", NvEpCtgyTypeCd.MUSIC), + MUSIC_USED("중고 음반", NvEpCtgyTypeCd.MUSIC), + MOVIE_DVD("영화 DVD", NvEpCtgyTypeCd.MOVIE), + MOVIE_BLUERAY("영화 블루레이", NvEpCtgyTypeCd.MOVIE), + MOVIE_VOD("영화 VOD", NvEpCtgyTypeCd.MOVIE), + MOVIE_TICKET("영화 티켓", NvEpCtgyTypeCd.MOVIE), + MOVIE_USED("중고 DVD, 블루레이 등", NvEpCtgyTypeCd.MOVIE), + PRODUCT_GENERAL("일반 상품", NvEpCtgyTypeCd.PRODUCT), + PRODUCT_CASHABLE("환금성 상품", NvEpCtgyTypeCd.PRODUCT), + PRODUCT_CLAIM("클레임", NvEpCtgyTypeCd.PRODUCT), + PRODUCT_DIGITAL_CONTENT("디지털 컨텐츠", NvEpCtgyTypeCd.PRODUCT), + PRODUCT_SUPPORT("후원", NvEpCtgyTypeCd.PRODUCT), + PLAY_TICKET("공연/전시", NvEpCtgyTypeCd.PLAY), + TRAVEL_DOMESTIC("국내 숙박", NvEpCtgyTypeCd.TRAVEL), + TRAVEL_OVERSEA("해외 숙박", NvEpCtgyTypeCd.TRAVEL), + INSURANCE_CAR("자동차보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_DRIVER("운전자보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_HEALTH("건강보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_CHILD("어린이보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_TRAVELER("여행자보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_GOLF("골프보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_ANNUITY("연금보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_ANNUITY_SAVING("연금저축보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_SAVING("저축보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_VARIABLE_ANNUITY("변액적립보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_CANCER("암보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_DENTIST("치아보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_ACCIDENT("상해보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_SEVERANCE("퇴직연금", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_PHONE("휴대폰 보험", NvEpCtgyTypeCd.INSURANCE), + INSURANCE_PET("펫보험", NvEpCtgyTypeCd.INSURANCE), + FLIGHT_TICKET("항공", NvEpCtgyTypeCd.FLIGHT), + FOOD_DELIVERY("음식", NvEpCtgyTypeCd.FOOD), + ETC_ETC("기타", NvEpCtgyTypeCd.ETC), + ; + @Getter + private String code; + @Getter + private String codeNm; + @Getter + private NvEpCtgyTypeCd categoryTypeCd; + + NvEpCtgyIdCd(String codeNm, NvEpCtgyTypeCd categoryTypeCd) { + this.code = this.name(); + this.codeNm = codeNm; + this.categoryTypeCd = categoryTypeCd; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/code/NvEpCtgyTypeCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/code/NvEpCtgyTypeCd.java new file mode 100644 index 0000000..78cee66 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/code/NvEpCtgyTypeCd.java @@ -0,0 +1,38 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.code; + +import cokr.xit.ens.core.code.CodeMapperType; +import lombok.Getter; + + +/** + *
    + *
  • 업무 그룹명: 네이버페이 간편결제API - 결제상품 유형
  • + *
  • 설 명:
  • + *
  • 작성일: 2023. 2. 22. 오후 2:47:43 + *
+ * + * @author 박민규 + */ + +public enum NvEpCtgyTypeCd implements CodeMapperType { + BOOK("도서"), + MUSIC("음악"), + MOVIE("영화"), + PRODUCT("상품"), + PLAY("공연"), + TRAVEL("여행"), + INSURANCE("보험"), + FLIGHT("항공"), + FOOD("음식"), + ETC("기타"), + ; + @Getter + private String code; + @Getter + private String codeNm; + + NvEpCtgyTypeCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/code/NvEpPayReferrerCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/code/NvEpPayReferrerCd.java new file mode 100644 index 0000000..a21f209 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/code/NvEpPayReferrerCd.java @@ -0,0 +1,39 @@ + +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.code; + +import cokr.xit.ens.core.code.CodeMapperType; +import lombok.Getter; + + +/** + *
    + *
  • 업무 그룹명: 네이버페이 간편결제API - 결제 유입경로
  • + *
  • 설 명:
  • + *
  • 작성일: 2023. 2. 22. 오후 2:47:43 + *
+ * + * @author 박민규 + */ + +public enum NvEpPayReferrerCd implements CodeMapperType { + NAVER_BOOK("네이버 책 서비스를 통해 유입 후 결제가 발생한 경우"), + NAVER_MUSIC("네이버 뮤직 서비스를 통해 유입 후 결제가 발생한 경우"), + NAVER_SHOPPING("네이버 쇼핑 서비스를 통해 유입 후 결제가 발생한 경우"), + NAVER_MAP("네이버 지도 서비스를 통해 유입 후 결제가 발생한 경우"), + NAVER_PLACE("네이버 플레이스 서비스를 통해 유입 후 결제가 발생한 경우"), + SEARCH_AD("검색 광고를 통해 유입 후 결제가 발생한 경우"), + NAVER_SEARCH("네이버 통합 검색 바로가기를 통해 유입 후 결제가 발생한 경우"), + BRAND_SEARCH("브랜드 검색을 통해 유입 후 결제가 발생한 경우"), + PARTNER_DIRECT("가맹점 사이트에 바로 접속하여 결제가 발생한 경우"), + ETC("그 외의 유입을 통해 결제가 발생한 경우"), + ; + @Getter + private String code; + @Getter + private String codeNm; + + NvEpPayReferrerCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayAbleReqData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayAbleReqData.java new file mode 100644 index 0000000..c6628bf --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayAbleReqData.java @@ -0,0 +1,55 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 네이버페이 결제가능여부 요청데이터 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +@ToString +public class NvPayAbleReqData { + @NotEmpty(message = "계약번호는 필수 입력값 입니다.") + @Length(max = 50, message = "계약번호의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "기관에서 관리하는 해당 고객번호 혹은 계약번호", example = " ") + @JsonProperty("billerUserKey") + @JsonAlias({"biller_user_key"}) + @SerializedName(value = "billerUserKey", alternate = {"biller_user_key"}) + private String billerUserKey; + @NotBlank(message = "상품명은 필수 입력값 입니다.") + @Length(max = 128, message = "상품명의 최대길이를 초과 했습니다.") + @Schema(required = true, title = "상품명", example = "테스트상품") + @JsonProperty("productName") + @JsonAlias({"product_name"}) + @SerializedName(value = "productName", alternate = {"product_name"}) + private String productName; + @NotNull(message = "총 결제 금액은 필수 입력값 입니다.") + @Schema(required = true, title = "총 결제 금액", example = "1000") + @JsonProperty("totalPayAmount") + @JsonAlias({"total_pay_amount"}) + @SerializedName(value = "totalPayAmount", alternate = {"total_pay_amount"}) + private Integer totalPayAmount; + @NotNull(message = "과세 대상 금액은 필수 입력값 입니다.") + @Schema(required = true, title = "과세 대상 금액", example = "1000") + @JsonProperty("taxScopeAmount") + @JsonAlias({"tax_scope_amount"}) + @SerializedName(value = "taxScopeAmount", alternate = {"tax_scope_amount"}) + private Integer taxScopeAmount; + @NotNull(message = "면세 대상 금액은 필수 입력값 입니다.") + @Schema(required = true, title = "면세 대상 금액", example = "0") + @JsonProperty("taxExScopeAmount") + @JsonAlias({"tax_ex_scope_amount"}) + @SerializedName(value = "taxExScopeAmount", alternate = {"tax_ex_scope_amount"}) + private Integer taxExScopeAmount; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayApplyRespData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayApplyRespData.java new file mode 100644 index 0000000..61f7aeb --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayApplyRespData.java @@ -0,0 +1,35 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.config.able.Detail; +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.validator.constraints.Length; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 네이버페이 결제승인 응답데이터 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +@ToString +public class NvPayApplyRespData { + @NotEmpty(message = "결제번호는 필수 입력값 입니다.") + @Length(max = 50, message = "결제번호의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "네이버페이 결제번호", example = " ") + @JsonProperty("paymentId") + @JsonAlias({"payment_id"}) + @SerializedName(value = "paymentId", alternate = {"payment_id"}) + private String paymentId; + @NotNull(message = "결제결과 상세정보는 필수 입력값 입니다.") + @Schema(required = true, title = "결제결과 상세정보", example = " ") + @Valid + private Detail detail; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayNoticeRespData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayNoticeRespData.java new file mode 100644 index 0000000..f068b6d --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayNoticeRespData.java @@ -0,0 +1,96 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.config.notice.ProductItem; +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.validator.constraints.Length; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 네이버페이 결제정보 응답데이터 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +@ToString +@JsonInclude(JsonInclude.Include.NON_NULL) //2023.03.14 네이버페이 검수 결과 - 요청대상이 아닌 null 값 제외 +public class NvPayNoticeRespData { + @NotBlank(message = "상품명은 필수 입력값 입니다.") + @Length(max = 128, message = "상품명의 최대길이를 초과 했습니다.") + @Schema(required = true, title = "상품명", example = "테스트상품") + @JsonProperty("productName") + @JsonAlias({"product_name"}) + @SerializedName(value = "productName", alternate = {"product_name"}) + private String productName; + @NotNull(message = "상품 수량은 필수 입력값 입니다.") + @Schema(required = true, title = "상품 수량", example = "") + @JsonProperty("productCount") + @JsonAlias({"product_count"}) + @SerializedName(value = "productCount", alternate = {"product_count"}) + private Integer productCount; + @NotNull(message = "총 결제 금액은 필수 입력값 입니다.") + @Schema(required = true, title = "총 결제 금액", example = "1000") + @JsonProperty("totalPayAmount") + @JsonAlias({"total_pay_amount"}) + @SerializedName(value = "totalPayAmount", alternate = {"total_pay_amount"}) + private Integer totalPayAmount; + @NotNull(message = "과세 대상 금액은 필수 입력값 입니다.") + @Schema(required = true, title = "과세 대상 금액", example = "1000") + @JsonProperty("taxScopeAmount") + @JsonAlias({"tax_scope_amount"}) + @SerializedName(value = "taxScopeAmount", alternate = {"tax_scope_amount"}) + private Integer taxScopeAmount; + @NotNull(message = "면세 대상 금액은 필수 입력값 입니다.") + @Schema(required = true, title = "면세 대상 금액", example = "0") + @JsonProperty("taxExScopeAmount") + @JsonAlias({"tax_ex_scope_amount"}) + @SerializedName(value = "taxExScopeAmount", alternate = {"tax_ex_scope_amount"}) + private Integer taxExScopeAmount; + @Schema(required = false, title = "컵 보증금 대상 금액", example = "0") + @JsonProperty("environmentDepositAmount") + @JsonAlias({"environment_deposit_amount"}) + @SerializedName(value = "environmentDepositAmount", alternate = {"environment_deposit_amount"}) + private Integer environmentDepositAmount; + @NotNull(message = "상품 목록은 필수조건 입니다.") + @Schema(required = false, title = "상품 목록", example = " ") + @JsonProperty("productItems") + @JsonAlias({"product_items"}) + @SerializedName(value = "productItems", alternate = {"product_items"}) + @Valid +// private List> productItems; + private List productItems; + @NotBlank(message = "리턴URL는 필수조건 입니다.") + @Length(max = 1000, message = "리턴URL의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "네이버페이 결제 후 리턴URL", example = " ") + @JsonProperty("returnUrl") + @JsonAlias({"return_url"}) + @SerializedName(value = "returnUrl", alternate = "return_url") + private String returnUrl; + + @Length(max = 64, message = "구매자 성명의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "구매자 성명", example = " ") + @JsonProperty("purchaserName") + @JsonAlias({"purchaser_name"}) + @SerializedName(value = "purchaserName", alternate = "purchaser_name") + private String purchaserName; + @Length(max = 64, message = "구매자 생년월일의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "구매자 생년월일(yyyyMMdd)", example = " ") + @JsonProperty("purchaserBirthday") + @JsonAlias({"purchaser_birthday"}) + @SerializedName(value = "purchaserBirthday", alternate = "purchaser_birthday") + private String purchaserBirthday; +// @Schema(required = false, title = "도서/공연비 소득공제 대상 여부", example = " ") +// @JsonProperty("extraDeduction") +// @JsonAlias({"extra_deduction"}) +// @SerializedName(value = "extraDeduction", alternate = "extra_deduction") +// private Boolean extraDeduction; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayResultDetail.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayResultDetail.java new file mode 100644 index 0000000..0afa076 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayResultDetail.java @@ -0,0 +1,211 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 네이버페이 결제결과 요청데이터 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +@ToString +public class NvPayResultDetail { + @NotBlank(message = "결제번호는 필수 입력값 입니다.") + @Length(max = 50, message = "결제번호의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "네이버페이 결제번호", example = " ") + @JsonProperty("paymentId") + @JsonAlias({"payment_id"}) + @SerializedName(value = "paymentId", alternate = {"payment_id"}) + private String paymentId; + + @NotBlank(message = "결제 이력번호는 필수 입력값 입니다.") + @Length(max = 50, message = "결제 이력번호의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "네이버페이 결제 이력 번호", example = " ") + @JsonProperty("payHistId") + @JsonAlias({"pay_hist_id"}) + @SerializedName(value = "payHistId", alternate = {"pay_hist_id"}) + private String payHistId; + @Length(max = 50, message = "가맹점 아이디의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "가맹점 아이디(가맹점센터 로그인 아이디)", example = " ") + @JsonProperty("merchantId") + @JsonAlias({"merchant_id"}) + @SerializedName(value = "merchantId", alternate = {"merchant_id"}) + private String merchantId; + @Length(max = 50, message = "가맹점명의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "가맹점명", example = " ") + @JsonProperty("merchantName") + @JsonAlias({"merchant_name"}) + @SerializedName(value = "merchantName", alternate = {"merchant_name"}) + private String merchantName; + @Length(max = 64, message = "가맹점의 결제번호의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "가맹점의 결제번호", example = " ") + @JsonProperty("merchantPayKey") + @JsonAlias({"merchant_pay_key"}) + @SerializedName(value = "merchantPayKey", alternate = {"merchant_pay_key"}) + private String merchantPayKey; + @Length(max = 50, message = "가맹점의 사용자 키의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "가맹점의 사용자 키", example = " ") + @JsonProperty("merchantUserKey") + @JsonAlias({"merchant_user_key"}) + @SerializedName(value = "merchantUserKey", alternate = {"merchant_user_key"}) + private String merchantUserKey; + @Length(max = 2, message = "결제승인 유형의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "결제승인 유형", example = " ") + @JsonProperty("admissionTypeCode") + @JsonAlias({"admission_type_code"}) + @SerializedName(value = "admissionTypeCode", alternate = {"admission_type_code"}) + private String admissionTypeCode; + @Length(max = 14, message = "결제/취소일시의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "결제/취소 일시(YYYYMMDDHH24MISS)", example = " ") + @JsonProperty("admissionYmdt") + @JsonAlias({"admission_ymdt"}) + @SerializedName(value = "admissionYmdt", alternate = {"admission_ymdt"}) + private String admissionYmdt; + @Length(max = 50, message = "거래완료 일시의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "거래완료 일시(정산기준날짜, YYYYMMDDHH24MISS)", example = " ") + @JsonProperty("tradeConfirmYmdt") + @JsonAlias({"trade_confirm_ymdt"}) + @SerializedName(value = "tradeConfirmYmdt", alternate = {"trade_confirm_ymdt"}) + private String tradeConfirmYmdt; + @Length(max = 10, message = "결제/취소 시도 최종결과의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "결제/취소 시도에 대한 최종결과", example = " ") + @JsonProperty("admissionState") + @JsonAlias({"admission_state"}) + @SerializedName(value = "admissionState", alternate = {"admission_state"}) + private String admissionState; + @Schema(required = true, title = "총 결제 금액", example = " ") + @JsonProperty("totalPayAmount") + @JsonAlias({"total_pay_amount"}) + @SerializedName(value = "totalPayAmount", alternate = {"total_pay_amount"}) + private Integer totalPayAmount; + @Schema(required = true, title = "주 결제 수단 결제 금액", example = " ") + @JsonProperty("primaryPayAmount") + @JsonAlias({"primary_pay_amount"}) + @SerializedName(value = "primaryPayAmount", alternate = {"primary_pay_amount"}) + private Integer primaryPayAmount; + @Schema(required = true, title = "네이버페이 포인트/머니 결제 금액", example = " ") + @JsonProperty("npointPayAmount") + @JsonAlias({"npoint_pay_amount"}) + @SerializedName(value = "npointPayAmount", alternate = {"npoint_pay_amount"}) + private Integer npointPayAmount; + @Schema(required = true, title = "기프트카드 결제 금액", example = " ") + @JsonProperty("giftCardAmount") + @JsonAlias({"gift_card_amount"}) + @SerializedName(value = "giftCardAmount", alternate = {"gift_card_amount"}) + private Integer giftCardAmount; + @Schema(required = true, title = "과세 결제 금액", example = " ") + @JsonProperty("taxScopeAmount") + @JsonAlias({"tax_scope_amount"}) + @SerializedName(value = "taxScopeAmount", alternate = {"tax_scope_amount"}) + private Integer taxScopeAmount; + @Schema(required = true, title = "면세 결제 금액", example = " ") + @JsonProperty("taxExScopeAmount") + @JsonAlias({"tax_ex_scope_amount"}) + @SerializedName(value = "taxExScopeAmount", alternate = {"tax_ex_scope_amount"}) + private Integer taxExScopeAmount; + @Schema(required = true, title = "컵 보증금 결제 금액", example = " ") + @JsonProperty("environmentDepositAmount") + @JsonAlias({"environment_deposit_amount"}) + @SerializedName(value = "environmentDepositAmount", alternate = {"environment_deposit_amount"}) + private Integer environmentDepositAmount; + @Length(max = 10, message = "주 결제 수단의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "주 결제 수단", example = " ") + @JsonProperty("primaryPayMeans") + @JsonAlias({"primary_pay_means"}) + @SerializedName(value = "primaryPayMeans", alternate = {"primary_pay_means"}) + private String primaryPayMeans; + @Length(max = 10, message = "주 결제 수단 카드사의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "주 결제 수단 카드사", example = " ") + @JsonProperty("cardCorpCode") + @JsonAlias({"card_corp_code"}) + @SerializedName(value = "cardCorpCode", alternate = {"card_corp_code"}) + private String cardCorpCode; + @Length(max = 50, message = "일부 마스킹 된 신용카드 번호의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "일부 마스킹 된 신용카드 번호", example = " ") + @JsonProperty("cardNo") + @JsonAlias({"card_no"}) + @SerializedName(value = "cardNo", alternate = {"card_no"}) + private String cardNo; + @Length(max = 30, message = "카드승인번호의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "카드승인번호", example = " ") + @JsonProperty("cardAuthNo") + @JsonAlias({"card_auth_no"}) + @SerializedName(value = "cardAuthNo", alternate = {"card_auth_no"}) + private String cardAuthNo; + @Schema(required = true, title = "할부 개월 수(일시불은 0)", example = " ") + @JsonProperty("cardInstCount") + @JsonAlias({"card_inst_count"}) + @SerializedName(value = "cardInstCount", alternate = {"card_inst_count"}) + private Integer cardInstCount; + @Schema(required = true, title = "카드사 포인트 사용유무", example = " ") + @JsonProperty("usedCardPoint") + @JsonAlias({"used_card_point"}) + @SerializedName(value = "usedCardPoint", alternate = {"used_card_point"}) + private Boolean usedCardPoint; + @Length(max = 10, message = "주 결제 수단 은행의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "주 결제 수단 은행", example = " ") + @JsonProperty("bankCorpCode") + @JsonAlias({"bank_corp_code"}) + @SerializedName(value = "bankCorpCode", alternate = {"bank_corp_code"}) + private String bankCorpCode; + @Length(max = 50, message = "일부 마스킹 된 계좌번호의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "일부 마스킹 된 계좌번호", example = " ") + @JsonProperty("bankAccountNo") + @JsonAlias({"bank_account_no"}) + @SerializedName(value = "bankAccountNo", alternate = {"bank_account_no"}) + private String bankAccountNo; + @Length(max = 128, message = "상품명의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "상품명", example = " ") + @JsonProperty("productName") + @JsonAlias({"product_name"}) + @SerializedName(value = "productName", alternate = {"product_name"}) + private String productName; + @Schema(required = true, title = "정산예정금액과 결제 수수료금액 계산 여부(true/false)", example = " ") + @JsonProperty("settleExpected") + @JsonAlias({"settle_expected"}) + @SerializedName(value = "settleExpected", alternate = {"settle_expected"}) + private Boolean settleExpected; + @Schema(required = true, title = "정산 예정 금액", example = " ") + @JsonProperty("settleExpectAmount") + @JsonAlias({"settle_expect_amount"}) + @SerializedName(value = "settleExpectAmount", alternate = {"settle_expect_amount"}) + private Integer settleExpectAmount; + @Schema(required = true, title = "결제 수수료 금액", example = " ") + @JsonProperty("payCommissionAmount") + @JsonAlias({"pay_commission_amount"}) + @SerializedName(value = "payCommissionAmount", alternate = {"pay_commission_amount"}) + private Integer payCommissionAmount; + @Schema(required = true, title = "도서/공연 소득공제 여부", example = " ") + @JsonProperty("extraDeduction") + @JsonAlias({"extra_deduction"}) + @SerializedName(value = "extraDeduction", alternate = {"extra_deduction"}) + private Boolean extraDeduction; + @Length(max = 8, message = "이용완료일의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "이용완료일(yyyymmdd)", example = " ") + @JsonProperty("useCfmYmdt") + @JsonAlias({"use_cfm_ymdt"}) + @SerializedName(value = "useCfmYmdt", alternate = {"use_cfm_ymdt"}) + private String useCfmYmdt; + @Length(max = 400, message = "별도 예비필드의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "별도 예비필드", example = " ") + @JsonProperty("merchantExtraParameter") + @JsonAlias({"merchant_extra_parameter"}) + @SerializedName(value = "merchantExtraParameter", alternate = {"merchant_extra_parameter"}) + private String merchantExtraParameter; + @Length(max = 28, message = "암호화된 사용자 구분값의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "암호화된 사용자 구분값", example = " ") + @JsonProperty("userIdentifier") + @JsonAlias({"user_identifier"}) + @SerializedName(value = "userIdentifier", alternate = {"user_identifier"}) + private String userIdentifier; +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayResultReqData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayResultReqData.java new file mode 100644 index 0000000..437efae --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/NvPayResultReqData.java @@ -0,0 +1,31 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.validator.constraints.Length; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; + +/** + * 네이버페이 결제결과 요청데이터 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +@ToString +public class NvPayResultReqData { + @NotBlank(message = "결제번호는 필수 입력값 입니다.") + @Length(max = 50, message = "결제번호의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "네이버페이 결제번호", example = " ") + @JsonProperty("paymentId") + @JsonAlias({"payment_id"}) + @SerializedName(value = "paymentId", alternate = {"payment_id"}) + private String paymentId; + @Valid + private NvPayResultDetail detail; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/config/able/Detail.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/config/able/Detail.java new file mode 100644 index 0000000..fb12ecd --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/config/able/Detail.java @@ -0,0 +1,240 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.config.able; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 네이버페이 결제승인 응답데이터 상세 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +@ToString +public class Detail { + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 50, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("paymentId") + @JsonAlias({"payment_id"}) + @SerializedName(value = "paymentId", alternate = "payment_id") + private String paymentId; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 50, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("payHistId") + @JsonAlias({"pay_hist_id"}) + @SerializedName(value = "payHistId", alternate = "pay_hist_id") + private String payHistId; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 50, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("merchantId") + @JsonAlias({"merchant_id"}) + @SerializedName(value = "merchantId", alternate = "merchant_id") + private String merchantId; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 50, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("merchantName") + @JsonAlias({"merchant_name"}) + @SerializedName(value = "merchantName", alternate = "merchant_name") + private String merchantName; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 64, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("merchantPayKey") + @JsonAlias({"merchant_pay_key"}) + @SerializedName(value = "merchantPayKey", alternate = "merchant_pay_key") + private String merchantPayKey; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 50, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("merchantUserKey") + @JsonAlias({"merchant_user_key"}) + @SerializedName(value = "merchantUserKey", alternate = "merchant_user_key") + private String merchantUserKey; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 2, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("admissionTypeCode") + @JsonAlias({"admission_type_code"}) + @SerializedName(value = "admissionTypeCode", alternate = "admission_type_code") + private String admissionTypeCode; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 14, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("admissionYmdt") + @JsonAlias({"admission_ymdt"}) + @SerializedName(value = "admissionYmdt", alternate = "admission_ymdt") + private String admissionYmdt; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 50, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("tradeConfirmYmdt") + @JsonAlias({"trade_confirm_ymdt"}) + @SerializedName(value = "tradeConfirmYmdt", alternate = "trade_confirm_ymdt") + private String tradeConfirmYmdt; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 10, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("admissionState") + @JsonAlias({"admission_state"}) + @SerializedName(value = "admissionState", alternate = "admission_state") + private String admissionState; + @NotNull(message = "은 필수조건 입니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("totalPayAmount") + @JsonAlias({"total_pay_amount"}) + @SerializedName(value = "totalPayAmount", alternate = "total_pay_amount") + private Integer totalPayAmount; + @NotNull(message = "은 필수조건 입니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("primaryPayAmount") + @JsonAlias({"primary_pay_amount"}) + @SerializedName(value = "primaryPayAmount", alternate = "primary_pay_amount") + private Integer primaryPayAmount; + @NotNull(message = "은 필수조건 입니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("npointPayAmount") + @JsonAlias({"npoint_pay_amount"}) + @SerializedName(value = "npointPayAmount", alternate = "npoint_pay_amount") + private Integer npointPayAmount; + @NotNull(message = "은 필수조건 입니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("giftCardAmount") + @JsonAlias({"gift_card_amount"}) + @SerializedName(value = "giftCardAmount", alternate = "gift_card_amount") + private Integer giftCardAmount; + @NotNull(message = "은 필수조건 입니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("taxScopeAmount") + @JsonAlias({"tax_scope_amount"}) + @SerializedName(value = "taxScopeAmount", alternate = "tax_scope_amount") + private Integer taxScopeAmount; + @NotNull(message = "은 필수조건 입니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("taxExScopeAmount") + @JsonAlias({"tax_ex_scope_amount"}) + @SerializedName(value = "taxExScopeAmount", alternate = "tax_ex_scope_amount") + private Integer taxExScopeAmount; + @NotNull(message = "은 필수조건 입니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("environmentDepositAmount") + @JsonAlias({"environment_deposit_amount"}) + @SerializedName(value = "environmentDepositAmount", alternate = "environment_deposit_amount") + private Integer environmentDepositAmount; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 10, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("primaryPayMeans") + @JsonAlias({"primary_pay_means"}) + @SerializedName(value = "primaryPayMeans", alternate = "primary_pay_means") + private String primaryPayMeans; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 10, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("cardCorpCode") + @JsonAlias({"card_corp_code"}) + @SerializedName(value = "cardCorpCode", alternate = "card_corp_code") + private String cardCorpCode; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 50, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("cardNo") + @JsonAlias({"card_no"}) + @SerializedName(value = "cardNo", alternate = "card_no") + private String cardNo; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 30, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("cardAuthNo") + @JsonAlias({"card_auth_no"}) + @SerializedName(value = "cardAuthNo", alternate = "card_auth_no") + private String cardAuthNo; + @NotNull(message = "은 필수조건 입니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("cardInstCount") + @JsonAlias({"card_inst_count"}) + @SerializedName(value = "cardInstCount", alternate = "card_inst_count") + private Integer cardInstCount; + @NotNull(message = "은 필수조건 입니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("usedCardPoint") + @JsonAlias({"used_card_point"}) + @SerializedName(value = "usedCardPoint", alternate = "used_card_point") + private Boolean usedCardPoint; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 10, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("bankCorpCode") + @JsonAlias({"bank_corp_code"}) + @SerializedName(value = "bankCorpCode", alternate = "bank_corp_code") + private String bankCorpCode; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 50, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("bankAccountNo") + @JsonAlias({"bank_account_no"}) + @SerializedName(value = "bankAccountNo", alternate = "bank_account_no") + private String bankAccountNo; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 128, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("productName") + @JsonAlias({"product_name"}) + @SerializedName(value = "productName", alternate = "product_name") + private String productName; + @NotNull(message = "은 필수조건 입니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("settleExpected") + @JsonAlias({"settle_expected"}) + @SerializedName(value = "settleExpected", alternate = "settle_expected") + private Boolean settleExpected; + @NotNull(message = "은 필수조건 입니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("settleExpectAmount") + @JsonAlias({"settle_expect_amount"}) + @SerializedName(value = "settleExpectAmount", alternate = "settle_expect_amount") + private Integer settleExpectAmount; + @NotNull(message = "은 필수조건 입니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("payCommissionAmount") + @JsonAlias({"pay_commission_amount"}) + @SerializedName(value = "payCommissionAmount", alternate = "pay_commission_amount") + private Integer payCommissionAmount; + @NotNull(message = "은 필수조건 입니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("extraDeduction") + @JsonAlias({"extra_deduction"}) + @SerializedName(value = "extraDeduction", alternate = "extra_deduction") + private Boolean extraDeduction; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 8, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("useCfmYmdt") + @JsonAlias({"use_cfm_ymdt"}) + @SerializedName(value = "useCfmYmdt", alternate = "use_cfm_ymdt") + private String useCfmYmdt; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 4000, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("merchantExtraParameter") + @JsonAlias({"merchant_extra_parameter"}) + @SerializedName(value = "merchantExtraParameter", alternate = "merchant_extra_parameter") + private String merchantExtraParameter; + @NotBlank(message = "은 필수조건 입니다.") + @Length(max = 44, message = "의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "", example = " ") + @JsonProperty("userIdentifier") + @JsonAlias({"user_identifier"}) + @SerializedName(value = "userIdentifier", alternate = "user_identifier") + private String userIdentifier; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/config/notice/ProductItem.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/config/notice/ProductItem.java new file mode 100644 index 0000000..3e634c4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/process/model/config/notice/ProductItem.java @@ -0,0 +1,74 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.model.config.notice; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.process.code.NvEpCtgyTypeCd; +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 네이버페이 결제정보 응답데이터 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +@ToString +@JsonInclude(JsonInclude.Include.NON_NULL) //2023.03.14 네이버페이 검수 결과 - 요청대상이 아닌 null 값 제외 +public class ProductItem { + @NotNull(message = "결제상품 유형은 필수조건 입니다.") +// @Length(max = 10, message = "결제상품 유형의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "결제상품 유형", example = " ") + @JsonProperty("categoryType") + @JsonAlias({"category_type"}) + @SerializedName(value = "categoryType", alternate = "category_type") + private NvEpCtgyTypeCd categoryType; + @NotBlank(message = "결제상품 분류는 필수조건 입니다.") + @Length(max = 16, message = "결제상품 분류의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "결제상품 분류", example = " ") + @JsonProperty("categoryId") + @JsonAlias({"category_id"}) + @SerializedName(value = "categoryId", alternate = "category_id") + private String categoryId; + @NotBlank(message = "결제상품 식별값은 필수조건 입니다.") + @Length(max = 100, message = "결제상품 식별값의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "결제상품 식별값", example = " ") + private String uid; + @NotBlank(message = "상품명은 필수조건 입니다.") + @Length(max = 128, message = "상품명의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "상품명", example = " ") + private String name; + @Length(max = 20, message = "결제상품유형의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "결제상품유형", example = " ") + @JsonProperty("payReferrer") + @JsonAlias({"pay_referrer"}) + @SerializedName(value = "payReferrer", alternate = "pay_referrer") + private String payReferrer; + @Length(max = 8, message = "시작일의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "시작일(yyyyMMdd)", example = "20160701") + @JsonProperty("startDate") + @JsonAlias({"start_date"}) + @SerializedName(value = "startDate", alternate = "start_date") + private String startDate; + @Length(max = 8, message = "종료일의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "종료일(yyyMMdd)", example = "20160701") + @JsonProperty("endDate") + @JsonAlias({"end_date"}) + @SerializedName(value = "endDate", alternate = "end_date") + private String endDate; + @Length(max = 30, message = "하위판매자식별키의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "하위판매자식별키", example = " ") + @JsonProperty("sellerId") + @JsonAlias({"seller_id"}) + @SerializedName(value = "sellerId", alternate = "seller_id") + private String sellerId; + @NotNull(message = "결제 상품 개수는 필수조건 입니다.") + @Schema(required = true, title = "결제 상품 개수", example = "1") + private Integer count; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/repair/kit/RepairNvPayResultTransferFail.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/repair/kit/RepairNvPayResultTransferFail.java new file mode 100644 index 0000000..68849d1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/nv/service/repair/kit/RepairNvPayResultTransferFail.java @@ -0,0 +1,27 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.nv.service.repair.kit; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.kit.RepairPayResultTransferFail; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.model.RepairPayRsltFwdFailSearchDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.Builder; + + +public class RepairNvPayResultTransferFail extends RepairPayResultTransferFail { + @Builder + public RepairNvPayResultTransferFail(JPAQueryFactory query, RepairPayRsltFwdFailSearchDTO searchDTO) { + this.query = query; + this.searchDTO = searchDTO; + } + + @Override + protected String getPayResultApiUrl(OrgMng orgMng) { + return orgMng.getNvBpPayresultApi(); + } + + @Override + protected BillSeCd getBillSeCd() { + return BillSeCd.bpNv; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PayApi.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PayApi.java new file mode 100644 index 0000000..e660465 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PayApi.java @@ -0,0 +1,170 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support; + +import cokr.xit.ens.core.utils.CmmnUtil; +import org.springframework.http.*; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +public interface PayApi { + + /** + * 결제 URL 생성정보 요청 + * + * @param uri + * @param mParam + * @return + */ + ResponseEntity payUrl(String uri, Map mParam, HttpHeaders headers); + + /** + * 결제정보 요청 + * + * @param uri + * @param mParam + * @return + */ + ResponseEntity payNotice(String uri, Map mParam, HttpHeaders headers); + + /** + * 납부가능여부 + * + * @param uri + * @param mParam + * @return + */ + ResponseEntity payAble(String uri, Map mParam, HttpHeaders headers); + + /** + * 납부결과 + * + * @param uri + * @param mParam + * @return + */ + ResponseEntity payResult(String uri, Map mParam, HttpHeaders headers); + + /** + * 결제취소 + * + * @param uri + * @param mParam + * @return + */ + ResponseEntity payCancelResult(String uri, Map mParam, HttpHeaders headers); + + + /** + * API 호출 + * + * @param method 호출메소드(GET/POST/PUT/DELETE) + * @param url 호출 URL + * @param body 파라미터 + * @param headers 요청헤더정보 + * @return + * @author 박민규 + */ + default ResponseEntity callApi(HttpMethod method, String url, String body, HttpHeaders headers) { + return this.callApi(method, url, body, headers, 5000, 30000); + } + + /** + * API 호출 + * + * @param method 호출메소드(GET/POST/PUT/DELETE) + * @param url 호출 URL + * @param body 파라미터 + * @param headers 요청헤더정보 + * @param connectTimeout 통신 연결 제한시간(ms) + * @param readTimeout 응답데이터 read 제한시간(ms) + * @return + * @author 박민규 + */ + default ResponseEntity callApi(HttpMethod method, String url, String body, HttpHeaders headers, int connectTimeout, int readTimeout) { + StringBuffer sb = new StringBuffer(); + StringBuffer log = new StringBuffer(); + log.append(getClass().getSimpleName()); + ResponseEntity responseEntity = null; + try { + + HttpEntity entity = null; + UriComponents uri = null; + switch (method) { + case GET: + entity = new HttpEntity<>(headers); + uri = UriComponentsBuilder + .fromHttpUrl(String.format("%s?%s", url, body == null ? "" : body)) +// .encode(StandardCharsets.UTF_8) //"%"기호가 "%25"로 인코딩 발생하여 주석처리 함. + .build(false); + break; + case POST: + entity = new HttpEntity<>(body, headers); + uri = UriComponentsBuilder + .fromHttpUrl(url) + .encode(StandardCharsets.UTF_8) + .build(); + break; + + default: + break; + } + + sb.append("url => " + uri.toString()) + .append("\n method => " + method) + .append("\n headers => " + entity.getHeaders().toString()) + .append("\n body => " + entity.getBody()); + + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + factory.setConnectTimeout(connectTimeout); + factory.setReadTimeout(readTimeout); + RestTemplate restTemplate = new RestTemplate(factory); + responseEntity = restTemplate.exchange(URI.create(uri.toString()), method, entity, String.class); + + } catch (HttpServerErrorException e) { + responseEntity = new ResponseEntity(e.getResponseBodyAsString(), e.getStatusCode()); + log.append(System.getProperty("line.separator")) + .append("call API 서버오류") + .append("[ error ]: ") + .append(CmmnUtil.printStackTraceToString(e)); + } catch (HttpClientErrorException e) { + responseEntity = new ResponseEntity(e.getResponseBodyAsString(), e.getStatusCode()); + log.append(System.getProperty("line.separator")) + .append("call API 클라이언트오류") + .append("[ error ]: ") + .append(CmmnUtil.printStackTraceToString(e)); + } catch (RestClientException e) { + responseEntity = new ResponseEntity(e.getMessage(), HttpStatus.REQUEST_TIMEOUT); + log.append(System.getProperty("line.separator")) + .append("RestAPI 호출 오류") + .append("[ error ]: ") + .append(CmmnUtil.printStackTraceToString(e)); + } catch (Exception e) { + responseEntity = new ResponseEntity(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + log.append(System.getProperty("line.separator")) + .append("call API 기타오류") + .append("[ error ]: ") + .append(CmmnUtil.printStackTraceToString(e)); + } finally { + log.append(System.getProperty("line.separator")) + .append("[ REQUEST ]-----------------------------------------------------------------------") + .append(System.getProperty("line.separator")) + .append(sb.toString()) + .append(System.getProperty("line.separator")) + .append("[ RESPONSE ]-----------------------------------------------------------------------") + .append(System.getProperty("line.separator")) + .append(responseEntity.getBody()); + System.out.println(log.toString()); + } + + return responseEntity; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PayController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PayController.java new file mode 100644 index 0000000..46897d1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PayController.java @@ -0,0 +1,51 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support; + +/** + * 결제 컨트롤러 + * + * @param 리턴타입 + * @param

파라미터 + */ +public interface PayController { + + /** + * 청구서링크 생성 + * + * @param p + * @return + */ + T gnrUrl(P p); + + /** + * 결제정보 + * + * @param p + * @return + */ + T payNotice(P p); + + /** + * 결제 전 납부가능여부 + * + * @param p + * @return + */ + T payAble(P p); + + /** + * 결제 후 납부결과 + * + * @param p + * @return + */ + T payResult(P p); + + /** + * 결제취소 + * + * @param p + * @return + */ + T payCancel(P p); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PayRepairController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PayRepairController.java new file mode 100644 index 0000000..6ee4d47 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PayRepairController.java @@ -0,0 +1,84 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.PayRepairServiceFactory; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.model.RepairPayRsltFwdFailSearchDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Arrays; +import java.util.Map; + +@Tag(name = "PayRepairController") +@Slf4j +@RestController +@RequiredArgsConstructor +public class PayRepairController { + private final PayRepairServiceFactory payRepairServiceFactory; + + @Parameters({ + @Parameter(name = "paySe", example = "kko", required = true, in = ParameterIn.PATH), + }) + @Operation(summary = "납부(결제)결과전달 실패자료 조회") + @PostMapping(value = "/bill/pay/repair/{paySe}/trsf/fail/payresult/find", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity findTransferFailData(@PathVariable String paySe, @RequestBody RepairPayRsltFwdFailSearchDTO searchDTO) { + + EnsResponseVO> result = null; + try { + + if (Arrays.stream(PayRepairServiceFactory.PRepairPaySe.values()).noneMatch(pTriggerPaySe -> pTriggerPaySe.name().equals(paySe))) + throw new EnsException(EnsErrCd.INVALID_REQUEST_URL, EnsErrCd.INVALID_REQUEST_URL.getCodeNm()); + final PayRepairServiceFactory.PRepairPaySe pTriggerPaySe = PayRepairServiceFactory.PRepairPaySe.valueOf(paySe); + + result = EnsResponseVO.>okBuilder() + .resultInfo((Map) payRepairServiceFactory.getService(pTriggerPaySe).findTransferFailedPayResultDataList(searchDTO)) + .build(); + } catch (EnsException e) { + result = EnsResponseVO.>errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + return new ResponseEntity>>(result, HttpStatus.OK); + } + + @Parameters({ + @Parameter(name = "paySe", example = "kko", required = true, in = ParameterIn.PATH), + }) + @Operation(summary = "납부(결제)결과전달 실패자료 전송") + @PostMapping(value = "/bill/pay/repair/{paySe}/trsf/fail/payresult", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity sendTransferFailData(@PathVariable String paySe, @RequestBody RepairPayRsltFwdFailSearchDTO searchDTO) { + + EnsResponseVO> result = null; + try { + + if (Arrays.stream(PayRepairServiceFactory.PRepairPaySe.values()).noneMatch(pTriggerPaySe -> pTriggerPaySe.name().equals(paySe))) + throw new EnsException(EnsErrCd.INVALID_REQUEST_URL, EnsErrCd.INVALID_REQUEST_URL.getCodeNm()); + final PayRepairServiceFactory.PRepairPaySe pTriggerPaySe = PayRepairServiceFactory.PRepairPaySe.valueOf(paySe); + + result = EnsResponseVO.>okBuilder() + .resultInfo((Map) payRepairServiceFactory.getService(pTriggerPaySe).sendTransferFailedPayResultDataList(searchDTO)) + .build(); + } catch (EnsException e) { + result = EnsResponseVO.>errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + return new ResponseEntity>>(result, HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PayUseSysController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PayUseSysController.java new file mode 100644 index 0000000..929be5e --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PayUseSysController.java @@ -0,0 +1,11 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support; + +/** + * 결제이용시스템 컨트롤러 + * + * @param 리턴타입 + * @param

파라미터 + */ +public interface PayUseSysController extends PayController { + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PaymentTriggerController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PaymentTriggerController.java new file mode 100644 index 0000000..1e4aea6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/PaymentTriggerController.java @@ -0,0 +1,95 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.QBill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.trigger.PaymentTriggerService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.trigger.PaymentTriggerServiceFactory; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng; +import com.querydsl.jpa.impl.JPAQueryFactory; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Tag(name = "PaymentTriggerController") +@Slf4j +@RestController +@RequiredArgsConstructor +public class PaymentTriggerController { + + private final JPAQueryFactory query; + private final PaymentTriggerServiceFactory paymentTriggerServiceFactory; + + @CrossOrigin(origins = "*") +// @CrossOrigin(origins = {"http://localhost:8080", "https://localhost:8080"}) +// @CrossOrigin(originPatterns = {"http:**", "https:**"}) + @Parameters({ + @Parameter(name = "paySe", example = "kko", required = true, in = ParameterIn.PATH), + @Parameter(name = "billUid", example = "청구서UID", required = true, in = ParameterIn.PATH) + }) + @Operation(summary = "납부(결제)정보 요청") + @GetMapping(value = "/bill/pay/trg/{paySe}/{billUid}/payinf", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity payInfo(@PathVariable String paySe, @PathVariable String billUid) { + + EnsResponseVO> result = null; + try { + + if (Arrays.stream(PaymentTriggerServiceFactory.PTriggerPaySe.values()).noneMatch(pTriggerPaySe -> pTriggerPaySe.name().equals(paySe))) + throw new EnsException(EnsErrCd.INVALID_REQUEST_URL, EnsErrCd.INVALID_REQUEST_URL.getCodeNm()); + final PaymentTriggerServiceFactory.PTriggerPaySe pTriggerPaySe = PaymentTriggerServiceFactory.PTriggerPaySe.valueOf(paySe); + + + Bill bill = Optional.ofNullable(query.selectFrom(QBill.bill).leftJoin(QBill.bill.orgMng, QOrgMng.orgMng).fetchJoin().where(QBill.bill.billUid.eq(billUid)).fetchOne()) + .filter(entity -> entity != null) + .map(entity -> { + if (entity.getPaidAt()) { + throw new EnsException(EnsErrCd.PAYMENT_ALREADY_CMPLTED + , String.format("%s\n -.결제수단: %s\n -.결제일시: %s" + , EnsErrCd.PAYMENT_ALREADY_CMPLTED.getCodeNm(), entity.getPaidType().getCodeNm(), entity.getPaidDt())); + } + return entity; + }) + .orElseThrow(() -> new EnsException(EnsErrCd.NO_DATA_FOUND, "청구 자료를 찾을 수 없습니다.")); + + if (CmmnUtil.isEmpty(bill.getOrgMng())) + throw new EnsException(EnsErrCd.NO_DATA_FOUND, "청구결제 위탁기관을 찾을 수 없습니다."); + + + Map param = new HashMap<>(); + param.put(PaymentTriggerService.PTriggerDataKeys.bill, bill); + param.put(PaymentTriggerService.PTriggerDataKeys.billUid, billUid); + + + result = EnsResponseVO.>okBuilder() + .resultInfo(paymentTriggerServiceFactory.getService(pTriggerPaySe).payInfo(param)) + .build(); + } catch (EnsException e) { + result = EnsResponseVO.>errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + + + return new ResponseEntity>>(result, HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/api/PayUseSysApi.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/api/PayUseSysApi.java new file mode 100644 index 0000000..ebcd852 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/api/PayUseSysApi.java @@ -0,0 +1,91 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.PayApi; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +import java.nio.charset.Charset; +import java.util.Map; + +/** + * 페이결제 이용시스템 API + * + * @Description 결제에 필요한 정보를 이용시스템측에 요청 한다. 이용시스템측은 요청을 수신 할 수 있도록 API를 구축해야 한다. + */ +@Slf4j +@Component +//@Profile({"!local-test"}) +public class PayUseSysApi implements PayApi { + + + @Override + public ResponseEntity payUrl(String uri, Map mParam, HttpHeaders headers) { + + if (headers == null) + headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + + + String param = CmmnUtil.toJsonString(mParam); + + return callApi(HttpMethod.POST, uri, param, headers); + } + + @Override + public ResponseEntity payNotice(String uri, Map mParam, HttpHeaders headers) { + + if (headers == null) + headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + + + String param = CmmnUtil.toJsonString(mParam); + + return callApi(HttpMethod.POST, uri, param, headers); + } + + @Override + public ResponseEntity payAble(String uri, Map mParam, HttpHeaders headers) { + + if (headers == null) + headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + + + String param = CmmnUtil.toJsonString(mParam); + + return callApi(HttpMethod.POST, uri, param, headers); + } + + @Override + public ResponseEntity payResult(String uri, Map mParam, HttpHeaders headers) { + + if (headers == null) + headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + + + String param = CmmnUtil.toJsonString(mParam); + + return callApi(HttpMethod.POST, uri, param, headers); + } + + @Override + public ResponseEntity payCancelResult(String uri, Map mParam, HttpHeaders headers) { + + if (headers == null) + headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + + + String param = CmmnUtil.toJsonString(mParam); + + return callApi(HttpMethod.POST, uri, param, headers); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/BillLogSeCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/BillLogSeCd.java new file mode 100644 index 0000000..a9219a1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/BillLogSeCd.java @@ -0,0 +1,38 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *

    + *
  • 업무 그룹명: 청구서API - 청구서 로그 구분
  • + *
  • 설 명: 이용시스템과 벤더사의 연계 오류를 구분하기 위한 코드 값. 응답메시지에 사용하며 업무 로직에는 사용되지 않는다.
  • + *
  • 작성일: 2023. 2. 25. 오후 3:51:43 + *
+ * + * @author 박민규 + */ +public enum BillLogSeCd implements CodeMapperType { + + US("이용시스템"), + VD("벤더") + ; + + private final String code; + private final String codeNm; + + BillLogSeCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/BillReqSeCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/BillReqSeCd.java new file mode 100644 index 0000000..7cc861e --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/BillReqSeCd.java @@ -0,0 +1,55 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *
    + *
  • 업무 그룹명: 청구서API - 요청구분 코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2022. 2. 15. 오후 3:51:43 + *
+ * + * @author 박민규 + */ + +public enum BillReqSeCd implements CodeMapperType { + + + ACPT("요청 접수"), + + + VD_URL("청구서링크생성"), + VD_REURL("청구서링크재생성"), + VD_PAYAPPLY("결제승인요청"), + VD_PAYCANCEL("결제취소"), + + + US_URLINF("이용시스템 청구서링크생성 정보"), + NOTICE("결제정보조회"),//TODO feat.NaverPay 민자고속도로 ENS_BILL_HIST DB에서 NOTICE -> GETNOTICE로 update 이후 코드삭제 요함 + US_NOTICE("이용시스템 결제정보"), + PREPAY("납부가능확인"),//TODO feat.NaverPay 민자고속도로 ENS_BILL_HIST DB에서 PREPAY -> CHKPREPAY로 update 이후 코드삭제 요함 + US_PREPAY("이용시스템 납부가능확인"), + PAYRSLT("납부결과전달"),//TODO feat.NaverPay 민자고속도로 ENS_BILL_HIST DB에서 PAYRSLT -> FWDPAYRSLT로 update 이후 코드삭제 요함 + US_PAYRSLT("이용시스템 납부결과전달"), + US_CANCELRSLT("이용시스템 결제취소결과전달"), + ; + + private final String code; + private final String codeNm; + + BillReqSeCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/BillSeCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/BillSeCd.java new file mode 100644 index 0000000..b3d6c8c --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/BillSeCd.java @@ -0,0 +1,40 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *
    + *
  • 업무 그룹명: 청구서API - 청구서 구분 코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2022. 9. 20. 오후 3:51:43 + *
+ * + * @author 박민규 + */ +public enum BillSeCd implements CodeMapperType { + + bpKko("카카오페이 청구서"), + bpNv("네이버페이 간편결제"), + privt("전자문서 벤더사의 결제시스템"), + all("모든 벤더사의 결제시스템"), + ; + + private final String code; + private final String codeNm; + + BillSeCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/PaidTypeCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/PaidTypeCd.java new file mode 100644 index 0000000..1864d2a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/PaidTypeCd.java @@ -0,0 +1,38 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *
    + *
  • 업무 그룹명: 요금 납부(결제) 구분
  • + *
  • 설 명:
  • + *
  • 작성일: 2023. 2. 15. 오전 8:28:43 + *
+ * + * @author 박민규 + */ +public enum PaidTypeCd implements CodeMapperType { + + kakaoPay("카카오페이"), + naverPay("네이버페이"), + ; + + private final String code; + private final String codeNm; + + PaidTypeCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/PayUseSysHisSeCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/PayUseSysHisSeCd.java new file mode 100644 index 0000000..63daa2d --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/PayUseSysHisSeCd.java @@ -0,0 +1,41 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *
    + *
  • 업무 그룹명: 이용시스템 페이결제 이력구분코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2023. 2. 15. 오전 8:38:43 + *
+ * + * @author 박민규 + */ +public enum PayUseSysHisSeCd implements CodeMapperType { + + gnrUrl("청구서링크생성"), + payNotice("납부(결제)정보"), + payAble("납부(결제)가능여부"), + payResult("납부(결제)결과"), + payCancel("결제취소결과"), + ; + + private final String code; + private final String codeNm; + + PayUseSysHisSeCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/PayUseSysResCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/PayUseSysResCd.java new file mode 100644 index 0000000..3dd7bb2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/code/PayUseSysResCd.java @@ -0,0 +1,61 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *
    + *
  • 업무 그룹명: 결제API - 이용시스템 응답 코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2023. 2. 01. 오후 5:47:43 + *
+ * + * @author 박민규 + */ +public enum PayUseSysResCd implements CodeMapperType { + + + OK("성공"), + + + GRNURL_FIND_FAILED("청구서링크생성 정보 조회 실패"), + + + NOT_FOUND_PAYDATA("결제 정보 없음"), + PAYDATA_FIND_FAILED("결제 정보 조회 실패"), + + + + NO_AMOUNT_PAYABLE("납부 가능 금액 없음"), + OVERPAYABLE_AMOUNT("납부 가능 금액 초과"), + NO_TARGET_PAYABLE("납부가능 대상 없음"), + EXPIRED_DATE("납부기한 지나서 납부 불가"), + FAILED_CHECK_INFO("납부 요청정보 조회 실패"), + + + FAILED_SAVE_PAYRSLT("납부(결제)결과 저장 실패"), + + + FAILED_SAVE_CANCELRSLT("결제취소결과 저장 실패"), + + + ; + + private final String code; + private final String codeNm; + + PayUseSysResCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + @Override + public String getCode() { + return this.code; + } + + @Override + public String getCodeNm() { + return this.codeNm; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/Bill.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/Bill.java new file mode 100644 index 0000000..dee6e61 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/Bill.java @@ -0,0 +1,72 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity; + +import cokr.xit.ens.core.jpa.support.BooleanToYnConverter; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PaidTypeCd; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.persistence.*; +import java.io.Serializable; + +@Entity +@Getter +@ToString +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +//@Inheritance(strategy = InheritanceType.JOINED) +//@DiscriminatorColumn(name = "dtype") +//@DiscriminatorValue("master") +@Table(name = "ens_bill", schema = "", catalog = "") +@Schema(name = "Bill") +public class Bill extends BillBaseEntity implements Serializable { + @Id + @GeneratedValue(strategy = GenerationType.TABLE, generator = "Bill_Generator") + @TableGenerator(table = "ens_seq_generator", name = "Bill_Generator" + , pkColumnName = "seq_name", pkColumnValue = "Bill_id" + , initialValue = 0, allocationSize = 200) + @Schema(required = true, title = "PK", example = " ") + private Long billId; + + @Enumerated(EnumType.STRING) + @Schema(required = true, title = "청구서 타입", example = " ") + @Column(name = "bill_se_cd", nullable = false) + private BillSeCd billSeCd; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "org_cd", nullable = false) + @Setter + private OrgMng orgMng; + + @Convert(converter = BooleanToYnConverter.class) + @Schema(required = false, title = "납부(결제)여부", example = " ") + @Column(name = "paid_at", nullable = true, length = 1) + @Setter + private Boolean paidAt; + @Schema(required = false, title = "지불 유형", example = " ") + @Column(name = "paid_type", nullable = true, length = 15) + @Enumerated(EnumType.STRING) + @Setter + private PaidTypeCd paidType; + @Schema(required = false, title = "납부(결제) 날짜", example = " ") + @Column(name = "paid_dt", nullable = true, length = 14) + @Setter + private String paidDt; + @Schema(required = false, title = "납부(결제) 취소 날짜", example = " ") + @Column(name = "paid_cancel_dt", nullable = true, length = 14) + @Setter + private String paidCancelDt; + + @Schema(required = false, title = "카카오 청구서", example = " ") + @Column(name = "doc_bill_kko", nullable = true) + @Lob + private String docBillKko; + + @Schema(required = false, title = "네이버 청구서", example = " ") + @Column(name = "doc_bill_nv", nullable = true) + @Lob + private String docBillNv; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/BillBaseEntity.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/BillBaseEntity.java new file mode 100644 index 0000000..9c2cd41 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/BillBaseEntity.java @@ -0,0 +1,26 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity; + +import cokr.xit.ens.modules.common.domain.BaseEntity; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; + +import javax.persistence.Column; +import javax.persistence.MappedSuperclass; + +@Getter +@Setter +@MappedSuperclass +@SuperBuilder +@NoArgsConstructor +public abstract class BillBaseEntity extends BaseEntity { + + @Column(name = "bill_uid", nullable = true, unique = true, length = 45) + private String billUid; + + @Schema(required = true, title = "기관에서 관리하는 해당 고객번호 혹은 계약번호", example = " ") + @Column(name = "biller_user_key", nullable = false, length = 40) + private String billerUserKey; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/BillHist.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/BillHist.java new file mode 100644 index 0000000..5d4a1a5 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/BillHist.java @@ -0,0 +1,57 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHistBaseEntity; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.domain.BaseEntity; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.persistence.*; + +@Entity +@Getter +@ToString +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_bill_his", schema = "", catalog = "", indexes = { + @Index(name = "idx_bill_his_01", columnList = "linked_uuid, req_se"), + @Index(name = "idx_bill_his_02", columnList = "bill_uid") +}) +@Schema(name = "BillHist") +public class BillHist extends BillHistBaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id", nullable = false) + @Schema(required = true, title = "PK", example = " ") + private Long id; + + @Schema(required = false, title = "청구서 유니크 아이디", example = " ") + @Column(name = "bill_uid", nullable = true, unique = false, length = 45) + private String billUid; + + @Schema(required = true, title = "청구서구분", example = " ") + @Column(name = "bill_se", nullable = false, length = 15) + @Enumerated(EnumType.STRING) + private BillSeCd billSe; + + @Schema(required = true, title = "요청구분", example = " ") + @Column(name = "req_se", nullable = false, length = 15) + @Enumerated(EnumType.STRING) + private BillReqSeCd reqSe; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "org_cd") + @Schema(required = false, title = "기관코드", example = " ") + private OrgMng orgMng; + + @Schema(required = false, title = "연계식별키", example = "") + @Column(name = "linked_uuid") + @Setter + private String linkedUuid; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/BillHistBaseEntity.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/BillHistBaseEntity.java new file mode 100644 index 0000000..f71e6d1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/BillHistBaseEntity.java @@ -0,0 +1,38 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity; + +import cokr.xit.ens.modules.common.domain.BaseEntity; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; + +import javax.persistence.Column; +import javax.persistence.Embedded; +import javax.persistence.Lob; +import javax.persistence.MappedSuperclass; + +@Getter +@Setter +@MappedSuperclass +@SuperBuilder +@NoArgsConstructor +public abstract class BillHistBaseEntity extends BaseEntity { + + + @Schema(required = false, title = "요청", example = " ") + @Column(name = "request_data", nullable = true) + @Lob + private String requestData; + + @Schema(required = false, title = "응답", example = " ") + @Column(name = "response_data", nullable = true) + @Lob + @Setter + private String responseData; + + @Embedded + @Setter + private FieldError error; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/BillHistPayUseSysBaseEntity.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/BillHistPayUseSysBaseEntity.java new file mode 100644 index 0000000..1878156 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/BillHistPayUseSysBaseEntity.java @@ -0,0 +1,33 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysHisSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PaidTypeCd; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; + +import javax.persistence.Column; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.MappedSuperclass; + +@Getter +@Setter +@MappedSuperclass +@SuperBuilder +@NoArgsConstructor +public abstract class BillHistPayUseSysBaseEntity extends BillHistBaseEntity { + + + @Schema(required = true, title = "지불 유형", example = " ") + @Column(name = "paid_type", nullable = false, length = 15) + @Enumerated(EnumType.STRING) + private PaidTypeCd paidType; + + @Schema(required = true, title = "이력구분", example = " ") + @Column(name = "his_se_cd", nullable = false, length = 15) + @Enumerated(EnumType.STRING) + private PayUseSysHisSeCd hisSeCd; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/repository/BillHistRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/repository/BillHistRepository.java new file mode 100644 index 0000000..caa02eb --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/repository/BillHistRepository.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface BillHistRepository extends JpaRepository { + + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/repository/BillRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/repository/BillRepository.java new file mode 100644 index 0000000..2bf57e6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/entity/repository/BillRepository.java @@ -0,0 +1,16 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import io.lettuce.core.dynamic.annotation.Param; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.Optional; + +public interface BillRepository extends JpaRepository { + + @Query("select a from Bill a inner join a.orgMng where a.billUid = :billUid") + Optional findByBillUid(@Param("billUid") String billUid); + + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/model/PayApiRespDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/model/PayApiRespDTO.java new file mode 100644 index 0000000..70d88e0 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/model/PayApiRespDTO.java @@ -0,0 +1,56 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +@Getter +@ToString +@EqualsAndHashCode +@NoArgsConstructor +@Schema(name = "PayApiRespDTO") +public class PayApiRespDTO { + + @Schema(title = "응답코드", example = " ") + @JsonProperty("res_code") + @JsonAlias({"resCode", "code"}) + @SerializedName(value = "res_code", alternate = {"resCode", "code"}) + private String resCode; + + @Schema(title = "응답메시지", example = " ") + @Setter + private String message; + + @Schema(title = "응답데이터", example = " ") + @Setter + @JsonProperty("data") + @JsonAlias({"body"}) + @SerializedName(value = "data", alternate = {"body"}) + private T data; + + + @Builder(builderClassName = "okBuilder", builderMethodName = "okBuilder") + PayApiRespDTO(T data) { + this.resCode = PayUseSysResCd.OK.getCode(); + this.message = PayUseSysResCd.OK.getCodeNm(); + this.data = data; + } + + @Builder(builderClassName = "errBuilder", builderMethodName = "errBuilder") + PayApiRespDTO(String resCode, String message) { + this.resCode = resCode; + this.message = message; + this.data = null; + } + + @Builder(builderClassName = "errDataBuilder", builderMethodName = "errDataBuilder") + PayApiRespDTO(String resCode, String message, T data) { + this.resCode = resCode; + this.message = message; + this.data = data; + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/Pay.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/Pay.java new file mode 100644 index 0000000..cc9f9d3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/Pay.java @@ -0,0 +1,21 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process; + +import cokr.xit.ens.core.exception.EnsException; + +/** + * 결제 처리자 + */ +public interface Pay { + + /** + * 실행 + * + * @return + */ + void exec(); + + RSLT getResult(); + + EnsException getException(); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/PayHelperService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/PayHelperService.java new file mode 100644 index 0000000..0437fc7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/PayHelperService.java @@ -0,0 +1,53 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process; + +import cokr.xit.ens.core.exception.EnsException; + +/** + * 결제 서비스 + */ +public interface PayHelperService { + + /** + * 데이터 조회 + * + * @param param + * @return + */ + D getData(PARAM param); + + /** + * 유효성 검사 + * + * @param param + * @param data + */ + void validate(PARAM param, D data); + + /** + * API 호출 + * + * @param param + * @param data + */ + void callApi(PARAM param, D data); + + /** + * 처리결과 생성 + *s + * @param param + * @param data + * @param e + * @return + */ + RSLT generateResult(PARAM param, D data, EnsException e); + + /** + * 이력 저장 + * + * @param param + * @param data + * @param e + */ + void saveHist(PARAM param, D data, EnsException e); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/PayProcessService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/PayProcessService.java new file mode 100644 index 0000000..046e3fa --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/PayProcessService.java @@ -0,0 +1,51 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process; + +/** + * 결제 서비스 + * + * @param 리턴타입 + * @param

파라미터 + */ +public interface PayProcessService { + + /** + * 결제 URL 생성 + * + * @param p + * @return + */ + T gnrUrl(P p); + + /** + * 결제정보 + * + * @param p + * @return + */ + T payNotice(P p); + + /** + * 결제 전 납부가능여부 + * + * @param p + * @return + */ + T payAble(P p); + + /** + * 결제 후 납부결과 + * + * @param p + * @return + */ + T payResult(P p); + + /** + * 결제취소 + * + * @param p + * @return + */ + T payCancel(P p); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayAbleService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayAbleService.java new file mode 100644 index 0000000..bc6fbcd --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayAbleService.java @@ -0,0 +1,10 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.PayHelperService; + +/** + * 결제가능확인 서비스 + */ +public interface PayAbleService extends PayHelperService { + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayCancelService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayCancelService.java new file mode 100644 index 0000000..9af83fe --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayCancelService.java @@ -0,0 +1,10 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.PayHelperService; + +/** + * 결제결과 서비스 + */ +public interface PayCancelService extends PayHelperService { + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayNoticeService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayNoticeService.java new file mode 100644 index 0000000..955bddf --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayNoticeService.java @@ -0,0 +1,10 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.PayHelperService; + +/** + * 결제정보 서비스 + */ +public interface PayNoticeService extends PayHelperService { + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayResultService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayResultService.java new file mode 100644 index 0000000..76cc974 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayResultService.java @@ -0,0 +1,10 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.PayHelperService; + +/** + * 결제결과 서비스 + */ +public interface PayResultService extends PayHelperService { + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayUrlService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayUrlService.java new file mode 100644 index 0000000..acb521e --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/kit/PayUrlService.java @@ -0,0 +1,11 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.PayHelperService; + +/** + * 결제URL 생성 서비스 + */ +public interface PayUrlService extends PayHelperService { + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayAbleData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayAbleData.java new file mode 100644 index 0000000..56bc77c --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayAbleData.java @@ -0,0 +1,24 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +@Getter +@EqualsAndHashCode +@Builder +public class PayAbleData { + private Bill bill; + private DTL billDetail; + + @Setter + private ReqAndRespInf reqAndRespInf; + + public ReqAndRespInf getReqAndRespInf() { + if (this.reqAndRespInf == null) + this.reqAndRespInf = ReqAndRespInf.builder().build(); + return this.reqAndRespInf; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayCancelData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayCancelData.java new file mode 100644 index 0000000..ed82ac6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayCancelData.java @@ -0,0 +1,24 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +@Getter +@EqualsAndHashCode +@Builder +public class PayCancelData { + private Bill bill; + private DTL billDetail; + + @Setter + private ReqAndRespInf reqAndRespInf; + + public ReqAndRespInf getReqAndRespInf() { + if (this.reqAndRespInf == null) + this.reqAndRespInf = ReqAndRespInf.builder().build(); + return this.reqAndRespInf; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayNoticeData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayNoticeData.java new file mode 100644 index 0000000..2d632d9 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayNoticeData.java @@ -0,0 +1,24 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +@Getter +@EqualsAndHashCode +@Builder +public class PayNoticeData { + private Bill bill; + private DTL billDetail; + + @Setter + private ReqAndRespInf reqAndRespInf; + + public ReqAndRespInf getReqAndRespInf() { + if (this.reqAndRespInf == null) + this.reqAndRespInf = ReqAndRespInf.builder().build(); + return this.reqAndRespInf; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayResultData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayResultData.java new file mode 100644 index 0000000..13cee07 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayResultData.java @@ -0,0 +1,24 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +@Getter +@EqualsAndHashCode +@Builder +public class PayResultData { + private Bill bill; + private DTL billDetail; + + @Setter + private ReqAndRespInf reqAndRespInf; + + public ReqAndRespInf getReqAndRespInf() { + if (this.reqAndRespInf == null) + this.reqAndRespInf = ReqAndRespInf.builder().build(); + return this.reqAndRespInf; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayUrlData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayUrlData.java new file mode 100644 index 0000000..53949f9 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/PayUrlData.java @@ -0,0 +1,24 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +@Getter +@EqualsAndHashCode +@Builder +public class PayUrlData { + private Bill bill; + private DTL billDetail; + + @Setter + private ReqAndRespInf reqAndRespInf; + + public ReqAndRespInf getReqAndRespInf() { + if (this.reqAndRespInf == null) + this.reqAndRespInf = ReqAndRespInf.builder().build(); + return this.reqAndRespInf; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/ReqAndRespInf.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/ReqAndRespInf.java new file mode 100644 index 0000000..2f2f741 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/model/ReqAndRespInf.java @@ -0,0 +1,26 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.model; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +import java.util.HashMap; +import java.util.Map; + +@Getter +@Setter +@EqualsAndHashCode +@Builder +public class ReqAndRespInf { + private String url; + private String reqData; + private String respRawData; + private Map etc; + + public Map getEtc() { + if (this.etc == null) + this.etc = new HashMap<>(); + return this.etc; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/template/PayHelper.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/template/PayHelper.java new file mode 100644 index 0000000..48ca01b --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/process/template/PayHelper.java @@ -0,0 +1,56 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.template; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.Pay; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.PayHelperService; +import lombok.Builder; + +public class PayHelper implements Pay { + + private final PARAM param; + private final PayHelperService payHelperService; + private D data; + private RSLT result; + private EnsException e; + + @Builder + PayHelper(PARAM param, PayHelperService payHelperService) { + this.param = param; + this.payHelperService = payHelperService; + } + + @Override + public void exec() { + try { + + this.data = payHelperService.getData(param); + + payHelperService.validate(param, data); + + payHelperService.callApi(param, data); + + this.result = payHelperService.generateResult(param, data, null); + + } catch (EnsException e) { + this.e = e; + this.result = payHelperService.generateResult(param, data, this.e); + } catch (Exception e) { + this.e = new EnsException(EnsErrCd.ERR999, "정의되지 않은 오류 입니다", e); + this.result = payHelperService.generateResult(param, data, this.e); + } finally { + payHelperService.saveHist(param, data, e); + } + + } + + @Override + public RSLT getResult() { + return this.result; + } + + @Override + public EnsException getException() { + return this.e; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/PayRepairServiceFactory.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/PayRepairServiceFactory.java new file mode 100644 index 0000000..f9cefe1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/PayRepairServiceFactory.java @@ -0,0 +1,28 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.RepairPayResultService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@RequiredArgsConstructor +public class PayRepairServiceFactory { + private final Map repairPayResultServiceMap; + + public enum PRepairPaySe { + kko, + nv, + } + + public RepairPayResultService getService(PRepairPaySe PTriggerPaySe) { + String beanName = PTriggerPaySe.name() + "PayRepairService"; + if (repairPayResultServiceMap.containsKey(beanName)) + return repairPayResultServiceMap.get(beanName); + else + throw new EnsException(EnsErrCd.NOT_FOUND_BEAN, EnsErrCd.NOT_FOUND_BEAN.getCodeNm()); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/RepairPayResultService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/RepairPayResultService.java new file mode 100644 index 0000000..8ff01e7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/RepairPayResultService.java @@ -0,0 +1,23 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair; + +import java.util.Map; + +public interface RepairPayResultService

{ + + /** + * 전송 실패한 납부(결제)결과 데이터 목록 조회 + * + * @param p + * @return + */ + Map> findTransferFailedPayResultDataList(P p); + + /** + * 전송 실패한 납부(결제)결과 데이터 목록 전송 + * + * @param p + * @return + */ + Map> sendTransferFailedPayResultDataList(P p); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/kit/RepairPayResultTransferFail.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/kit/RepairPayResultTransferFail.java new file mode 100644 index 0000000..ce6291f --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/kit/RepairPayResultTransferFail.java @@ -0,0 +1,176 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.kit; + +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.api.PayUseSysApi; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.model.PayResultTransferFailData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.model.PayResultTransferProcessVO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.model.RepairPayRsltFwdFailSearchDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.dsl.CaseBuilder; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.QBillHist.billHist; +import static cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng.orgMng; + + +public abstract class RepairPayResultTransferFail { + + protected JPAQueryFactory query; + protected RepairPayRsltFwdFailSearchDTO searchDTO; + private List transferFailDatas = null; + private Gson gson = new Gson(); + + + /** + * 납부(결제)결과 전달에 실패한 청구서 목록 조회 + * + * @return + */ + public List findDatas() { + + BooleanBuilder builder = new BooleanBuilder(); + builder.and(billHist.reqSe.in(Arrays.asList(BillReqSeCd.US_PAYRSLT, BillReqSeCd.PAYRSLT))); + builder.and(billHist.billSe.eq(getBillSeCd())); + if (!CmmnUtil.isEmpty(searchDTO.getSchOrgCd())) + builder.and(billHist.orgMng.orgCd.in(searchDTO.getSchOrgCd())); + if (!CmmnUtil.isEmpty(searchDTO.getSchOrgNm())) + builder.and(billHist.orgMng.orgNm.in(searchDTO.getSchOrgNm())); + if (!CmmnUtil.isEmpty(searchDTO.getSchBillUid())) + builder.and(billHist.billUid.in(searchDTO.getSchBillUid())); + + + + List list = query + .select(billHist.linkedUuid + , billHist.linkedUuid.count().longValue().as("totCnt") + , new CaseBuilder().when(billHist.error.errorCode.isNotNull() + .and((billHist.error.errorMessage.contains("REQUEST_TIMEOUT I/O error on") + .or(billHist.error.errorMessage.contains("404 NOT_FOUND")) + .or(billHist.error.errorCode.eq(PayUseSysResCd.FAILED_SAVE_PAYRSLT.getCode())) + )) + ) + .then(1) + .otherwise(0) + .sum().longValue().as("failCnt") + , billHist.orgMng.orgCd + , billHist.orgMng.orgNm + , billHist.billSe + , billHist.id.max().as(billHist.id) + ) + .from(billHist) + .innerJoin(billHist.orgMng, orgMng) + .where(builder) + .groupBy(billHist.orgMng, orgMng.orgNm, billHist.linkedUuid, billHist.billSe) + .fetch() + .stream() + .filter(tuple -> tuple.get(1, Long.class) == tuple.get(2, Long.class)) + .map(tuple -> + PayResultTransferFailData.builder() + .orgCd(tuple.get(billHist.orgMng.orgCd)) + .orgNm(tuple.get(billHist.orgMng.orgNm)) + .billSe(tuple.get(billHist.billSe)) + .billerUserKey(tuple.get(billHist.linkedUuid)) + .id(tuple.get(billHist.id)) + .build() + ) + .collect(Collectors.toList()); + + this.transferFailDatas = list; + return list; + } + + public List transferData(PayUseSysApi api, BillHistRepository billHistRepository) { + if (this.transferFailDatas == null) + this.findDatas(); + + List billHistList = this.transferFailDatas.stream() + .map(data -> PayResultTransferProcessVO + .builder() + .data(data) + .build() + ) + .map(vo -> { + vo.setReqBillHist(query.selectFrom(billHist) + .where(billHist.id.eq(vo.getData().getId())) + .fetchOne()); + return vo; + }) + .filter(vo -> !CmmnUtil.isEmpty(vo.getReqBillHist())) + .map(vo -> { + final String apiUrl = getPayResultApiUrl(vo.getReqBillHist().getOrgMng()); + ResponseEntity response = api.payResult(apiUrl, gson.fromJson(vo.getReqBillHist().getRequestData(), Map.class), null); + vo.setResponse(response); + return vo; + }) + .map(vo -> { + ResponseEntity response = vo.getResponse(); + + if (!HttpStatus.OK.equals(response.getStatusCode())) { + vo.setError(FieldError.initBuilder() + .errorCode(EnsErrCd.API_COMM_ERROR.getCode()) + .errorMessage(EnsErrCd.API_COMM_ERROR.getCodeNm() + " " + response.getStatusCode().toString()) + .build()); + return vo; + } + + PayApiRespDTO> result = null; + try { + result = gson.fromJson(response.getBody(), PayApiRespDTO.class); + } catch (Exception ex) { + vo.setError(FieldError.initBuilder() + .errorCode(EnsErrCd.INVALID_RESPONSE.getCode()) + .errorMessage(EnsErrCd.INVALID_RESPONSE.getCodeNm() + " " + ex.getMessage()) + .build()); + return vo; + } + + try { + PayUseSysResCd.valueOf(result.getResCode()); + } catch (Exception ex) { + vo.setError(FieldError.initBuilder() + .errorCode(EnsErrCd.INVALID_RES_CODE.getCode()) + .errorMessage(EnsErrCd.INVALID_RES_CODE.getCodeNm() + " " + ex.getMessage()) + .build()); + return vo; + } + return vo; + }) + .map(vo -> BillHist.builder() + .billUid(vo.getReqBillHist().getBillUid()) + .billSe(vo.getReqBillHist().getBillSe()) + .reqSe(BillReqSeCd.US_PAYRSLT) + .orgMng(vo.getReqBillHist().getOrgMng()) + .linkedUuid(vo.getReqBillHist().getLinkedUuid()) + .requestData(vo.getReqBillHist().getRequestData()) + .responseData(vo.getResponse().getBody()) + .error(vo.getError()) + .build()) + .collect(Collectors.toList()); + + billHistRepository.saveAll(billHistList); + return billHistList; + } + + + abstract protected String getPayResultApiUrl(OrgMng orgMng); + + abstract protected BillSeCd getBillSeCd(); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/model/PayResultTransferFailData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/model/PayResultTransferFailData.java new file mode 100644 index 0000000..5ed34e5 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/model/PayResultTransferFailData.java @@ -0,0 +1,43 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "RepairPayRsltFwdFailRespData") +public class PayResultTransferFailData { + + @Schema(title = "기관코드", example = " ") + @JsonProperty("orgCd") + @JsonAlias({"org_cd"}) + @SerializedName(value = "orgCd", alternate = {"org_cd"}) + private String orgCd; + @Schema(title = "기관코드명", example = " ") + @JsonProperty("orgNm") + @JsonAlias({"org_nm"}) + @SerializedName(value = "orgNm", alternate = {"org_nm"}) + private String orgNm; + @Schema(title = "빌러유저키", example = " ") + @JsonProperty("billSe") + @JsonAlias({"bill_se"}) + @SerializedName(value = "billSe", alternate = {"bill_se"}) + private BillSeCd billSe; + @Schema(title = "빌러유저키", example = " ") + @JsonProperty("billerUserKey") + @JsonAlias({"biller_user_key"}) + @SerializedName(value = "billerUserKey", alternate = {"biller_user_key"}) + private String billerUserKey; + @Schema(title = "청구서이력식별키(PK)") + private Long id; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/model/PayResultTransferProcessVO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/model/PayResultTransferProcessVO.java new file mode 100644 index 0000000..8e8bf32 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/model/PayResultTransferProcessVO.java @@ -0,0 +1,23 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.http.ResponseEntity; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "PayResultTransferVO") +public class PayResultTransferProcessVO { + + private PayResultTransferFailData data; + private BillHist reqBillHist; + private ResponseEntity response; + private FieldError error; +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/model/RepairPayRsltFwdFailSearchDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/model/RepairPayRsltFwdFailSearchDTO.java new file mode 100644 index 0000000..ee21e3e --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/repair/model/RepairPayRsltFwdFailSearchDTO.java @@ -0,0 +1,34 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.repair.model; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@SuperBuilder +@Data +@NoArgsConstructor +@Schema(name = "RepairPayRsltFwdFailSearchDTO") +public class RepairPayRsltFwdFailSearchDTO { + + @Schema(title = "기관코드", example = "[]") + @JsonProperty("schOrgCd") + @JsonAlias({"sch_org_cd"}) + @SerializedName(value = "schOrgCd", alternate = {"sch_org_cd"}) + protected List schOrgCd; + @Schema(title = "기관코드명", example = "[]") + @JsonProperty("schOrgNm") + @JsonAlias({"sch_org_nm"}) + @SerializedName(value = "schOrgNm", alternate = {"sch_org_nm"}) + protected List schOrgNm; + @Schema(title = "청구서UID", example = "[]") + @JsonProperty("schBillUid") + @JsonAlias({"sch_bill_uid"}) + @SerializedName(value = "schBillUid", alternate = {"sch_bill_uid"}) + protected List schBillUid; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/trigger/PaymentTriggerService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/trigger/PaymentTriggerService.java new file mode 100644 index 0000000..20096c6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/trigger/PaymentTriggerService.java @@ -0,0 +1,23 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.trigger; + +import java.util.Map; + +/** + * 결제 이벤트 시점 트리거 서비스 + */ +public interface PaymentTriggerService { + + enum PTriggerDataKeys { + bill, + billUid, + } + + /** + * 결제정보 + * + * @param p + * @return + */ + Map payInfo(Map p); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/trigger/PaymentTriggerServiceFactory.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/trigger/PaymentTriggerServiceFactory.java new file mode 100644 index 0000000..febaa51 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/trigger/PaymentTriggerServiceFactory.java @@ -0,0 +1,28 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.trigger; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.trigger.PaymentTriggerService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@RequiredArgsConstructor +public class PaymentTriggerServiceFactory { + private final Map paymentTriggerServiceMap; + + public enum PTriggerPaySe { + kko, + nv, + } + + public PaymentTriggerService getService(PTriggerPaySe PTriggerPaySe) { + String beanName = PTriggerPaySe.name() + "PaymentTriggerService"; + if (paymentTriggerServiceMap.containsKey(beanName)) + return paymentTriggerServiceMap.get(beanName); + else + throw new EnsException(EnsErrCd.NOT_FOUND_BEAN, EnsErrCd.NOT_FOUND_BEAN.getCodeNm()); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/trigger/PaymentTriggerServiceTemplate.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/trigger/PaymentTriggerServiceTemplate.java new file mode 100644 index 0000000..b303297 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/support/service/trigger/PaymentTriggerServiceTemplate.java @@ -0,0 +1,48 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.trigger; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; + +import java.util.Map; + +/** + * 결제 이벤트 시점 트리거 서비스 템플릿 + */ +public abstract class PaymentTriggerServiceTemplate implements PaymentTriggerService { + + /** + * 결제정보 + * + * @param param + * @return + */ + @Override + public Map payInfo(Map param) { + if (!existsBill((String) param.get(PTriggerDataKeys.billUid))) + generateBill((Bill) param.get(PTriggerDataKeys.bill)); + return getPayInfo(param); + } + + /** + * 청구서데이터 유무 확인 + * + * @param billUid 청구서UID + * @return + */ + abstract protected boolean existsBill(String billUid); + + /** + * 청구서데이터 생성 + * + * @param bill + */ + abstract protected void generateBill(Bill bill); + + /** + * 청구서 납부(결제)정보 가져오기 + * + * @param param + * @return + */ + abstract protected Map getPayInfo(Map param); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/code/TryStatCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/code/TryStatCd.java new file mode 100644 index 0000000..1b6c305 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/code/TryStatCd.java @@ -0,0 +1,33 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.code; + +import cokr.xit.ens.core.code.CodeMapperType; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum TryStatCd implements CodeMapperType { + +// acpt("접수") + stby("전송대기") + +// , sndRdy("전송준비") + , start("전송시작") + + , sndRsrv("예약전송") + , sndRtme("실시간전송") + + , ok("성공") + , fail("실패") + + , cmplt("전회차완료") + ; + + @Getter + private final String codeNm; + + @Override + public String getCode() { + return this.name(); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/IntgrnSendDetail.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/IntgrnSendDetail.java new file mode 100644 index 0000000..3c34e76 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/IntgrnSendDetail.java @@ -0,0 +1,159 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain; + +import cokr.xit.ens.modules.common.code.IntgrnDtlStatCd; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.domain.BaseEntity; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.persistence.*; + +@Entity +//@Data +@Getter +@ToString +@SuperBuilder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_intgrn_snd_dtl", schema = "", catalog = "", indexes = { + @Index(name = "idx_intgrn_linked_uuid", columnList = "linked_uuid"), +// @Index(name = "idx_intgrn_bill_uid", columnList = "mk_bill_uid"), +}) +public class IntgrnSendDetail extends BaseEntity { + + @Id +// @GeneratedValue(strategy=GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.TABLE, generator = "IntgrnSendDetail_Generator") + @TableGenerator(table = "ens_seq_generator", name = "IntgrnSendDetail_Generator" + , pkColumnName = "seq_name", pkColumnValue = "IntgrnSendDetail_id" + , initialValue = 0, allocationSize = 50) + + private Long intSendDetailId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "int_send_mast_id") + private IntgrnSendMast intgrnSendMast; + + + @Column(name = "linked_uuid", length = 40) + @Setter + private String linkedUuid; + + + @Column(name = "ci", nullable = true) + private String ci; + + + @Column(name = "jid", nullable = true, length = 24) + private String jid; + + + @Column(name = "mblphonNo", nullable = true) + private String mblphonNo; + + +// @Column(name = "json_kko_bill_link_info", nullable = true) +// @Lob +// private String jKkoBillLinkInfo; + + + @Column(name = "json_tmplt_msg_data", nullable = true) + @Lob + private String jTmpltMsgData; + + + @Column(name = "json_mbl_page_data", nullable = true) + @Lob + private String jMblPageData; + + + @Column(name = "j_acpt_doc_kko_at", nullable = true) + @Lob + private String jAcptDocKkoAt; + @Column(name = "j_acpt_doc_kko_md", nullable = true) + @Lob + private String jAcptDocKkoMd; + @Column(name = "j_acpt_doc_nv_st", nullable = true) + @Lob + private String jAcptDocNvSt; + @Column(name = "j_acpt_doc_kt_st", nullable = true) + @Lob + private String jAcptDocKtSt; + @Column(name = "j_acpt_doc_kt_gbs", nullable = true) + @Lob + private String jAcptDocKtGbs; + + @Setter + @Column(name = "cur_post_se", nullable = true) + @Enumerated(EnumType.STRING) + private PostSeCd curPostSe; + @Setter + @Column(name = "send_detail_id_kko_at", nullable = true) + private Long sendDetailIdKkoAt; + @Setter + @Column(name = "send_detail_id_kko_md", nullable = true) + private Long sendDetailIdKkoMd; + @Setter + @Column(name = "send_detail_id_nv_st", nullable = true) + private Long sendDetailIdNvSt; + @Setter + @Column(name = "send_detail_id_kt_st", nullable = true) + private Long sendDetailIdKtSt; + @Setter + @Column(name = "send_detail_id_kt_gbs", nullable = true) + private Long sendDetailIdKtGbs; + + + + @Setter + @Enumerated(EnumType.STRING) + @Column(name = "cur_stat_cd", nullable = false) + private IntgrnDtlStatCd curStatCd; + + @Column(name = "doc_sent_dt", nullable = true, length = 14) + @Setter + private String docSentDt; + + @Column(name = "doc_received_dt", nullable = true, length = 14) + @Setter + private String docReceivedDt; + + @Column(name = "doc_auth_frst_dt", nullable = true, length = 14) + @Setter + private String docAuthFrstDt; + + @Column(name = "doc_token_vrfy_frst_dt", nullable = true, length = 14) + @Setter + private String docTokenVrfyFrstDt; + + @Column(name = "doc_read_frst_dt", nullable = true, length = 14) + @Setter + private String docReadFrstDt; + + @Column(name = "doc_user_notied_dt", nullable = true, length = 14) + @Setter + private String docUserNotiedDt; + + + + @Column(name = "mk_bill_use_yn", nullable = true, length = 1) + private String mkBillUseYn; + +// @Column(name = "mk_bill_uid", nullable = true, length = 45) +// private String mkBillUid; + + @JoinColumn(name = "bill_uid", referencedColumnName = "bill_uid") + @OneToOne(fetch = FetchType.LAZY) + private Bill bill; + + + @Embedded + @Setter + private FieldError error; + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/IntgrnSendMast.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/IntgrnSendMast.java new file mode 100644 index 0000000..f4eeb89 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/IntgrnSendMast.java @@ -0,0 +1,57 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain; + +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.domain.SendMastBaseEntity; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.code.TryStatCd; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.persistence.*; + +@Entity +//@Data +@Getter @ToString +@SuperBuilder +@EqualsAndHashCode(callSuper = false) +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_intgrn_snd_mast", schema = "", catalog = "") +public class IntgrnSendMast extends SendMastBaseEntity { +//public class IntgrnSendMast { + + @Id +// @GeneratedValue(strategy=GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.TABLE, generator = "IntgrnSendMast_Generator") + @TableGenerator(table = "ens_seq_generator", name = "IntgrnSendMast_Generator" + ,pkColumnName = "seq_name", pkColumnValue = "IntgrnSendMast_id" + ,initialValue = 0, allocationSize = 50) + + private Long intSendMastId; + + @Column(name = "try1", nullable = false) + + @Enumerated(EnumType.STRING) + private PostSeCd try1; + @Column(name = "try2", nullable = true) + + @Enumerated(EnumType.STRING) + private PostSeCd try2; + @Column(name = "try3", nullable = true) + + @Enumerated(EnumType.STRING) + private PostSeCd try3; + @Column(name = "try_cnt", nullable = false) + + private Integer tryCnt; + @Setter + @Column(name = "try_seq", nullable = false) + + private Integer trySeq; + @Setter + @Enumerated(EnumType.STRING) + @Column(name = "try_stat_cd", nullable = false) + + private TryStatCd tryStatCd; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/TmpltMngIntgrn.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/TmpltMngIntgrn.java new file mode 100644 index 0000000..d0ad58a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/TmpltMngIntgrn.java @@ -0,0 +1,36 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain; + +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.TmpltMng; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.persistence.*; + +@Entity +@Getter +@ToString +@SuperBuilder +@EqualsAndHashCode +@NoArgsConstructor +@Table(name = "ens_tmplt_mng_intgrn", schema = "", catalog = "") +@DiscriminatorValue("intgrn") +public class TmpltMngIntgrn extends TmpltMng { + @Setter + @Enumerated(EnumType.STRING) + + @Column(name = "try1", nullable = false) + private PostSeCd try1; + + @Enumerated(EnumType.STRING) + + @Column(name = "try2", nullable = true) + private PostSeCd try2; + + @Enumerated(EnumType.STRING) + + @Column(name = "try3", nullable = true) + private PostSeCd try3; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendDetailRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendDetailRepository.java new file mode 100644 index 0000000..51ac691 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendDetailRepository.java @@ -0,0 +1,16 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Optional; + +public interface IntgrnSendDetailRepository extends JpaRepository, IntgrnSendDetailRepositoryCustom { + + List findAllByIntgrnSendMast(IntgrnSendMast intgrnSendMast); + + Optional findByLinkedUuid(String linkedUuid); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendDetailRepositoryCustom.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendDetailRepositoryCustom.java new file mode 100644 index 0000000..a3ecf7a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendDetailRepositoryCustom.java @@ -0,0 +1,33 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.code.TryStatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnDetailStatVO; +import cokr.xit.ens.modules.common.biztmplt.SendDetailRepositorySupport; + +import java.util.List; +import java.util.Optional; + +public interface IntgrnSendDetailRepositoryCustom extends SendDetailRepositorySupport { + + List findAllBySendTargetAndSendMast(IntgrnSendMast intgrnSendMast); + List findAllBySendTargetAndSendMastAndTryStatCdIn(IntgrnSendMast intgrnSendMast, List tryStatCds); + + + void modifyDetailStatCdByIntgrnDetailStatVO(List list); + + List findIntgrnDetailStatVOsByIntSendMastIdAndCurPostSe(Long intSendMastId); + + List findIntgrnDetailStatVOsByIntSendMastId(Long intSendMastId); + + List findIntSendMastIdsBySendTarget(); + + + + Optional findByDocUuidAndLinkedUuid(String docUuid, String linkedUuid); + PostSeCd findPostSeByDocUuidAndLinkedUuid(String docUuid, String linkedUuid); + + Optional findIntSendMastIdBySendMastId(Long sendMastId); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendDetailRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendDetailRepositoryImpl.java new file mode 100644 index 0000000..dd28d84 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendDetailRepositoryImpl.java @@ -0,0 +1,414 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.code.IntgrnDtlStatCd; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.code.TryStatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.QIntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnDetailStatVO; +import cokr.xit.ens.modules.common.domain.SendMast; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.time.LocalDateTime; +import java.util.*; + +import static cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.QIntgrnSendDetail.intgrnSendDetail; +import static cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.QIntgrnSendMast.intgrnSendMast; +import static cokr.xit.ens.modules.common.domain.QSendMast.sendMast; +import static cokr.xit.ens.modules.kkoalimtalk.domain.QSendDetailKkoAlimtalk.sendDetailKkoAlimtalk; +import static cokr.xit.ens.modules.kkomydoc.domain.QSendDetailKkoMydoc.sendDetailKkoMydoc; +import static cokr.xit.ens.modules.ktsigntalk.direct.domain.QSendDetailKtSigntalk.sendDetailKtSigntalk; +import static cokr.xit.ens.modules.ktsigntalk.gibis.domain.QSendDetailKtGibis.sendDetailKtGibis; +import static cokr.xit.ens.modules.nvsigntalk.domain.QSendDetailNvSigntalk.sendDetailNvSigntalk; + +@RequiredArgsConstructor +public class IntgrnSendDetailRepositoryImpl implements IntgrnSendDetailRepositoryCustom { + + private final JPAQueryFactory query; + + @Override + public List findAllBySendTargetAndSendMast(IntgrnSendMast intgrnSendMast) { + return findAllBySendTargetAndSendMastAndTryStatCdIn(intgrnSendMast, null); + } + + @Override + public List findAllBySendTargetAndSendMastAndTryStatCdIn(IntgrnSendMast intgrnSendMast, List tryStatCds) { + return query.selectFrom(intgrnSendDetail) + .innerJoin(intgrnSendDetail.intgrnSendMast, QIntgrnSendMast.intgrnSendMast) + .where(isSendTarget(tryStatCds) + .and(intgrnSendDetail.intgrnSendMast.eq(intgrnSendMast)) + ) + .fetch(); + } + + @Override + public void modifyDetailStatCdByIntgrnDetailStatVO(List list) { + list.forEach(data -> + + query.update(intgrnSendDetail) + .set(intgrnSendDetail.curStatCd, IntgrnDtlStatCd.ACPT_CMPLT.equals(data.getCurStatCd().getIntgrnDtlStatCd()) ? (CmmnUtil.isEmpty(data.getMastErrorCode()) ? data.getCurStatCd().getIntgrnDtlStatCd() : IntgrnDtlStatCd.FAIL) : data.getCurStatCd().getIntgrnDtlStatCd()) + .set(intgrnSendDetail.docSentDt, data.getDocSentDt()) + .set(intgrnSendDetail.docReceivedDt, data.getDocReceivedDt()) + .set(intgrnSendDetail.docAuthFrstDt, data.getDocAuthFrstDt()) + .set(intgrnSendDetail.docTokenVrfyFrstDt, data.getDocTokenVrfyFrstDt()) + .set(intgrnSendDetail.docReadFrstDt, data.getDocReadFrstDt()) + .set(intgrnSendDetail.docUserNotiedDt, data.getDocUserNotiedDt()) + .set(intgrnSendDetail.error.errorCode, data.getMastErrorCode() == null && data.getErrorCode() == null ? null : String.format("[M]%s. [D]%s", data.getMastErrorCode(), data.getErrorCode())) + .set(intgrnSendDetail.error.errorMessage, data.getMastErrorCode() == null && data.getErrorCode() == null ? null : String.format("[M]%s. [D]%s", data.getMastErrorMessage(), data.getErrorMessage())) + .where(intgrnSendDetail.intSendDetailId.eq(data.getIntSendDetailId())) + .execute() + ); + } + + @Override + public List findIntgrnDetailStatVOsByIntSendMastIdAndCurPostSe(Long intSendMastId) { + List list = new ArrayList<>(); + + + list.addAll(query.select(Projections.fields(IntgrnDetailStatVO.class + , intgrnSendDetail.intSendDetailId + , intgrnSendDetail.linkedUuid + , intgrnSendDetail.curPostSe + , sendDetailKkoAlimtalk.kkoResultCd.as("curStatCd") + , sendDetailKkoAlimtalk.kkoRequestDt.as("docSentDt") + , sendDetailKkoAlimtalk.kkoReceivedDt.as("docReceivedDt") +// , isNull().as("docAuthFrstDt") +// , isNull().as("docTokenVrfyFrstDt") +// , isNull().as("docReadFrstDt") +// , isNull().as("docUserNotiedDt") + , sendDetailKkoAlimtalk.error.errorCode + , sendDetailKkoAlimtalk.error.errorMessage + , sendMast.error.errorCode.as("mastErrorCode") + , sendMast.error.errorMessage.as("mastErrorMessage") + )) + .from(intgrnSendDetail) + .innerJoin(sendDetailKkoAlimtalk).on(sendDetailKkoAlimtalk.sendDetailId.eq(intgrnSendDetail.sendDetailIdKkoAt)) + .innerJoin(sendDetailKkoAlimtalk.sendMast, sendMast) + .where( + intgrnSendDetail.curPostSe.eq(PostSeCd.kkoAlimtalk) + .and(intgrnSendDetail.intgrnSendMast.intSendMastId.eq(intSendMastId)) + ) + .fetch()); + + list.addAll(query.select(Projections.fields(IntgrnDetailStatVO.class + , intgrnSendDetail.intSendDetailId + , intgrnSendDetail.linkedUuid + , intgrnSendDetail.curPostSe + , sendDetailKkoMydoc.kkoDocStat.as("curStatCd") + , sendDetailKkoMydoc.kkoDocSentDt.as("docSentDt") + , sendDetailKkoMydoc.kkoDocReceivedDt.as("docReceivedDt") + , sendDetailKkoMydoc.kkoDocAuthFrstDt.as("docAuthFrstDt") + , sendDetailKkoMydoc.kkoDocTokenVrfyFrstDt.as("docTokenVrfyFrstDt") + , sendDetailKkoMydoc.kkoDocReadFrstDt.as("docReadFrstDt") + , sendDetailKkoMydoc.kkoDocUserNotiedDt.as("docUserNotiedDt") + , sendDetailKkoMydoc.error.errorCode + , sendDetailKkoMydoc.error.errorMessage + , sendMast.error.errorCode.as("mastErrorCode") + , sendMast.error.errorMessage.as("mastErrorMessage") + )) + .from(intgrnSendDetail) + .innerJoin(sendDetailKkoMydoc).on(sendDetailKkoMydoc.sendDetailId.eq(intgrnSendDetail.sendDetailIdKkoMd)) + .innerJoin(sendDetailKkoMydoc.sendMast, sendMast) + .where( + intgrnSendDetail.curPostSe.eq(PostSeCd.kkoMydoc) + .and(intgrnSendDetail.intgrnSendMast.intSendMastId.eq(intSendMastId)) + ) + .fetch()); + + list.addAll(query.select(Projections.fields(IntgrnDetailStatVO.class + , intgrnSendDetail.intSendDetailId + , intgrnSendDetail.linkedUuid + , intgrnSendDetail.curPostSe + , sendDetailNvSigntalk.nvDocStat.as("curStatCd") + , sendDetailNvSigntalk.nvDocSentDt.as("docSentDt") + , sendDetailNvSigntalk.nvDocReceivedDt.as("docReceivedDt") + , sendDetailNvSigntalk.nvDocAuthFrstDt.as("docAuthFrstDt") + , sendDetailNvSigntalk.nvDocTokenVrfyFrstDt.as("docTokenVrfyFrstDt") + , sendDetailNvSigntalk.nvDocReadFrstDt.as("docReadFrstDt") +// , sendDetailNvSigntalk.nvdocnoti.as("docUserNotiedDt") + , sendDetailNvSigntalk.error.errorCode + , sendDetailNvSigntalk.error.errorMessage + , sendMast.error.errorCode.as("mastErrorCode") + , sendMast.error.errorMessage.as("mastErrorMessage") + )) + .from(intgrnSendDetail) + .innerJoin(sendDetailNvSigntalk).on(sendDetailNvSigntalk.sendDetailId.eq(intgrnSendDetail.sendDetailIdNvSt)) + .innerJoin(sendDetailNvSigntalk.sendMast, sendMast) + .where( + intgrnSendDetail.curPostSe.eq(PostSeCd.nvSigntalk) + .and(intgrnSendDetail.intgrnSendMast.intSendMastId.eq(intSendMastId)) + ) + .fetch()); + + list.addAll(query.select(Projections.fields(IntgrnDetailStatVO.class + , intgrnSendDetail.intSendDetailId + , intgrnSendDetail.linkedUuid + , intgrnSendDetail.curPostSe + , sendDetailKtSigntalk.docStat.as("curStatCd") + , sendDetailKtSigntalk.docSentDt.as("docSentDt") + , sendDetailKtSigntalk.docReceivedDt.as("docReceivedDt") + , sendDetailKtSigntalk.docAuthFrstDt.as("docAuthFrstDt") + , sendDetailKtSigntalk.docTokenVrfyFrstDt.as("docTokenVrfyFrstDt") + , sendDetailKtSigntalk.docReadFrstDt.as("docReadFrstDt") +// , sendDetailKtSigntalk.nvdocnoti.as("docUserNotiedDt") + , sendDetailKtSigntalk.error.errorCode + , sendDetailKtSigntalk.error.errorMessage + , sendMast.error.errorCode.as("mastErrorCode") + , sendMast.error.errorMessage.as("mastErrorMessage") + )) + .from(intgrnSendDetail) + .innerJoin(sendDetailKtSigntalk).on(sendDetailKtSigntalk.sendDetailId.eq(intgrnSendDetail.sendDetailIdKtSt)) + .innerJoin(sendDetailKtSigntalk.sendMast, sendMast) + .where( + intgrnSendDetail.curPostSe.eq(PostSeCd.ktSigntalk) + .and(intgrnSendDetail.intgrnSendMast.intSendMastId.eq(intSendMastId)) + ) + .fetch()); + + list.addAll(query.select(Projections.fields(IntgrnDetailStatVO.class + , intgrnSendDetail.intSendDetailId + , intgrnSendDetail.linkedUuid + , intgrnSendDetail.curPostSe + , sendDetailKtGibis.docStat.as("curStatCd") + , sendDetailKtGibis.docSentDt.as("docSentDt") + , sendDetailKtGibis.docReceivedDt.as("docReceivedDt") + , sendDetailKtGibis.docAuthFrstDt.as("docAuthFrstDt") + , sendDetailKtGibis.docTokenVrfyFrstDt.as("docTokenVrfyFrstDt") + , sendDetailKtGibis.docReadFrstDt.as("docReadFrstDt") +// , sendDetailKtGibis.nvdocnoti.as("docUserNotiedDt") + , sendDetailKtGibis.error.errorCode + , sendDetailKtGibis.error.errorMessage + , sendMast.error.errorCode.as("mastErrorCode") + , sendMast.error.errorMessage.as("mastErrorMessage") + )) + .from(intgrnSendDetail) + .innerJoin(sendDetailKtGibis).on(sendDetailKtGibis.sendDetailId.eq(intgrnSendDetail.sendDetailIdKtGbs)) + .innerJoin(sendDetailKtGibis.sendMast, sendMast) + .where( + intgrnSendDetail.curPostSe.eq(PostSeCd.ktGibis) + .and(intgrnSendDetail.intgrnSendMast.intSendMastId.eq(intSendMastId)) + ) + .fetch()); + + return list; + } + + @Override + public List findIntgrnDetailStatVOsByIntSendMastId(Long intSendMastId) { + return query.select(Projections.fields(IntgrnDetailStatVO.class + , intgrnSendDetail.intSendDetailId + , intgrnSendDetail.linkedUuid + , intgrnSendDetail.curPostSe + , intgrnSendDetail.curStatCd + , intgrnSendDetail.docSentDt + , intgrnSendDetail.docReceivedDt + , intgrnSendDetail.docAuthFrstDt + , intgrnSendDetail.docTokenVrfyFrstDt + , intgrnSendDetail.docReadFrstDt + , intgrnSendDetail.docUserNotiedDt + , intgrnSendDetail.error.errorCode + , intgrnSendDetail.error.errorMessage + )) + .from(intgrnSendDetail) + .where(intgrnSendDetail.intgrnSendMast.intSendMastId.eq(intSendMastId)) + .fetch(); + } + + + @Override + public List findIntSendMastIdsBySendTarget() { + + return query.select(intgrnSendMast.intSendMastId) + .from(intgrnSendDetail) + .innerJoin(intgrnSendDetail.intgrnSendMast, intgrnSendMast) + .where(isSendTarget(null)) + .groupBy(intgrnSendMast.intSendMastId) + .fetch(); + } + + @Override + public Optional findByDocUuidAndLinkedUuid(String docUuid, String linkedUuid) { + List intSendDetailIds = new ArrayList<>(); + intSendDetailIds.addAll(findIntSendDetailIdsByKkoMydoc(docUuid, linkedUuid)); + intSendDetailIds.addAll(findIntSendDetailIdsByNvSigntalk(docUuid, linkedUuid)); + intSendDetailIds.addAll(findIntSendDetailIdsByKtSigntalk(docUuid, linkedUuid)); + intSendDetailIds.addAll(findIntSendDetailIdsByKtGibis(docUuid, linkedUuid)); + return Optional.ofNullable(query.selectFrom(intgrnSendDetail) + .where(intgrnSendDetail.intSendDetailId.in(intSendDetailIds)) + .fetchOne()); + } + + @Override + public PostSeCd findPostSeByDocUuidAndLinkedUuid(String docUuid, String linkedUuid) { + if (findIntSendDetailIdsByKkoMydoc(docUuid, linkedUuid).size() > 0) return PostSeCd.kkoMydoc; + if (findIntSendDetailIdsByNvSigntalk(docUuid, linkedUuid).size() > 0) return PostSeCd.nvSigntalk; + if (findIntSendDetailIdsByKtSigntalk(docUuid, linkedUuid).size() > 0) return PostSeCd.ktSigntalk; + if (findIntSendDetailIdsByKtGibis(docUuid, linkedUuid).size() > 0) return PostSeCd.ktGibis; + + return null; + } + + @Override + public Optional findIntSendMastIdBySendMastId(Long sendMastId) { + SendMast sendMastObj = query.selectFrom(sendMast).where(sendMast.sendMastId.eq(sendMastId)).fetchOne(); + + + if (PostSeCd.kkoMydoc.equals(sendMastObj.getPostSe())) + return Optional.ofNullable(query.select(intgrnSendDetail.intgrnSendMast.intSendMastId) + .from(intgrnSendDetail) + .innerJoin(sendDetailKkoMydoc).on(intgrnSendDetail.sendDetailIdKkoMd.eq(sendDetailKkoMydoc.sendDetailId)) + .where(sendDetailKkoMydoc.sendMast.sendMastId.eq(sendMastId)) + .groupBy(intgrnSendDetail.intgrnSendMast.intSendMastId) + .fetchOne()); + + if (PostSeCd.kkoAlimtalk.equals(sendMastObj.getPostSe())) + return Optional.ofNullable(query.select(intgrnSendDetail.intgrnSendMast.intSendMastId) + .from(intgrnSendDetail) + .innerJoin(sendDetailKkoAlimtalk).on(intgrnSendDetail.sendDetailIdKkoAt.eq(sendDetailKkoAlimtalk.sendDetailId)) + .where(sendDetailKkoAlimtalk.sendMast.sendMastId.eq(sendMastId)) + .groupBy(intgrnSendDetail.intgrnSendMast.intSendMastId) + .fetchOne()); + + if (PostSeCd.nvSigntalk.equals(sendMastObj.getPostSe())) + return Optional.ofNullable(query.select(intgrnSendDetail.intgrnSendMast.intSendMastId) + .from(intgrnSendDetail) + .innerJoin(sendDetailNvSigntalk).on(intgrnSendDetail.sendDetailIdNvSt.eq(sendDetailNvSigntalk.sendDetailId)) + .where(sendDetailNvSigntalk.sendMast.sendMastId.eq(sendMastId)) + .groupBy(intgrnSendDetail.intgrnSendMast.intSendMastId) + .fetchOne()); + + if (PostSeCd.ktSigntalk.equals(sendMastObj.getPostSe())) + return Optional.ofNullable(query.select(intgrnSendDetail.intgrnSendMast.intSendMastId) + .from(intgrnSendDetail) + .innerJoin(sendDetailKtSigntalk).on(intgrnSendDetail.sendDetailIdKtSt.eq(sendDetailKtSigntalk.sendDetailId)) + .where(sendDetailKtSigntalk.sendMast.sendMastId.eq(sendMastId)) + .groupBy(intgrnSendDetail.intgrnSendMast.intSendMastId) + .fetchOne()); + + if (PostSeCd.ktGibis.equals(sendMastObj.getPostSe())) + return Optional.ofNullable(query.select(intgrnSendDetail.intgrnSendMast.intSendMastId) + .from(intgrnSendDetail) + .innerJoin(sendDetailKtGibis).on(intgrnSendDetail.sendDetailIdKtGbs.eq(sendDetailKtGibis.sendDetailId)) + .where(sendDetailKtGibis.sendMast.sendMastId.eq(sendMastId)) + .groupBy(intgrnSendDetail.intgrnSendMast.intSendMastId) + .fetchOne()); + + return Optional.ofNullable(null); + } + + private List findIntSendDetailIdsByKkoMydoc(String docUuid, String linkedUuid) { + BooleanBuilder isMatched = new BooleanBuilder(); + isMatched.and(sendDetailKkoMydoc.documentBinderUuid.eq(docUuid)); + if (linkedUuid != null) + isMatched.and(intgrnSendDetail.linkedUuid.eq(linkedUuid)); + + return query.select(intgrnSendDetail.intSendDetailId) + .from(intgrnSendDetail) + .innerJoin(sendDetailKkoMydoc).on(intgrnSendDetail.sendDetailIdKkoMd.eq(sendDetailKkoMydoc.sendDetailId)) + .where(isMatched) + .fetch(); + } + + private List findIntSendDetailIdsByNvSigntalk(String docUuid, String linkedUuid) { + BooleanBuilder isMatched = new BooleanBuilder(); + isMatched.and(sendDetailNvSigntalk.docId.eq(docUuid)); + if (linkedUuid != null) + isMatched.and(intgrnSendDetail.linkedUuid.eq(linkedUuid)); + + return query.select(intgrnSendDetail.intSendDetailId) + .from(intgrnSendDetail) + .innerJoin(sendDetailNvSigntalk).on(intgrnSendDetail.sendDetailIdNvSt.eq(sendDetailNvSigntalk.sendDetailId)) + .where(isMatched) + .fetch(); + } + + private List findIntSendDetailIdsByKtSigntalk(String docUuid, String linkedUuid) { + BooleanBuilder isMatched = new BooleanBuilder(); + isMatched.and(sendDetailKtSigntalk.srcKey.eq(docUuid)); + if (linkedUuid != null) + isMatched.and(intgrnSendDetail.linkedUuid.eq(linkedUuid)); + + return query.select(intgrnSendDetail.intSendDetailId) + .from(intgrnSendDetail) + .innerJoin(sendDetailKtSigntalk).on(intgrnSendDetail.sendDetailIdKtSt.eq(sendDetailKtSigntalk.sendDetailId)) + .where(isMatched) + .fetch(); + } + + private List findIntSendDetailIdsByKtGibis(String docUuid, String linkedUuid) { + BooleanBuilder isMatched = new BooleanBuilder(); + isMatched.and(sendDetailKtGibis.srcKey.eq(docUuid)); + if (linkedUuid != null) + isMatched.and(intgrnSendDetail.linkedUuid.eq(linkedUuid)); + + return query.select(intgrnSendDetail.intSendDetailId) + .from(intgrnSendDetail) + .innerJoin(sendDetailKtGibis).on(intgrnSendDetail.sendDetailIdKtGbs.eq(sendDetailKtGibis.sendDetailId)) + .where(isMatched) + .fetch(); + } + + /** + * 전송 타깃 데이터 + * -.조건: statCd!='close' + * and ( + * (statCd='makeok' and tryStatCd='stby' and curStatCd='MAKING') + * or (tryStatCd in ('ok','fail) and trySeq tryStatCds) { + List try1StatCds = new ArrayList<>(Arrays.asList(TryStatCd.stby)); + List try2StatCds = new ArrayList<>(Arrays.asList(TryStatCd.ok, TryStatCd.fail)); + if (!CmmnUtil.isEmpty(tryStatCds)) { + tryStatCds.forEach(tryStatCd -> { + try1StatCds.add(tryStatCd); + try2StatCds.add(tryStatCd); + }); + } + + + BooleanBuilder builder = new BooleanBuilder(); + return builder.and(intgrnSendMast.statCd.ne(StatCd.close)) + .and(intgrnSendMast.trySeq.lt(intgrnSendMast.tryCnt)) + .and( + + (intgrnSendMast.statCd.eq(StatCd.makeok) + .and(intgrnSendMast.tryStatCd.in(try1StatCds)) + .and(intgrnSendDetail.curStatCd.eq(IntgrnDtlStatCd.MAKING)) + ) + + .or( + (intgrnSendMast.tryStatCd.in(try2StatCds) + .and(intgrnSendMast.sendDt.before(LocalDateTime.now())) + .and(intgrnSendDetail.curStatCd.in(IntgrnDtlStatCd.getFails())) + ) + ) + ); + + + } + +// +// @Override +// public List findAllFetchBySendMastIdAndMkBillUseYAndUrlIsNull(Long intSendMastId, boolean urlIsNull) { +// return query.selectFrom(intgrnSendDetail) +// .innerJoin(intgrnSendDetail.intgrnSendMast, intgrnSendMast) +// .fetchJoin() +// .leftJoin(intgrnSendDetail.kkoBillMast, kkoBillMast) +// .fetchJoin() +// .where(intgrnSendDetail.intgrnSendMast.intSendMastId.eq(intSendMastId) +// .and(intgrnSendDetail.mkBillUseYn.eq("Y")) +// .and(urlIsNull ? intgrnSendDetail.kkoBillMast.url.isNull() : intgrnSendDetail.kkoBillMast.url.isNotNull()) +// ) +// .fetch(); +// } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendMastRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendMastRepository.java new file mode 100644 index 0000000..177e915 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendMastRepository.java @@ -0,0 +1,19 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.code.TryStatCd; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.time.LocalDateTime; +import java.util.List; + +public interface IntgrnSendMastRepository extends JpaRepository, IntgrnSendMastRepositoryCustom { + + List findAllByIntSendMastIdIn(List sendMastIds); + + List findAllByStatCdIn(List statCds); + List findAllByStatCdInOrTryStatCdIn(List statCds, List tryStatCds); + + List findAllByStatCdInAndCloseDtBefore(List statCds, LocalDateTime closeDt); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendMastRepositoryCustom.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendMastRepositoryCustom.java new file mode 100644 index 0000000..b64303a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendMastRepositoryCustom.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +public interface IntgrnSendMastRepositoryCustom { + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendMastRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendMastRepositoryImpl.java new file mode 100644 index 0000000..5077915 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/IntgrnSendMastRepositoryImpl.java @@ -0,0 +1,10 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class IntgrnSendMastRepositoryImpl implements IntgrnSendMastRepositoryCustom { + + private final JPAQueryFactory query; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngIntgrnRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngIntgrnRepository.java new file mode 100644 index 0000000..fdd0e6f --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngIntgrnRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.TmpltMngIntgrn; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.ids.TmpltMngIds; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TmpltMngIntgrnRepository extends JpaRepository, TmpltMngIntgrnRepositoryCustom { +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngIntgrnRepositoryCustom.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngIntgrnRepositoryCustom.java new file mode 100644 index 0000000..dc286f0 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngIntgrnRepositoryCustom.java @@ -0,0 +1,10 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.TmpltMngRepositorySupport; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngSearchDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.TmpltMngIntgrn; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.TmpltMngIntgrnDTO; + +public interface TmpltMngIntgrnRepositoryCustom extends TmpltMngRepositorySupport { + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngIntgrnRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngIntgrnRepositoryImpl.java new file mode 100644 index 0000000..50c3b95 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngIntgrnRepositoryImpl.java @@ -0,0 +1,163 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.TmpltMngIntgrn; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.TmpltMngIntgrnDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngSearchDTO; +import cokr.xit.ens.modules.kkoalimtalk.model.TmpltMngKkoAlimtalkDTO; +import cokr.xit.ens.modules.kkomydoc.model.TmpltMngKkoMydocDTO; +import cokr.xit.ens.modules.ktsigntalk.direct.model.TmpltMngKtSigntalkDTO; +import cokr.xit.ens.modules.ktsigntalk.gibis.model.TmpltMngKtGibisDTO; +import cokr.xit.ens.modules.nvsigntalk.model.TmpltMngNvSigntalkDTO; +import com.google.gson.Gson; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.QBean; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.util.List; +import java.util.Optional; + +import static cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.QTmpltMngIntgrn.tmpltMngIntgrn; +import static cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng.orgMng; +import static cokr.xit.ens.modules.kkoalimtalk.domain.QTmpltMngKkoAlimtalk.tmpltMngKkoAlimtalk; +import static cokr.xit.ens.modules.kkomydoc.domain.QTmpltMngKkoMydoc.tmpltMngKkoMydoc; +import static cokr.xit.ens.modules.ktsigntalk.direct.domain.QTmpltMngKtSigntalk.tmpltMngKtSigntalk; +import static cokr.xit.ens.modules.ktsigntalk.gibis.domain.QTmpltMngKtGibis.tmpltMngKtGibis; +import static cokr.xit.ens.modules.nvsigntalk.domain.QTmpltMngNvSigntalk.tmpltMngNvSigntalk; + +@RequiredArgsConstructor +public class TmpltMngIntgrnRepositoryImpl implements TmpltMngIntgrnRepositoryCustom { + + private final JPAQueryFactory query; + + @Override + public Optional findFetchByOrgCdAndTmpltCd(String orgCd, String tmpltCd) { + return Optional.ofNullable(query.selectFrom(tmpltMngIntgrn) + .where(tmpltMngIntgrn.orgMng.orgCd.eq(orgCd) + .and(tmpltMngIntgrn.tmpltCd.eq(tmpltCd))) + .fetchOne()); + } + + @Override + public List findAllFetchBySearchDTO(TmpltMngSearchDTO searchDTO) { + return query.selectFrom(tmpltMngIntgrn) + .innerJoin(tmpltMngIntgrn.orgMng, orgMng) + .fetchJoin() + .where(eqSearchDTO(searchDTO)) + .fetch(); + } + + @Override + public Optional findDtoByOrgCdAndTmpltCd(String orgCd, String tmpltCd) { + return Optional.ofNullable(query.select(mappedDto()) + .from(tmpltMngIntgrn) + .leftJoin(tmpltMngKkoAlimtalk).on(tmpltMngIntgrn.orgMng.orgCd.eq(tmpltMngKkoAlimtalk.orgMng.orgCd).and(tmpltMngIntgrn.tmpltCd.eq(tmpltMngKkoAlimtalk.tmpltCd))) + .leftJoin(tmpltMngKkoMydoc).on(tmpltMngIntgrn.orgMng.orgCd.eq(tmpltMngKkoMydoc.orgMng.orgCd).and(tmpltMngIntgrn.tmpltCd.eq(tmpltMngKkoMydoc.tmpltCd))) + .leftJoin(tmpltMngNvSigntalk).on(tmpltMngIntgrn.orgMng.orgCd.eq(tmpltMngNvSigntalk.orgMng.orgCd).and(tmpltMngIntgrn.tmpltCd.eq(tmpltMngNvSigntalk.tmpltCd))) + .leftJoin(tmpltMngKtSigntalk).on(tmpltMngIntgrn.orgMng.orgCd.eq(tmpltMngKtSigntalk.orgMng.orgCd).and(tmpltMngIntgrn.tmpltCd.eq(tmpltMngKtSigntalk.tmpltCd))) + .leftJoin(tmpltMngKtGibis).on(tmpltMngIntgrn.orgMng.orgCd.eq(tmpltMngKtGibis.orgMng.orgCd).and(tmpltMngIntgrn.tmpltCd.eq(tmpltMngKtGibis.tmpltCd))) + .where(tmpltMngIntgrn.orgMng.orgCd.eq(orgCd) + .and(tmpltMngIntgrn.tmpltCd.eq(tmpltCd))) + .fetchOne()); + } + + @Override + public List findAllDtoBySearchDTO(TmpltMngSearchDTO searchDTO) { + return query.select(mappedDto()) + .from(tmpltMngIntgrn) + .leftJoin(tmpltMngKkoAlimtalk).on(tmpltMngIntgrn.orgMng.orgCd.eq(tmpltMngKkoAlimtalk.orgMng.orgCd).and(tmpltMngIntgrn.tmpltCd.eq(tmpltMngKkoAlimtalk.tmpltCd))) + .leftJoin(tmpltMngKkoMydoc).on(tmpltMngIntgrn.orgMng.orgCd.eq(tmpltMngKkoMydoc.orgMng.orgCd).and(tmpltMngIntgrn.tmpltCd.eq(tmpltMngKkoMydoc.tmpltCd))) + .leftJoin(tmpltMngNvSigntalk).on(tmpltMngIntgrn.orgMng.orgCd.eq(tmpltMngNvSigntalk.orgMng.orgCd).and(tmpltMngIntgrn.tmpltCd.eq(tmpltMngNvSigntalk.tmpltCd))) + .leftJoin(tmpltMngKtSigntalk).on(tmpltMngIntgrn.orgMng.orgCd.eq(tmpltMngKtSigntalk.orgMng.orgCd).and(tmpltMngIntgrn.tmpltCd.eq(tmpltMngKtSigntalk.tmpltCd))) + .leftJoin(tmpltMngKtGibis).on(tmpltMngIntgrn.orgMng.orgCd.eq(tmpltMngKtGibis.orgMng.orgCd).and(tmpltMngIntgrn.tmpltCd.eq(tmpltMngKtGibis.tmpltCd))) + .where(eqSearchDTO(searchDTO)) + .fetch(); + } + + private QBean mappedDto() { + Gson gson = new Gson(); + return Projections.fields(TmpltMngIntgrnDTO.class + , tmpltMngIntgrn.dtype + , tmpltMngIntgrn.orgMng.orgCd + , tmpltMngIntgrn.orgMng.orgNm + , tmpltMngIntgrn.tmpltCd + , tmpltMngIntgrn.title + , tmpltMngIntgrn.message + , tmpltMngIntgrn.useYn + , tmpltMngIntgrn.try1 + , tmpltMngIntgrn.try2 + , tmpltMngIntgrn.try3 + , Projections.fields(TmpltMngKkoAlimtalkDTO.class + , tmpltMngKkoAlimtalk.biztalkOrgCd + , tmpltMngKkoAlimtalk.biztalkTmpltCode + , tmpltMngKkoAlimtalk.pryMessage + ).as("kkoAlimtalk") + , Projections.fields(TmpltMngKkoMydocDTO.class + , tmpltMngKkoMydoc.csNumber + , tmpltMngKkoMydoc.csName + , tmpltMngKkoMydoc.ciTransUseYn + , tmpltMngKkoMydoc.tmpltMsgUseYn + , tmpltMngKkoMydoc.tmpltCsInfoUseYn + , tmpltMngKkoMydoc.pryMessage + ).as("kkoMydoc") + , Projections.fields(TmpltMngNvSigntalkDTO.class + , tmpltMngNvSigntalk.callCenterNo + , tmpltMngNvSigntalk.ciTransUseYn + , tmpltMngNvSigntalk.tmpltMsgUseYn + , tmpltMngNvSigntalk.tmpltCsInfoUseYn + , tmpltMngNvSigntalk.messageDataFmt + ).as("nvSigntalk") + , Projections.fields(TmpltMngKtSigntalkDTO.class + , tmpltMngKtSigntalk.sndTelNo + , tmpltMngKtSigntalk.sendTel + , tmpltMngKtSigntalk.ciTransUseYn + , tmpltMngKtSigntalk.tmpltMsgUseYn + , tmpltMngKtSigntalk.tmpltCsInfoUseYn + , tmpltMngKtSigntalk.pryMessage + ).as("ktSigntalk") + , Projections.fields(TmpltMngKtGibisDTO.class + , tmpltMngKtGibis.msgCd + , tmpltMngKtGibis.mtype + , tmpltMngKtGibis.msgType + , tmpltMngKtGibis.optType + , tmpltMngKtGibis.sndTelNo + , tmpltMngKtGibis.sendTel + , tmpltMngKtGibis.ciTransUseYn + , tmpltMngKtGibis.tmpltMsgUseYn + , tmpltMngKtGibis.tmpltCsInfoUseYn + , tmpltMngKtGibis.pryMessage + ).as("ktGibis") + ); + } + + @Override + public Optional findFetchByOrgCdAndTmpltCdAndUseYn(String orgCd, String tmpltCd, String useYn) { + return Optional.ofNullable( + query.selectFrom(tmpltMngIntgrn) + .innerJoin(tmpltMngIntgrn.orgMng, orgMng).fetchJoin() + .where( + tmpltMngIntgrn.orgMng.orgCd.eq(orgCd) + .and(tmpltMngIntgrn.tmpltCd.eq(tmpltCd)) + .and(tmpltMngIntgrn.useYn.eq(useYn)) + ) + .fetchOne()); + } + + private BooleanBuilder eqSearchDTO(TmpltMngSearchDTO searchDTO) { + BooleanBuilder builder = new BooleanBuilder(); + + if (!CmmnUtil.isEmpty(searchDTO.getSchOrgCd())) + builder.and(tmpltMngIntgrn.orgMng.orgCd.eq(searchDTO.getSchOrgCd())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchTmpltCd())) + builder.and(tmpltMngIntgrn.tmpltCd.eq(searchDTO.getSchTmpltCd())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchTitle())) + builder.and(tmpltMngIntgrn.title.like(searchDTO.getSchTitle() + "%")); + + + return builder; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngKkoAlimtalkMapper.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngKkoAlimtalkMapper.java new file mode 100644 index 0000000..967a98d --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngKkoAlimtalkMapper.java @@ -0,0 +1,10 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +import cokr.xit.ens.core.repository.MybatisCrudSupport; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.ids.TmpltMngIds; +import cokr.xit.ens.modules.kkoalimtalk.domain.TmpltMngKkoAlimtalk; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TmpltMngKkoAlimtalkMapper extends MybatisCrudSupport { +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngKkoMydocMapper.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngKkoMydocMapper.java new file mode 100644 index 0000000..6b48712 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngKkoMydocMapper.java @@ -0,0 +1,10 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +import cokr.xit.ens.core.repository.MybatisCrudSupport; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.ids.TmpltMngIds; +import cokr.xit.ens.modules.kkomydoc.domain.TmpltMngKkoMydoc; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TmpltMngKkoMydocMapper extends MybatisCrudSupport { +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngKtGibisMapper.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngKtGibisMapper.java new file mode 100644 index 0000000..4f9c407 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngKtGibisMapper.java @@ -0,0 +1,11 @@ + +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +import cokr.xit.ens.core.repository.MybatisCrudSupport; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.ids.TmpltMngIds; +import cokr.xit.ens.modules.ktsigntalk.gibis.domain.TmpltMngKtGibis; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TmpltMngKtGibisMapper extends MybatisCrudSupport { +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngKtSigntalkMapper.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngKtSigntalkMapper.java new file mode 100644 index 0000000..0218565 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngKtSigntalkMapper.java @@ -0,0 +1,11 @@ + +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +import cokr.xit.ens.core.repository.MybatisCrudSupport; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.ids.TmpltMngIds; +import cokr.xit.ens.modules.ktsigntalk.direct.domain.TmpltMngKtSigntalk; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TmpltMngKtSigntalkMapper extends MybatisCrudSupport { +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngNvSigntalkMapper.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngNvSigntalkMapper.java new file mode 100644 index 0000000..ddaa950 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/domain/repository/TmpltMngNvSigntalkMapper.java @@ -0,0 +1,10 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository; + +import cokr.xit.ens.core.repository.MybatisCrudSupport; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.ids.TmpltMngIds; +import cokr.xit.ens.modules.nvsigntalk.domain.TmpltMngNvSigntalk; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TmpltMngNvSigntalkMapper extends MybatisCrudSupport { +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/IntgrnDetailStatVO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/IntgrnDetailStatVO.java new file mode 100644 index 0000000..19dfa85 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/IntgrnDetailStatVO.java @@ -0,0 +1,59 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.model; + +import cokr.xit.ens.core.model.EnsAcceptReqDTO; +import cokr.xit.ens.modules.common.code.IntgrnDtlStatMapperType; +import cokr.xit.ens.modules.common.code.PostSeCd; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@SuperBuilder +@Data +@Schema(name = "IntgrnDetailStatVO") +@NoArgsConstructor +public class IntgrnDetailStatVO extends EnsAcceptReqDTO { + + + private Long intSendDetailId; + + @Schema(required = false, title = "연계식별키", example = "") + private String linkedUuid; + + @Schema(required = true, title = "우편구분", example = "") + private PostSeCd curPostSe; + + @Schema(required = true, title = "상태코드", example = "") + private IntgrnDtlStatMapperType curStatCd; + + @Schema(required = false, title = "1.송신 시간(yyyyMMddHHmmss)", example = " ") + private String docSentDt; + + @Schema(required = false, title = "2-1.수신 시간(yyyyMMddHHmmss)", example = " ") + private String docReceivedDt; + + @Schema(required = false, title = "3.열람 인증을 성공한 최초 시간(yyyyMMddHHmmss)", example = " ") + private String docAuthFrstDt; + + @Schema(required = false, title = "4.OTT 검증을 성공한 최초 시간(yyyyMMddHHmmss)", example = " ") + private String docTokenVrfyFrstDt; + + @Schema(required = false, title = "5.최초 열람 시간(yyyyMMddHHmmss)", example = " ") + private String docReadFrstDt; + + @Schema(required = false, title = "2-2.수신 시간(yyyyMMddHHmmss)", example = " ") + private String docUserNotiedDt; + + @Schema(required = false, title = "에러코드", example = " ") + private String errorCode; + + @Schema(required = false, title = "에러메시지", example = " ") + private String errorMessage; + + @Schema(required = false, title = "부모 에러코드", example = " ") + private String mastErrorCode; + + @Schema(required = false, title = "부모 에러메시지", example = " ") + private String mastErrorMessage; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/IntgrnNotiAcceptReqDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/IntgrnNotiAcceptReqDTO.java new file mode 100644 index 0000000..f49e6b8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/IntgrnNotiAcceptReqDTO.java @@ -0,0 +1,24 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.model; + +import cokr.xit.ens.core.model.EnsAcceptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config.Document; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import java.util.List; + +@SuperBuilder +@Data +@Schema(name = "IntgrnNotiAcceptReqDTO") +@NoArgsConstructor +public class IntgrnNotiAcceptReqDTO extends EnsAcceptReqDTO { + + @Valid + @NotEmpty(message = "문서목록은 필수 입력값 입니다") + private List documents; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/IntgrnNotiRsltRespDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/IntgrnNotiRsltRespDTO.java new file mode 100644 index 0000000..5b6cfde --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/IntgrnNotiRsltRespDTO.java @@ -0,0 +1,26 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.model; + +import cokr.xit.ens.core.model.EnsRsltRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.code.TryStatCd; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.SuperBuilder; + +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import java.util.List; + +@SuperBuilder +@Data +@Schema(name = "IntgrnNotiRsltRespDTO") +public class IntgrnNotiRsltRespDTO extends EnsRsltRespDTO { + @Schema(required = true, title = "발송마스터ID", example = " ") + private Long intSendMastId; + @Schema(required = true, title = "회차 상태정보", example = " ") + @Enumerated(EnumType.STRING) + private TryStatCd tryStatCd; + @Schema(required = false, title = "발송요청문서", example = " ") + private List documents; + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/TmpltMngIntgrnDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/TmpltMngIntgrnDTO.java new file mode 100644 index 0000000..e513689 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/TmpltMngIntgrnDTO.java @@ -0,0 +1,59 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.model; + +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngDTO; +import cokr.xit.ens.modules.kkoalimtalk.model.TmpltMngKkoAlimtalkDTO; +import cokr.xit.ens.modules.kkomydoc.model.TmpltMngKkoMydocDTO; +import cokr.xit.ens.modules.ktsigntalk.direct.model.TmpltMngKtSigntalkDTO; +import cokr.xit.ens.modules.ktsigntalk.gibis.model.TmpltMngKtGibisDTO; +import cokr.xit.ens.modules.nvsigntalk.model.TmpltMngNvSigntalkDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +@Data +@SuperBuilder +@NoArgsConstructor +@Schema(name = "TmpltMngIntegrationDTO") +public class TmpltMngIntgrnDTO extends TmpltMngDTO implements Serializable { + + @NotNull(message = "1회차 발송유형은 필수 입력값 입니다.") + @Schema(required = true, title = "1회차 발송유형", example = "kkoMydoc") + private PostSeCd try1; + + @Schema(required = false, title = "2회차 발송유형", example = "nvSigntalk") + private PostSeCd try2; + + @Enumerated(EnumType.STRING) + @Schema(required = false, title = "3회차 발송유형", example = "kkoAlimtalk") + private PostSeCd try3; + + @Schema(required = false, title = "카카오 알림톡", example = " ") + @Valid + private TmpltMngKkoAlimtalkDTO kkoAlimtalk; + + @Schema(required = false, title = "카카오 내문서함(인증톡)", example = " ") + @Valid + private TmpltMngKkoMydocDTO kkoMydoc; + + @Schema(required = false, title = "네이버 고지서(인증톡)", example = " ") + @Valid + private TmpltMngNvSigntalkDTO nvSigntalk; + + @Schema(required = false, title = "KT 인증톡", example = " ") + @Valid + private TmpltMngKtSigntalkDTO ktSigntalk; + + @Schema(required = false, title = "KT 인증톡(지비스)", example = " ") + @Valid + private TmpltMngKtGibisDTO ktGibis; + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/config/AcptData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/config/AcptData.java new file mode 100644 index 0000000..7c7e602 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/config/AcptData.java @@ -0,0 +1,40 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config; + +import cokr.xit.ens.modules.kkoalimtalk.model.config.DocumentConfKkoAt; +import cokr.xit.ens.modules.kkomydoc.model.config.DocumentConfKkoMd; +import cokr.xit.ens.modules.ktsigntalk.direct.model.config.DocumentConfKtSt; +import cokr.xit.ens.modules.ktsigntalk.gibis.model.config.DocumentConfKtGbs; +import cokr.xit.ens.modules.nvsigntalk.model.config.DocumentConfNvSt; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.validation.Valid; + +@Getter +@ToString +@Builder +@Schema(name = "AcptData") +@NoArgsConstructor +@AllArgsConstructor +public class AcptData { + + @Schema(required = false, title = "카카오 내문서함(인증톡) 접수요청", example = " ") + @Valid + private DocumentConfKkoMd kko_md; + + @Schema(required = false, title = "카카오 알림톡 접수요청", example = " ") + @Valid + private DocumentConfKkoAt kko_at; + + @Schema(required = false, title = "네이버 고지서(인증톡) 접수요청", example = " ") + @Valid + private DocumentConfNvSt nv_st; + + @Schema(required = false, title = "KT 인증톡 접수요청", example = " ") + @Valid + private DocumentConfKtSt kt_st; + + @Schema(required = false, title = "KT 인증톡(지비스) 접수요청", example = " ") + @Valid + private DocumentConfKtGbs kt_gbs; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/config/Document.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/config/Document.java new file mode 100644 index 0000000..f7c00ac --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/config/Document.java @@ -0,0 +1,67 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.validator.constraints.Length; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Getter +@ToString +@Builder +@Schema(name = "Document") +@NoArgsConstructor +@AllArgsConstructor +public class Document { + +// @Pattern(regexp = "[^a-zA-Z0-9]", message = "연계식별키는 숫자 또는 문자만 입력 가능 합니다.") + @NotEmpty(message = "연계식별키는 필수 입력값 입니다.") + @Length(max = 40, message = "연계식별키의 최대길이를 초과 했습니다.") + @Schema(required = false, title = "연계식별키", example = " ") + private String linked_uuid; + +// @Schema(required = false, title = "ci", example = " ") +// private String ci; +// +// @Pattern(regexp = "\\d{2}([0]\\d|[1][0-2])([0][1-9]|[1-2]\\d|[3][0-1])[1-8]\\d{6}", message = "주민등록번호 입력값의 형식이 유효하지 않습니다. 13자리 숫자로 입력하시기 바랍니다.") +// @Schema(required = false, title = "주민등록번호", example = "8611281234567") +// private String jid; +// +// @Pattern(regexp = "^\\d{3}\\d{3,4}\\d{4}$", message = "휴대폰번호 입력값의 형식이 유효하지 않습니다.") +// @Schema(required = false, title = "휴대폰번호", example = "0101231234") +// private String mblphonNo; +// +// @Schema(required = false, title = "카카오페이 청구서링크 정보", example = " ") +// @Valid +// private BillLinkInfo kkoBillLinkInfo; +// +// @Schema(required = false, title = "템플릿 메시지 데이터", example = "{\"#{TARGET_NAME}\":\"홍길동\",\"#{CAR_NO}\":\"12더1234\",\"#{HISTORY}\":\"2022-01-01\",\"#{FEE}\":\"1000\",\"#{YYYY}\":\"2022\",\"#{MM}\":\"03\",\"#{DD}\":\"30\",\"#{BANK}\":\"기업\",\"#{ACCOUNT}\":\"311-063233-01-123\",\"#{HOMEPAGE}\":\"http://www.xit.co.kr\",\"#{REP_CALL_NO}\":\"070-4490-7404\"}") +// private Map tmpltMsgData; +// +// @Schema(required = false, title = "모바일페이지 노출 데이터", example = "{\"details\":[{\"title\":\"텍스트 타입\",\"item_type\":\"TEXT\",\"properties\":{\"use_toggle\":false},\"elements\":[\"test\",\"하하하\"]},{\"title\":\"PRE 텍스트 타입\",\"item_type\":\"PRE_TEXT\",\"properties\":{\"use_toggle\":false},\"elements\":\"가나다라마\\r\\nABCDEFGHI\\n1234567890\"},{\"title\":\"키-밸류 타입\",\"item_type\":\"KEY_VALUE\",\"properties\":{\"use_toggle\":false},\"elements\":[{\"key\":\"당월 부과 금액\",\"value\":\"200,203원\",\"level\":1},{\"key\":\"미납액\",\"value\":\"1,200원\",\"level\":1}]},{\"title\":\"테이블 타입\",\"item_type\":\"TABLE\",\"properties\":{\"use_toggle\":false,\"style\":{\"text_align\":[\"center\",\"left\",\"right\"]}},\"elements\":{\"head\":[\"항목\",\"당월금액\",\"전월대비\"],\"rows\":[[\"전기료\",\"1,000,000원\",\"+500,000\"],[\"수도료\",\"300,000원\",\"-100,000\"]]}},{\"title\":\"이미지 타입\",\"item_type\":\"IMAGE\",\"print_type\":\"이미지출력타입(공백: img태그(default), SLIDE: 슬라이드 기능 적용)\",\"properties\":{\"use_toggle\":false},\"elements\":[{\"링크 이미지\":\"http://www.xit.co.kr/....\"},{\"Base64 이미지\":\"data:image/png;base64,iVBORw0KGgoAAAAN....\"}]},{\"title\":\"링크버튼 타입\",\"item_type\":\"BUTTON\",\"link_url\":\"https://www.naver.com\"},{\"title\":\"결제버튼 타입\",\"item_type\":\"PAY_BUTTON\"}]}") +// private Map>> mblPageData; +// +// @Schema(required = false, title = "카카오 내문서함(인증톡) 접수요청", example = " ") +// @Valid +// private DocumentConfKkoMd acptDocKkoMd; +// +// @Schema(required = false, title = "카카오 알림톡 접수요청", example = " ") +// @Valid +// private DocumentConfKkoAt acptDocKkoAt; +// +// @Schema(required = false, title = "네이버 고지서(인증톡) 접수요청", example = " ") +// @Valid +// private DocumentConfNvSt acptDocNvSt; + + + @NotNull(message = "수신자정보는 필수 입력값 입니다.") + @Valid + private Receiver receiver; + @NotNull(message = "타입별 접수데이터는 필수 입력값 입니다.") + @Valid + private AcptData acpt_data; + @Valid + private XitProperty xit_property; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/config/Receiver.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/config/Receiver.java new file mode 100644 index 0000000..afc7be9 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/config/Receiver.java @@ -0,0 +1,27 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.validation.constraints.Pattern; + +@Getter +@ToString +@Builder +@Schema(name = "Receiver") +@NoArgsConstructor +@AllArgsConstructor +public class Receiver { + + + @Schema(required = false, title = "ci", example = " ") + private String ci; + + @Pattern(regexp = "\\d{2}([0]\\d|[1][0-2])([0][1-9]|[1-2]\\d|[3][0-1])[1-8]\\d{6}", message = "주민등록번호 입력값의 형식이 유효하지 않습니다. 13자리 숫자로 입력하시기 바랍니다.") + @Schema(required = false, title = "주민등록번호", example = "8611281234567") + private String jid; + + @Pattern(regexp = "^\\d{3}\\d{3,4}\\d{4}$", message = "휴대폰번호 입력값의 형식이 유효하지 않습니다.") + @Schema(required = false, title = "휴대폰번호", example = "0101231234") + private String mblphon_no; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/config/XitProperty.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/config/XitProperty.java new file mode 100644 index 0000000..9fc2611 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/config/XitProperty.java @@ -0,0 +1,34 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config; + +import cokr.xit.ens.core.model.EnsBillAcptReqDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.Map; + +@Getter +@ToString +@EqualsAndHashCode +//@SuperBuilder +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Schema(name = "XitProperty") +public class XitProperty { + + @Schema(required = false, title = "모바일페이지 노출 데이터", example = "{\"details\":[{\"title\":\"텍스트 타입\",\"item_type\":\"TEXT\",\"properties\":{\"use_toggle\":false,\"style\":{\"highlight\":{\"하하하\":{\"use-clipboard\":true,\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"}}},\"hyperlink\":[\"http://www.naver.com\",\"http://www.xit.co.kr\"]},\"elements\":[\"test\",\"하하하\"]},{\"title\":\"PRE 텍스트 타입\",\"item_type\":\"PRE_TEXT\",\"properties\":{\"use_toggle\":false,\"style\":{\"highlight\":{\"다라마\":{\"use-clipboard\":true,\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"},\"1111-23123-12313\":{\"use-clipboard\":false,\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"}}},\"hyperlink\":[\"http://www.naver.com\",\"http://www.xit.co.kr\"]},\"elements\":\"가나다라마\\r\\nABCDEFGHI\\n1234567890\\n1111-23123-12313 카카오\\n카카오뱅크\\nhttp://www.naver.com\"},{\"title\":\"키-밸류 타입\",\"item_type\":\"KEY_VALUE\",\"properties\":{\"use_toggle\":false,\"style\":{\"highlight\":{\"액\":{\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"}}},\"hyperlink\":[\"http://www.naver.com\",\"http://www.xit.co.kr\"]},\"elements\":[{\"key\":\"당월 부과 금액\",\"value\":\"200,203원\",\"level\":1},{\"key\":\"미납액\",\"value\":\"1,200원\",\"level\":1}]},{\"title\":\"테이블 타입\",\"item_type\":\"TABLE\",\"properties\":{\"use_toggle\":false,\"style\":{\"text_align\":[\"center\",\"left\",\"right\"],\"highlight\":{\"전기료\":{\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"}}},\"hyperlink\":[\"http://www.naver.com\",\"http://www.xit.co.kr\"]},\"elements\":{\"head\":[\"항목\",\"당월금액\",\"전월대비\"],\"rows\":[[\"전기료\",\"1,000,000원\",\"+500,000\"],[\"수도료\",\"300,000원\",\"-100,000\"]]}},{\"title\":\"이미지 타입\",\"item_type\":\"IMAGE\",\"print_type\":\"이미지출력타입(공백: img태그(default), SLIDE: 슬라이드 기능 적용)\",\"properties\":{\"use_toggle\":false},\"elements\":[{\"key\":\"링크 이미지\",\"value\":\"http://www.xit.co.kr/....\"},{\"key\":\"Base64 이미지\",\"value\":\"data:image/png;base64,iVBORw0KGgoAAAAN....\"}]},{\"title\":\"링크버튼 타입\",\"item_type\":\"BUTTON\",\"link_url\":\"https://www.naver.com\"},{\"title\":\"결제버튼 타입\",\"item_type\":\"PAY_BUTTON\"}]}") + private Map>> mbl_page_data; + + @Schema(required = false, title = "템플릿 메시지 데이터", example = "{\"#{TARGET_NAME}\":\"홍길동\",\"#{CAR_NO}\":\"12더1234\",\"#{HISTORY}\":\"2022-01-01\",\"#{FEE}\":\"1000\",\"#{YYYY}\":\"2022\",\"#{MM}\":\"03\",\"#{DD}\":\"30\",\"#{BANK}\":\"기업\",\"#{ACCOUNT}\":\"311-063233-01-123\",\"#{HOMEPAGE}\":\"http://www.xit.co.kr\",\"#{REP_CALL_NO}\":\"070-4490-7404\"}") + private Map tmplt_msg_data; + + @Valid + private EnsBillAcptReqDTO bill_acpt_data; + +// @Schema(required = false, title = "카카오페이 청구서링크 정보", example = " ") +// @Valid +// private BillLinkInfo bill_link_info; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/struct/TmpltMngIntgrnMapper.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/struct/TmpltMngIntgrnMapper.java new file mode 100644 index 0000000..9f24bf8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/model/struct/TmpltMngIntgrnMapper.java @@ -0,0 +1,21 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.struct; + +import cokr.xit.ens.core.mapstruct.GenericMapper; +import cokr.xit.ens.core.mapstruct.StructMapperConfig; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.TmpltMngIntgrn; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.TmpltMngIntgrnDTO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(config = StructMapperConfig.class) +public interface TmpltMngIntgrnMapper extends GenericMapper { + + @Override + @Mapping(target = "orgMng.orgCd", source = "orgCd") + TmpltMngIntgrn toEntity(TmpltMngIntgrnDTO tmpltMngIntgrnDTO); + + + @Override + @Mapping(target = "orgCd", expression = "java(tmpltMngIntgrn.getOrgMng().getOrgCd())") + TmpltMngIntgrnDTO toDto(TmpltMngIntgrn tmpltMngIntgrn); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/presentation/IntgrnNotiController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/presentation/IntgrnNotiController.java new file mode 100644 index 0000000..79c5f24 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/presentation/IntgrnNotiController.java @@ -0,0 +1,153 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.presentation; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnNotiAcceptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.IntgrnNotiService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@Tag(name = "IntgrnNotiController") +@Slf4j +@RestController +@RequiredArgsConstructor +public class IntgrnNotiController { + + private final IntgrnNotiService intgrnNotiService; + + + @Operation(summary = "접수") + @PostMapping(value = "/intgrn/noti/accept", produces = MediaType.APPLICATION_JSON_VALUE) +// public ResponseEntity accept(@Validated @RequestBody IntgrnNotiAcceptReqDTO reqDTO, BindingResult bindingResult){ + public ResponseEntity accept(@RequestBody IntgrnNotiAcceptReqDTO reqDTO){ + + EnsResponseVO responseVO = intgrnNotiService.accept(reqDTO); + + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "제작" + , value = "{\"intSendMastId\": 1}") + }) + }) + @Operation(summary = "제작") +// @PutMapping(value = "/intgrn/noti/make", produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/intgrn/noti/make", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity make(@RequestBody Map mParam){ + + EnsResponseVO responseVO = intgrnNotiService.remake(mParam.get("intSendMastId")); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + + + @Operation(summary = "제작(일괄)") +// @PutMapping(value = "/intgrn/noti/make/all", produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/intgrn/noti/make/all", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity makeAll(){ + + EnsResponseVO responseVO = intgrnNotiService.makeAll(); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "(대량)전송요청" + , value = "{\"intSendMastId\": 1}") + }) + }) + @Operation(summary = "(대량)전송요청") + @PostMapping(value = "/intgrn/noti/send/bulk", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity sendBulk(@RequestBody Map mParam){ + EnsResponseVO responseVO = intgrnNotiService.sendBulk(mParam.get("intSendMastId")); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "(대량)전송요청 일괄") + @PostMapping(value = "/intgrn/noti/send/bulk/all", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity sendBulkAll(){ + EnsResponseVO responseVO = intgrnNotiService.sendBulkAll(); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "(대량)문서상태 갱신" + , value = "{\"intSendMastId\": 1}") + }) + }) + @Operation(summary = "(대량)문서상태 갱신") +// @PutMapping(value = "/intgrn/noti/stat/bulk", produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/intgrn/noti/stat/bulk", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity statBulk(@RequestBody Map mParam){ + + EnsResponseVO responseVO = intgrnNotiService.statBulk(mParam.get("intSendMastId")); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "(대량)문서상태 일괄 갱신") +// @PutMapping(value = "/intgrn/noti/stat/bulk/all", produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/intgrn/noti/stat/bulk/all", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity statBulkAll(){ + + EnsResponseVO responseVO = intgrnNotiService.statBulkAll(); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "전송결과 가져오기" + , value = "{\"intSendMastId\": 1}") + }) + }) + @Operation(summary = "전송결과 가져오기") + @PostMapping(value = "/intgrn/noti/send/result/provide", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity sendResultProvide(@RequestBody Map mParam){ + + EnsResponseVO responseVO = intgrnNotiService.sendResultProvide(mParam.get("intSendMastId")); + + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + + @Operation(summary = "문서상태 마감처리") +// @PutMapping(value = "/intgrn/noti/stat/bulk/all", produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/intgrn/noti/stat/closed", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity statClosed(){ + + EnsResponseVO responseVO = intgrnNotiService.closed(); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/presentation/IntgrnNotiCryptoController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/presentation/IntgrnNotiCryptoController.java new file mode 100644 index 0000000..5c16bc0 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/presentation/IntgrnNotiCryptoController.java @@ -0,0 +1,107 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.presentation; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.utils.crypto.AES256; +import cokr.xit.ens.core.utils.crypto.Crypto; +import cokr.xit.ens.modules.common.code.UseNativeQuery; +import com.google.common.collect.Lists; +import com.querydsl.jpa.impl.JPAQueryFactory; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.core.BatchPreparedStatementSetter; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.transaction.Transactional; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +import static cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.QIntgrnSendDetail.intgrnSendDetail; + +@Tag(name = "IntgrnNotiCryptoController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class IntgrnNotiCryptoController { + + private final JPAQueryFactory query; + private final JdbcTemplate jdbcTemplate; + private int BATCH_SIZE = 1000; + + @Operation(summary = "주민번호 암호화(전체)") + @PostMapping(value = "/intgrn/noti/crypto/enc/jid/all", produces = MediaType.APPLICATION_JSON_VALUE) + @Transactional + public ResponseEntity encJidAll() { + + AES256 aes256 = new AES256(Crypto.AES256.getKey()); + Long totCnt = Lists.partition(query.selectFrom(intgrnSendDetail) + .where(intgrnSendDetail.jid.length().eq(13) + .or(intgrnSendDetail.jid.length().eq(14))) + .fetch(), this.BATCH_SIZE) + .stream() + .map(intgrnSendDetails -> { + jdbcTemplate.batchUpdate("update " + UseNativeQuery.IntgrnSendDetail.getTblNm() + " set jid = ? where int_send_detail_id = ?", new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setString(1, aes256.encrypt(intgrnSendDetails.get(i).getJid())); + ps.setLong(2, intgrnSendDetails.get(i).getIntSendDetailId()); + } + + @Override + public int getBatchSize() { + return intgrnSendDetails.size(); + } + }); + + return Long.valueOf(intgrnSendDetails.size()); + }) + .reduce(Long::sum) + .orElse(0L); + + EnsResponseVO responseVO = EnsResponseVO.okBuilder() + .resultInfo(totCnt + " updated success") + .build(); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "주민번호 복호화(전체)") + @PostMapping(value = "/intgrn/noti/crypto/dec/jid/all", produces = MediaType.APPLICATION_JSON_VALUE) + @Transactional + public ResponseEntity decJidAll() { + + AES256 aes256 = new AES256(Crypto.AES256.getKey()); + Long totCnt = Lists.partition(query.selectFrom(intgrnSendDetail) + .where(intgrnSendDetail.jid.length().eq(24)) + .fetch(), this.BATCH_SIZE) + .stream() + .map(intgrnSendDetails -> { + jdbcTemplate.batchUpdate("update " + UseNativeQuery.IntgrnSendDetail.getTblNm() + " set jid = ? where int_send_detail_id = ?", new BatchPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + ps.setString(1, aes256.decrypt(intgrnSendDetails.get(i).getJid())); + ps.setLong(2, intgrnSendDetails.get(i).getIntSendDetailId()); + } + + @Override + public int getBatchSize() { + return intgrnSendDetails.size(); + } + }); + + return Long.valueOf(intgrnSendDetails.size()); + }) + .reduce(Long::sum) + .orElse(0L); + + EnsResponseVO responseVO = EnsResponseVO.okBuilder() + .resultInfo(totCnt + " updated success") + .build(); + return new ResponseEntity(responseVO, HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/presentation/IntgrnNotiMblPageController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/presentation/IntgrnNotiMblPageController.java new file mode 100644 index 0000000..38fbc0c --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/presentation/IntgrnNotiMblPageController.java @@ -0,0 +1,81 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.presentation; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.Map; + +@Tag(name = "IntgrnNotiMblPageController") +@Slf4j +@RequiredArgsConstructor +@Controller +public class IntgrnNotiMblPageController { + + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + + @Value("${xit.mblpage.postse.kkomd.path}") + private String KKOMD_MBL_PATH; + @Value("${xit.mblpage.postse.nvst.path}") + private String NVST_MBL_PATH; + @Value("${xit.mblpage.postse.ktst.path}") + private String KTST_MBL_PATH; + @Value("${xit.mblpage.postse.ktgbs.path}") + private String KTGBS_MBL_PATH; + + + @GetMapping(value = "/intgrn/noti/page/prnt") + public String mblPagePrnt(@RequestParam Map mParam, ModelMap model) { + + String docUuid = null; + String linkedUuid = null; + if (docUuid == null) docUuid = mParam.get("document_binder_uuid"); + if (linkedUuid == null) linkedUuid = mParam.get("external_document_uuid"); + if (docUuid == null) docUuid = mParam.get("docId"); + if (linkedUuid == null) linkedUuid = mParam.get("clientDocId"); + if (docUuid == null) { + docUuid = CmmnUtil.isEmpty(mParam.get("src_key")) ? null : mParam.get("src_key").replaceAll("[\\\"\\,\\[\\]]", ""); + linkedUuid = null; + } + + try { + if (CmmnUtil.isEmpty(docUuid)) + throw new EnsException(EnsErrCd.ERR410, "정상적인 요청이 아닙니다. 재인증 후 시도하시기 바랍니다. ( 내부식별ID는 필수조건 입니다 )"); + + + final String finalDocUuid = docUuid; + final String finalLinkedUuid = linkedUuid; +// IntgrnSendDetail intgrnSendDetail = intgrnSendDetailRepository.findByDocUuidAndLinkedUuid(docUuid, linkedUuid) +// .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("일치하는 자료가 없습니다. [docUuid %s linkedUuid %s]", finalDocUuid, finalLinkedUuid))); + final PostSeCd postSeCd = intgrnSendDetailRepository.findPostSeByDocUuidAndLinkedUuid(docUuid, linkedUuid); + if (postSeCd == null) + throw new EnsException(EnsErrCd.ERR404, String.format("일치하는 자료가 없습니다. [docUuid %s linkedUuid %s]", finalDocUuid, finalLinkedUuid)); + + + String url = null; + if (PostSeCd.kkoMydoc.equals(postSeCd)) url = KKOMD_MBL_PATH; + else if (PostSeCd.nvSigntalk.equals(postSeCd)) url = NVST_MBL_PATH; + else if (PostSeCd.ktSigntalk.equals(postSeCd)) url = KTST_MBL_PATH; + else if (PostSeCd.ktGibis.equals(postSeCd)) url = KTGBS_MBL_PATH; + else + throw new EnsException(EnsErrCd.ERR500, String.format("정의되지 않은 우편구분 입니다. [linkedUuid %s]", finalLinkedUuid)); + + return "forward:" + url; + } catch (EnsException e) { + model.put("errCode", e.getErrCd()); + model.put("errMsg", e.getMessage()); + return "modules/mblpage/notiprnt"; + } + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/IntgrnNotiService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/IntgrnNotiService.java new file mode 100644 index 0000000..4f599ba --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/IntgrnNotiService.java @@ -0,0 +1,291 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.code.TryStatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendMastRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnNotiAcceptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class IntgrnNotiService { + + + private final IntgrnSendMastRepository intgrnSendMastRepository; + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + + private final IntgrnNotiAcceptor intgrnSendAcceptor; + private final IntgrnNotiMaker intgrnNotiMaker; + + private final IntgrnNotiSender intgrnNotiSender; + private final IntgrnNotiRsltFetcher intgrnNotiRsltFetcher; + private final IntgrnNotiRsltProvider intgrnNotiRsltProvider; + + /** + * 접수 서비스 + * + * @param reqDTO + * @return + */ + @Transactional(propagation = Propagation.SUPPORTS) + public EnsResponseVO accept(IntgrnNotiAcceptReqDTO reqDTO) { + EnsResponseVO responseVO = null; + try { + responseVO = intgrnSendAcceptor.statBegin(reqDTO); + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) + return responseVO; + + responseVO = intgrnSendAcceptor.execute(reqDTO); + } catch (EnsException e) { + responseVO = EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + + return responseVO; + } + + + /** + * 제작 서비스 + * + * @param intSendMastId + * @return + */ + @Transactional(propagation = Propagation.SUPPORTS) + public EnsResponseVO remake(Long intSendMastId) { + try { + IntgrnSendMast sendMast = intgrnSendMastRepository.findById(intSendMastId) + .orElseThrow(() -> new EnsException(EnsErrCd.MAKE404, "일치하는 자료가 없습니다.")); + if (!(StatCd.accept.equals(sendMast.getStatCd()) + || StatCd.makefail.equals(sendMast.getStatCd()))) + throw new EnsException(EnsErrCd.MAKE404, "접수/제작실패(accept/makefail) 단계가 아닙니다."); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + + intgrnNotiMaker.statReady(Arrays.asList(intSendMastId)); + + + return this.make(intSendMastId); + } + + /** + * (일괄)제작 서비스 + * + * @return + */ + @Transactional(propagation = Propagation.SUPPORTS) + public EnsResponseVO makeAll() { + List sendMastIds = intgrnSendMastRepository.findAllByStatCdIn(Arrays.asList(StatCd.accept)) + .stream() + .map(row -> row.getIntSendMastId()) + .collect(Collectors.toList()); + if (sendMastIds.size() < 1) + return EnsResponseVO.errBuilder() + .errCode(EnsErrCd.MAKE404) + .errMsg("\"접수(accept)\" 상태인 자료가 없습니다") + .build(); + + intgrnNotiMaker.statReady(sendMastIds); + + List resultInfo = sendMastIds.stream() + .map(intSendMastId -> this.make(intSendMastId)) + .collect(Collectors.toList()); + + return EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } + + private EnsResponseVO make(Long intSendMastId) { + EnsResponseVO responseVO = intgrnNotiMaker.statBegin(intSendMastId); + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) + return responseVO; + + try { +// +// responseVO = this.makeBillLink(intSendMastId); +// if (!EnsErrCd.OK.equals(responseVO.getErrCode())) +// throw new EnsException(responseVO.getErrCode(), responseVO.getErrMsg()); + + responseVO = intgrnNotiMaker.execute(intSendMastId); + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) + throw new EnsException(responseVO.getErrCode(), responseVO.getErrMsg()); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + + return responseVO; + } + +// /** +// * 제작(청구서링크) 서비스 +// * +// * @param sendMastId +// * @return +// */ +// @Transactional(propagation = Propagation.SUPPORTS) +// public EnsResponseVO makeBillLink(Long sendMastId) { +// EnsResponseVO responseVO = intgrnNotiMakerOfBillLink.execute(sendMastId); +// +// return responseVO; +// } + + + /** + * (대량)전송 서비스 + * @return + */ + @Transactional(propagation = Propagation.SUPPORTS) + public EnsResponseVO sendBulk(Long intSendMastId) { + + try { + if (intgrnSendDetailRepository.findAllBySendTargetAndSendMast(IntgrnSendMast.builder().intSendMastId(intSendMastId).build()).size() < 1) + throw new EnsException(EnsErrCd.SEND404, "일치하는 자료가 없거나 전송 가능한 상태의 자료가 없습니다. (1회차:상태=makeok&try상태=stby&dtl상태=MAKING, 2~3회차:try상태:ok/fail&발송일시=기한경과&dtl상태=실패(ACPT_FAIL/FAIL/...)"); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + + List sendMastIds = Arrays.asList(intSendMastId); + + + return this.send(sendMastIds); + } + + /** + * (대량)전송 서비스-일괄 + */ + @Transactional(propagation = Propagation.SUPPORTS) + public EnsResponseVO sendBulkAll() { + + List intSendMastIds = intgrnSendDetailRepository.findIntSendMastIdsBySendTarget(); + if (intSendMastIds.size() < 1) + return EnsResponseVO.errBuilder() + .errCode(EnsErrCd.SEND404) + .errMsg("전송 타깃 데이터가 없습니다.") + .build(); + + return this.send(intSendMastIds); + } + + private EnsResponseVO send(List intSendMastIds) { + List resultInfo = intSendMastIds.stream() + .map(intSendMastId -> { + intgrnNotiSender.statBegin(intSendMastId); + return intSendMastId; + }) + .map(intSendMastId -> intgrnNotiSender.execute(intSendMastId)) + .collect(Collectors.toList()); + + + return EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } + + + /** + * 전송(성공/실패) 결과 가져오기 + */ + @Transactional(propagation = Propagation.SUPPORTS) + public EnsResponseVO statBulk(Long intSendMastId) { + IntgrnSendMast intgrnSendMast = null; + try { + intgrnSendMast = intgrnSendMastRepository.findById(intSendMastId) + .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("[ intSendMastId %s ]와 일치하는 자료가 없습니다.", intSendMastId))); + int validCnt = 0; + IntgrnSendMast finalIntgrnSendMast = intgrnSendMast; + if (!Arrays.asList(StatCd.sendok, StatCd.sendcmplt, StatCd.open).stream() + .anyMatch(statCd -> statCd.equals(finalIntgrnSendMast.getStatCd()))) + validCnt++; + if (!Arrays.asList(TryStatCd.sndRsrv, TryStatCd.sndRtme).stream() + .anyMatch(statCd -> statCd.equals(finalIntgrnSendMast.getTryStatCd()))) + validCnt++; + if (validCnt == 2) + throw new EnsException(EnsErrCd.RSLT404, "\"진행상태\"가 전송성공/전송완료/열람중(sendok/sendcmplt/open) 또는 \"현재 회차상태\"가 예약전송/실시간전송(sndRsrv/sndRtme) 상태가 아닙니다."); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + + return this.stat(Arrays.asList(intgrnSendMast)); + } + + /** + * 전송(성공/실패) 결과 모두 가져오기 + */ + @Transactional(propagation = Propagation.SUPPORTS) + public EnsResponseVO statBulkAll() { +// List intgrnSendMasts = intgrnSendMastRepository.findAllByStatCdIn(Arrays.asList(StatCd.sendok, StatCd.sendcmplt, StatCd.open)); + List intgrnSendMasts = intgrnSendMastRepository.findAllByStatCdInOrTryStatCdIn(Arrays.asList(StatCd.sendok, StatCd.sendcmplt, StatCd.open), Arrays.asList(TryStatCd.sndRsrv, TryStatCd.sndRtme)); + if (intgrnSendMasts.size() < 1) + return EnsResponseVO.errBuilder() + .errCode(EnsErrCd.RSLT404) +// .errMsg("\"전송성공/전송완료/열람중(sendok/sendcmplt/open)\" 상태인 자료가 없습니다") + .errMsg("\"상태정보가 전송성공/전송완료/열람중(sendok/sendcmplt/open)\" or 현재 회차상태가 예약전송/실시간전송(sndRsrv/sndRtme)\" 상태인 자료가 없습니다") + .build(); + + return this.stat(intgrnSendMasts); + } + + private EnsResponseVO stat(List intgrnSendMasts) { + List resultInfo = intgrnSendMasts.stream() + .map(data -> intgrnNotiRsltFetcher.execute(data.getIntSendMastId())) + .collect(Collectors.toList()); + + return EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } + + /** + * 전송결과 제공 + * + * @param intSendMastId + * @return + */ + @Transactional(propagation = Propagation.SUPPORTS) + public EnsResponseVO sendResultProvide(Long intSendMastId) { + + return intgrnNotiRsltProvider.execute(intSendMastId); + } + + @Transactional + public EnsResponseVO> closed() { + List intgrnSendMastList = intgrnSendMastRepository.findAllByStatCdInAndCloseDtBefore(Arrays.asList(StatCd.sendcmplt, StatCd.open), LocalDateTime.now().minusDays(1)); + List intSendMastIds = intgrnSendMastList.stream() + .map(row -> { + row.setStatCd(StatCd.close); + return row.getIntSendMastId(); + }) + .collect(Collectors.toList()); + + return EnsResponseVO.>okBuilder() + .resultInfo(intSendMastIds) + .build(); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/event/IntgrnNotiSendEventListener.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/event/IntgrnNotiSendEventListener.java new file mode 100644 index 0000000..9f863fe --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/event/IntgrnNotiSendEventListener.java @@ -0,0 +1,83 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.event; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.IntgrnNotiService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; + +@Slf4j +@Component +@RequiredArgsConstructor +public class IntgrnNotiSendEventListener { + private final IntgrnNotiService intgrnNotiService; + + @Order(1) +// @EventListener + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void sendRealtime(IntgrnNotiSendRealtimeEvent event) { + event.getSendMastIds().stream() + .forEach(intSendMastId -> { + StringBuffer sb = new StringBuffer(); + sb.append("\n=======================================================") + .append("\n[ENS] 통합고지 실시간전송") + .append("\n요청ID: " + intSendMastId); + + EnsResponseVO responseVO = intgrnNotiService.remake(intSendMastId); + sb.append("\n제작 결과: " + responseVO.toString()); + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) { + sb.append("\n======================================================="); + log.info(sb.toString()); + return; + } + + responseVO = intgrnNotiService.sendBulk(intSendMastId); + sb.append("\n전송요청 결과: " + responseVO.toString()); + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) { + sb.append("\n======================================================="); + log.info(sb.toString()); + return; + } + + responseVO = intgrnNotiService.statBulk(intSendMastId); + sb.append("\n상태갱신 결과: " + responseVO.toString()); + sb.append("\n======================================================="); + log.info(sb.toString()); + + if (event.getCallback() != null) + event.getCallback().execute(); + }); + } + + + @Async + @Order(1) + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void sendReserve(IntgrnNotiSendReserveEvent event) { + event.getSendMastIds().stream() + .forEach(intSendMastId -> { + StringBuffer sb = new StringBuffer(); + + EnsResponseVO responseVO = intgrnNotiService.remake(intSendMastId); + sb.append("\n=======================================================") + .append("\n[ENS] 통합고지 예약전송") + .append("\n요청ID: " + intSendMastId) + .append("\n제작 결과: " + responseVO.toString()); + + responseVO = intgrnNotiService.sendBulk(intSendMastId); + sb.append("\n-------------------------------------------------------") + .append("\n요청ID: " + intSendMastId) + .append("\n전송 결과: " + responseVO.toString()) + .append("\n======================================================="); + log.info(sb.toString()); + + if (event.getCallback() != null) + event.getCallback().execute(); + }); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/event/IntgrnNotiSendRealtimeEvent.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/event/IntgrnNotiSendRealtimeEvent.java new file mode 100644 index 0000000..6600378 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/event/IntgrnNotiSendRealtimeEvent.java @@ -0,0 +1,17 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.event; + +import cokr.xit.ens.core.eventlistner.adaptor.EnsAMSCallbackAdaptor; +import lombok.Builder; +import lombok.Getter; + +import java.util.List; + +@Builder +@Getter +public class IntgrnNotiSendRealtimeEvent { + + private List sendMastIds; + + private EnsAMSCallbackAdaptor callback; + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/event/IntgrnNotiSendReserveEvent.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/event/IntgrnNotiSendReserveEvent.java new file mode 100644 index 0000000..968a157 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/event/IntgrnNotiSendReserveEvent.java @@ -0,0 +1,17 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.event; + +import cokr.xit.ens.core.eventlistner.adaptor.EnsAMSCallbackAdaptor; +import lombok.Builder; +import lombok.Getter; + +import java.util.List; + +@Builder +@Getter +public class IntgrnNotiSendReserveEvent { + + private List sendMastIds; + + private EnsAMSCallbackAdaptor callback; + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/event/SendMastStatUpdateEventListener.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/event/SendMastStatUpdateEventListener.java new file mode 100644 index 0000000..256038d --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/event/SendMastStatUpdateEventListener.java @@ -0,0 +1,34 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.event; + +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.IntgrnNotiService; +import cokr.xit.ens.modules.common.event.SendMastStatUpdateEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; + +@Slf4j +@Component +@RequiredArgsConstructor +public class SendMastStatUpdateEventListener { + private final IntgrnNotiService intgrnNotiService; + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + + + @Async + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + public void IntgrnNotiStatUpdate(SendMastStatUpdateEvent event) { + + Long intSendMastId = intgrnSendDetailRepository.findIntSendMastIdBySendMastId(event.getSendMastId()).orElse(-999L); + StringBuffer sb = new StringBuffer(); + sb.append("\n=======================================================") + .append("\n[ENS Intgrn] 통합고지 상태갱신") + .append("\n요청ID: {}") + .append("\n상태갱신 결과: {}") + .append("\n======================================================="); + log.info(sb.toString(), intSendMastId, intgrnNotiService.statBulk(intSendMastId).toString()); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/strategy/TmpltMngStrategyIntegration.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/strategy/TmpltMngStrategyIntegration.java new file mode 100644 index 0000000..c429920 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/strategy/TmpltMngStrategyIntegration.java @@ -0,0 +1,186 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.strategy; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.TmpltMngIntgrn; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.TmpltMngIntgrnRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.TmpltMngIntgrnDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.struct.TmpltMngIntgrnMapper; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.ids.TmpltMngIds; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.OrgMngRepository; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.TmpltMngRepository; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngSearchDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.service.strategy.TmpltMngStrategyTemplate; +import cokr.xit.ens.modules.kkoalimtalk.domain.TmpltMngKkoAlimtalk; +import cokr.xit.ens.modules.kkoalimtalk.model.struct.TmpltMngKkoAlimtalkMapper; +import cokr.xit.ens.modules.kkomydoc.domain.TmpltMngKkoMydoc; +import cokr.xit.ens.modules.kkomydoc.model.struct.TmpltMngKkoMydocMapper; +import cokr.xit.ens.modules.nvsigntalk.domain.TmpltMngNvSigntalk; +import cokr.xit.ens.modules.nvsigntalk.model.struct.TmpltMngNvSigntalkMapper; +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.RequiredArgsConstructor; +import org.mapstruct.factory.Mappers; +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.*; +import java.util.stream.Collectors; + +@Component("tmpltMngStrategy_intgrn") +@RequiredArgsConstructor +public class TmpltMngStrategyIntegration extends TmpltMngStrategyTemplate, TmpltMngIntgrnDTO> { + + private final OrgMngRepository orgMngRepository; + private final TmpltMngRepository tmpltMngRepository; + private final TmpltMngIntgrnRepository tmpltMngIntgrnRepository; + private final cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.TmpltMngKkoAlimtalkMapper tmpltMngKkoAlimtalkMapper; + private final cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.TmpltMngKkoMydocMapper tmpltMngKkoMydocMapper; + private final cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.TmpltMngNvSigntalkMapper tmpltMngNvSigntalkMapper; +// private final RedisTemplate redisTemplate; + + private TmpltMngIntgrnMapper intgrnMapper = Mappers.getMapper(TmpltMngIntgrnMapper.class); + + @Override + public List findAll(TmpltMngSearchDTO tmpltMngSearchDTO) { + return tmpltMngIntgrnRepository.findAllDtoBySearchDTO(tmpltMngSearchDTO); + } + + @Override + public Optional find(String orgCd, String tmpltCd) { + return tmpltMngIntgrnRepository.findDtoByOrgCdAndTmpltCd(orgCd, tmpltCd); + +// String key = super.pushCache(redisTemplate, orgCd, tmpltCd, tmpltMngIntgrnRepository); +// HashOperations hashOperations = redisTemplate.opsForHash(); +// return Optional.ofNullable(hashOperations.entries(KEY).get(key)); + } + + @Override + protected TmpltMngIntgrnDTO validate(Map params) { + try { + if (params.getOrDefault("nvSigntalk", null) != null) { + Map nvSigntalk = (Map) params.get("nvSigntalk"); + if (nvSigntalk.getOrDefault("messageDataFmt", null) != null) + nvSigntalk.put("messageDataFmt", mapper.writeValueAsString(nvSigntalk.get("messageDataFmt"))); + } + + TmpltMngIntgrnDTO dto = mapper.convertValue(params, TmpltMngIntgrnDTO.class); + if (!CmmnUtil.isEmpty(dto.getKkoAlimtalk())) + this.toMappedChildTmpltMng(dto, dto.getKkoAlimtalk()); + if (!CmmnUtil.isEmpty(dto.getKkoMydoc())) + this.toMappedChildTmpltMng(dto, dto.getKkoMydoc()); + if (!CmmnUtil.isEmpty(dto.getNvSigntalk())) + this.toMappedChildTmpltMng(dto, dto.getNvSigntalk()); + + final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + Set> list = validator.validate(dto); + if (list.size() > 0) { + throw new EnsException(EnsErrCd.ERR410, "유효하지 않은 요청 값 입니다.", list.stream() + .map(row -> String.format("%s [ %s ]", row.getMessageTemplate(), row.getPropertyPath())) + .collect(Collectors.toList()) + ); + } + return dto; + } catch (IllegalArgumentException e) { + List fields = Arrays.stream(TmpltMngDTO.class.getDeclaredFields()).map(row -> row.getName()).collect(Collectors.toList()); + fields.addAll(Arrays.stream(TmpltMngIntgrnDTO.class.getDeclaredFields()).map(row -> row.getName()).collect(Collectors.toList())); + throw new EnsException(EnsErrCd.ERR403, "유효하지 않은 파라미터 입니다. 사용가능한 파라미터는 resultInfo 를 참고하시기 바랍니다.", fields); + } catch (JsonProcessingException e) { + throw new EnsException(EnsErrCd.ERR403, "nvSigntalk.messageDataFmt 변환에 실패했습니다."); + } + + } + + @Override + protected void addProc(TmpltMngIntgrnDTO dto) { + OrgMng orgMng = orgMngRepository.findById(dto.getOrgCd()).orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("기관코드(%s)가 일치하는 자료가 없습니다.", dto.getOrgCd()))); + tmpltMngRepository.findFetchByOrgCdAndTmpltCd(dto.getOrgCd(), dto.getTmpltCd()) + .ifPresent(tmpltMng -> { + throw new EnsException(EnsErrCd.ERR540, String.format("이미 등록된 템플릿코드[기관코드 %s 템플릿코드 %s] 입니다.", tmpltMng.getOrgMng().getOrgCd(), tmpltMng.getTmpltCd())); + }); + + TmpltMngIntgrn tmpltMng = intgrnMapper.toEntity(dto); + tmpltMng.setOrgMng(orgMng); + tmpltMng.setRegistId("ENS_SYS"); + tmpltMngIntgrnRepository.saveAndFlush(tmpltMng); + + if (!CmmnUtil.isEmpty(dto.getKkoAlimtalk())) { + TmpltMngKkoAlimtalkMapper mapper = Mappers.getMapper(TmpltMngKkoAlimtalkMapper.class); + TmpltMngKkoAlimtalk tmpltChild = mapper.toEntity(dto.getKkoAlimtalk()); + tmpltMngKkoAlimtalkMapper.add(tmpltChild); + } + if (!CmmnUtil.isEmpty(dto.getKkoMydoc())) { + TmpltMngKkoMydocMapper mapper = Mappers.getMapper(TmpltMngKkoMydocMapper.class); + TmpltMngKkoMydoc tmpltChild = mapper.toEntity(dto.getKkoMydoc()); + tmpltMngKkoMydocMapper.add(tmpltChild); + } + if (!CmmnUtil.isEmpty(dto.getNvSigntalk())) { + TmpltMngNvSigntalkMapper mapper = Mappers.getMapper(TmpltMngNvSigntalkMapper.class); + TmpltMngNvSigntalk tmpltChild = mapper.toEntity(dto.getNvSigntalk()); + tmpltMngNvSigntalkMapper.add(tmpltChild); + } + + + } + + @Override + protected void modifyProc(TmpltMngIntgrnDTO dto) { + TmpltMngIntgrn tmpltMng = tmpltMngIntgrnRepository.findFetchByOrgCdAndTmpltCd(dto.getOrgCd(), dto.getTmpltCd()) + .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("기관코드(%s) 및 템플릿코드(%s)가 일치하는 자료가 없습니다.", dto.getOrgCd(), dto.getTmpltCd()))); + intgrnMapper.updateFromDto(dto, tmpltMng); + tmpltMng.setUpdId("ENS_SYS"); + + + if (!CmmnUtil.isEmpty(dto.getKkoAlimtalk())) { + TmpltMngKkoAlimtalkMapper mapper = Mappers.getMapper(TmpltMngKkoAlimtalkMapper.class); + TmpltMngKkoAlimtalk tmpltChild = mapper.toEntity(dto.getKkoAlimtalk()); + if (tmpltMngKkoAlimtalkMapper.findById(TmpltMngIds.builder().orgMng(dto.getOrgCd()).tmpltCd(dto.getTmpltCd()).build()).isPresent()) { + tmpltChild.setUpdId("ENS_SYS"); + tmpltMngKkoAlimtalkMapper.modify(tmpltChild); + } else { + tmpltChild.setRegistId("ENS_SYS"); + tmpltMngKkoAlimtalkMapper.add(tmpltChild); + } + } + + if (!CmmnUtil.isEmpty(dto.getKkoMydoc())) { + TmpltMngKkoMydocMapper mapper = Mappers.getMapper(TmpltMngKkoMydocMapper.class); + TmpltMngKkoMydoc tmpltChild = mapper.toEntity(dto.getKkoMydoc()); + if (tmpltMngKkoMydocMapper.findById(TmpltMngIds.builder().orgMng(dto.getOrgCd()).tmpltCd(dto.getTmpltCd()).build()).isPresent()) { + tmpltChild.setUpdId("ENS_SYS"); + tmpltMngKkoMydocMapper.modify(tmpltChild); + } else { + tmpltChild.setRegistId("ENS_SYS"); + tmpltMngKkoMydocMapper.add(tmpltChild); + } + } + + if (!CmmnUtil.isEmpty(dto.getNvSigntalk())) { + TmpltMngNvSigntalkMapper mapper = Mappers.getMapper(TmpltMngNvSigntalkMapper.class); + TmpltMngNvSigntalk tmpltChild = mapper.toEntity(dto.getNvSigntalk()); + if (tmpltMngNvSigntalkMapper.findById(TmpltMngIds.builder().orgMng(dto.getOrgCd()).tmpltCd(dto.getTmpltCd()).build()).isPresent()) { + tmpltChild.setUpdId("ENS_SYS"); + tmpltMngNvSigntalkMapper.modify(tmpltChild); + } else { + tmpltChild.setRegistId("ENS_SYS"); + tmpltMngNvSigntalkMapper.add(tmpltChild); + } + } + +// super.deleteCache(redisTemplate, dto.getOrgCd(), dto.getTmpltCd()); + } + + private void toMappedChildTmpltMng(TmpltMngIntgrnDTO dto, TmpltMngDTO childDto) { + childDto.setOrgCd(dto.getOrgCd()); + childDto.setTmpltCd(dto.getTmpltCd()); + childDto.setTitle(dto.getTitle()); + childDto.setMessage(dto.getMessage()); + childDto.setUseYn(dto.getUseYn()); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/AcceptData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/AcceptData.java new file mode 100644 index 0000000..18ab592 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/AcceptData.java @@ -0,0 +1,31 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support; + +import cokr.xit.ens.core.utils.MapDeserailizer; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.RequiredArgsConstructor; + +import java.util.List; +import java.util.Map; + +@RequiredArgsConstructor +public abstract class AcceptData { + + protected final Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).disableHtmlEscaping().create(); + + protected final IntgrnSendMast intgrnSendMast; + protected final List intgrnSendDetails; + protected final Boolean isReserveSend; + + public abstract T createReqDto(); + + public List getIntgrnSendDetails() { + return this.intgrnSendDetails; + } + public Boolean IsReserveSend() { + return this.isReserveSend; + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/AcceptDataEventListener.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/AcceptDataEventListener.java new file mode 100644 index 0000000..b7b7a50 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/AcceptDataEventListener.java @@ -0,0 +1,80 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.MapDeserailizer; +import cokr.xit.ens.modules.common.code.IntgrnDtlStatCd; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; + +public interface AcceptDataEventListener { + + + @Async + @EventListener + @Transactional + void accept(P p); + + default void acceptFail(List intgrnSendDetails, PostSeCd postSeCd, EnsErrCd ensErrCd, String errMsg) { + intgrnSendDetails.forEach(data -> { + data.setCurPostSe(postSeCd); + data.setCurStatCd(IntgrnDtlStatCd.ACPT_FAIL); + data.setError(FieldError.initBuilder() + .errorCode(ensErrCd.getCode()) + .errorMessage(errMsg) + .build()); + }); + } + + default void acceptSuccess(List intgrnSendDetails, PostSeCd postSeCd, Map sendDetailIdMap) { + + intgrnSendDetails.forEach(data -> { + if (sendDetailIdMap.containsKey(data.getLinkedUuid())) { + data.setCurPostSe(postSeCd); + data.setCurStatCd(IntgrnDtlStatCd.ACPT_OK); + setSendDetailId(data, sendDetailIdMap.get(data.getLinkedUuid())); + data.setError(FieldError.initBuilder().build()); + } + }); + + } + + Map convertSendDetailIdMap(List sendDetails); + + void setSendDetailId(IntgrnSendDetail intgrnSendDetail, Long sendDetailId); + +// EnsResponseVO fetch(Long sendMastId, List sendDetails); + + default String createFailMessage(Long intSendMastId, PostSeCd postSeCd, EnsResponseVO responseVO) { + StringBuffer sb = new StringBuffer(); + sb.append("-.IntSendMastId: " + intSendMastId) + .append(System.getProperty("line.separator")) + .append("-.PostType: " + postSeCd.getCodeNm()) + .append(System.getProperty("line.separator")) + .append(responseVO.getErrMsg()); + if (EnsErrCd.ACPT402.equals(responseVO.getErrCode())) { + sb.append(System.getProperty("line.separator")) + .append("-.ValidateFails: "); + try { +// ((List) responseVO.getResultInfo()).forEach(str -> sb.append(System.getProperty("line.separator")).append(str)); + if (responseVO.getResultInfo() instanceof List || responseVO.getResultInfo() instanceof Map){ + Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).disableHtmlEscaping().create(); + sb.append(gson.toJson(responseVO.getResultInfo())); + } + } catch (Exception e) { + sb.append("VaildateFails message is create fail.. " + e.getMessage()); + } + } + return sb.toString(); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/AcceptDataFactory.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/AcceptDataFactory.java new file mode 100644 index 0000000..8609494 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/AcceptDataFactory.java @@ -0,0 +1,11 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support; + + +import cokr.xit.ens.modules.common.code.PostSeCd; + +public abstract class AcceptDataFactory { + + + abstract public T get(PostSeCd postSeCd); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/AcceptDataMakerFactory.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/AcceptDataMakerFactory.java new file mode 100644 index 0000000..c788351 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/AcceptDataMakerFactory.java @@ -0,0 +1,39 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support; + +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.kkoalimtalk.AcceptDataByKkoAlimtalk; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.kkomydoc.AcceptDataByKkoMydoc; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.ktGibis.AcceptDataByKtGibis; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.ktSigntalk.AcceptDataByKtSigntalk; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.nvsigntalk.AcceptDataByNvSigntalk; +import lombok.RequiredArgsConstructor; + +import java.util.List; + +@RequiredArgsConstructor +public class AcceptDataMakerFactory extends AcceptDataFactory { + private final IntgrnSendMast sendMast; + private final List sendDetails; + + private final Boolean isReserveSend; + + @Override + public AcceptData get(PostSeCd postSeCd) { + switch (postSeCd) { + case kkoAlimtalk: + return new AcceptDataByKkoAlimtalk(sendMast, sendDetails, isReserveSend); + case kkoMydoc: + return new AcceptDataByKkoMydoc(sendMast, sendDetails, isReserveSend); + case nvSigntalk: + return new AcceptDataByNvSigntalk(sendMast, sendDetails, isReserveSend); + case ktSigntalk: + return new AcceptDataByKtSigntalk(sendMast, sendDetails, isReserveSend); + case ktGibis: + return new AcceptDataByKtGibis(sendMast, sendDetails, isReserveSend); + default: + throw new IllegalAccessError(postSeCd.getCode() + "에 대한 전자고지 접수 Class가 정의되지 않았습니다."); + } + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiAcceptor.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiAcceptor.java new file mode 100644 index 0000000..6d253bd --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiAcceptor.java @@ -0,0 +1,276 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.utils.DateUtil; +import cokr.xit.ens.core.utils.IdGenerator; +import cokr.xit.ens.core.utils.MapDeserailizer; +import cokr.xit.ens.core.utils.crypto.AES256; +import cokr.xit.ens.core.utils.crypto.Crypto; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.common.code.IntgrnDtlStatCd; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.code.VenderCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.repository.BillRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.code.TryStatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendMastRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnNotiAcceptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.TmpltMngIntgrnDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.service.OrgMngService; +import cokr.xit.ens.modules.common.ctgy.sys.mng.service.TmpltMngService; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class IntgrnNotiAcceptor implements EnsPhaseProcSupport { + private final IntgrnSendMastRepository intgrnSendMastRepository; + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + private final BillRepository billRepository; + private final OrgMngService orgMngService; + private final TmpltMngService tmpltMngService; + + private Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).disableHtmlEscaping().create(); + + @Override + public EnsResponseVO statReady(List reqDTOs) { + log.info("no process"); + return null; + } + + @Override + public EnsResponseVO statBegin(IntgrnNotiAcceptReqDTO reqDTO) { + final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + Set> list = validator.validate(reqDTO); + if (list.size() > 0) { + return EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ACPT402) + .errMsg("유효하지 않은 요청값 입니다.") + .resultInfo(list.stream() + .map(row -> String.format("%s [ %s ]", row.getMessageTemplate(), row.getPropertyPath())) + .collect(Collectors.toList())) + .build(); + } + List expiredDateValidateList = expiredDateVaildate(reqDTO); + if (expiredDateValidateList.size() > 0) { + return EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ACPT402) + .errMsg("유효하지 않은 유효기한 입니다. 자료의 유효기한은 마감일시 이내이어야 합니다.") + .resultInfo(expiredDateValidateList) + .build(); + } + EnsResponseVO orgMng = orgMngService.find(reqDTO.getOrg_cd()); + if (!EnsErrCd.OK.equals(orgMng.getErrCode())) + return EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ACPT404) + .errMsg("일치하는 기관정보가 없습니다.") + .resultInfo(orgMng.getErrMsg()) + .build(); + EnsResponseVO tmpltMng = tmpltMngService.find(reqDTO.getOrg_cd(), reqDTO.getTmplt_cd(), "intgrn"); + if (!EnsErrCd.OK.equals(tmpltMng.getErrCode())) + return EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ACPT404) + .errMsg("일치하는 템플릿정보가 없습니다.") + .resultInfo(tmpltMng.getErrMsg()) + .build(); + + + return EnsResponseVO.okBuilder().build(); + } + + private List expiredDateVaildate(IntgrnNotiAcceptReqDTO reqDTO) { + List result = new ArrayList<>(); + + AtomicInteger i = new AtomicInteger(); + reqDTO.getDocuments().forEach(document -> { + if (!CmmnUtil.isEmpty(document.getAcpt_data().getKko_md())) { + if (!CmmnUtil.isEmpty(document.getAcpt_data().getKko_md().getRead_expired_at())) { + String expDate = DateUtil.absTimeSecToDate(document.getAcpt_data().getKko_md().getRead_expired_at(), "yyyyMMddHHmmss"); + int sec = DateUtil.secByFromBetweenTo(DateUtil.toLocalDateTime(expDate), DateUtil.toLocalDateTime(reqDTO.getClose_dt())); + if (sec < 0) + result.add(String.format("마감일시보다 \"처리마감시간(절대시간)\"이 느립니다. [ document[%d].acpt_data.kko_md.read_expired_at ]", i.get())); + } + if (!CmmnUtil.isEmpty(document.getAcpt_data().getKko_md().getRead_expired_sec())) { + String expDate = DateUtil.addRelTimeSecToDate(DateUtil.toLocalDateTime(reqDTO.getSend_dt()), document.getAcpt_data().getKko_md().getRead_expired_sec(), "yyyyMMddHHmmss"); + int sec = DateUtil.secByFromBetweenTo(DateUtil.toLocalDateTime(expDate), DateUtil.toLocalDateTime(reqDTO.getClose_dt())); + if (sec < 0) + result.add(String.format("마감일시보다 \"처리마감시간(상대시간)\"이 느립니다. [ document[%d].acpt_data.kko_md.read_expired_sec ]", i.get())); + } + } + if (!CmmnUtil.isEmpty(document.getAcpt_data().getNv_st())) { + if (!CmmnUtil.isEmpty(document.getAcpt_data().getNv_st().getValid_duration_at())) { + String expDate = DateUtil.absTimeSecToDate(document.getAcpt_data().getNv_st().getValid_duration_at(), "yyyyMMddHHmmss"); + int sec = DateUtil.secByFromBetweenTo(DateUtil.toLocalDateTime(expDate), DateUtil.toLocalDateTime(reqDTO.getClose_dt())); + if (sec < 0) + result.add(String.format("마감일시보다 \"고지서 열람 유효시간(초)-절대시간\"이 느립니다. [ document[%d].acpt_data.nv_st.valid_duration_at ]", i.get())); + } + if (!CmmnUtil.isEmpty(document.getAcpt_data().getNv_st().getValid_duration())) { + String expDate = DateUtil.addRelTimeSecToDate(DateUtil.toLocalDateTime(reqDTO.getSend_dt()), document.getAcpt_data().getNv_st().getValid_duration().intValue(), "yyyyMMddHHmmss"); + int sec = DateUtil.secByFromBetweenTo(DateUtil.toLocalDateTime(expDate), DateUtil.toLocalDateTime(reqDTO.getClose_dt())); + if (sec < 0) + result.add(String.format("마감일시보다 \"고지서 열람 유효시간(초)-상대시간\"이 느립니다. [ document[%d].acpt_data.nv_st.valid_duration ]", i.get())); + } + } + if (!CmmnUtil.isEmpty(document.getAcpt_data().getKt_st())) { + if (!CmmnUtil.isEmpty(document.getAcpt_data().getKt_st().getExTime())) { + String expDate = document.getAcpt_data().getKt_st().getExTime(); + int sec = DateUtil.secByFromBetweenTo(DateUtil.toLocalDateTime(expDate), DateUtil.toLocalDateTime(reqDTO.getClose_dt())); + if (sec < 0) + result.add(String.format("마감일시보다 \"처리마감시간\"이 느립니다. [ document[%d].acpt_data.kt_st.extTime ]", i.get())); + } + + } + i.getAndIncrement(); + }); + + return result; + } + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO> execute(IntgrnNotiAcceptReqDTO reqDTO) throws EnsException { + AES256 aes256 = new AES256(Crypto.AES256.getKey()); + EnsResponseVO responseVO = null; + try { + final TmpltMngIntgrnDTO tmpltMngIntgrnDTO = (TmpltMngIntgrnDTO) tmpltMngService.find(reqDTO.getOrg_cd(), reqDTO.getTmplt_cd(), "intgrn").getResultInfo(); + + + int tryCnt = 0; + if (!CmmnUtil.isEmpty(tmpltMngIntgrnDTO.getTry1())) tryCnt++; + if (!CmmnUtil.isEmpty(tmpltMngIntgrnDTO.getTry2())) tryCnt++; + if (!CmmnUtil.isEmpty(tmpltMngIntgrnDTO.getTry3())) tryCnt++; + IntgrnSendMast intgrnSendMast = IntgrnSendMast.builder() + .vender(VenderCd.valueOfEnum(reqDTO.getVender())) + .orgCd(reqDTO.getOrg_cd()) + .tmpltCd(reqDTO.getTmplt_cd()) + .postBundleTitle(reqDTO.getPost_bundle_title()) + .statCd(StatCd.accept) + .sendDt(DateUtil.toLocalDateTime(reqDTO.getSend_dt())) + .sendCnt(reqDTO.getDocuments().size()) + .closeDt(DateUtil.toLocalDateTime(reqDTO.getClose_dt())) + .try1(tmpltMngIntgrnDTO.getTry1()) + .try2(tmpltMngIntgrnDTO.getTry2()) + .try3(tmpltMngIntgrnDTO.getTry3()) + .tryCnt(tryCnt) + .trySeq(0) + .tryStatCd(TryStatCd.stby) + .build(); + intgrnSendMastRepository.save(intgrnSendMast); + + + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + List intgrnSendDetails = new ArrayList<>(); + List bills = new ArrayList<>(); + final String prefixBillUid = PostSeCd.intgrnNoti.getCode() + "-" + IdGenerator.getCurrentTimeSec(); + AtomicInteger i = new AtomicInteger(); + reqDTO.getDocuments().forEach(document -> { + i.getAndIncrement(); + try { + + Bill bill = null; + if (!CmmnUtil.isEmpty(document.getXit_property()) + && !CmmnUtil.isEmpty(document.getXit_property().getBill_acpt_data())) { +// if (document.getXit_property().getBill_acpt_data().getUse_bill_uid()) { + if (!CmmnUtil.isEmpty(document.getXit_property().getBill_acpt_data().getBillUid())) { + bill = billRepository.findByBillUid(document.getXit_property().getBill_acpt_data().getBillUid()) + .orElseThrow(() -> new RuntimeException("등록된 청구서가 없습니다.")); + } else { + bill = Bill.builder() +// .billId(document.getXit_property().getBill_acpt_data().getBill_id()) + .billId(null) + .billUid(IdGenerator.getShortUUID(prefixBillUid)) + .billerUserKey(document.getXit_property().getBill_acpt_data().getBillerUserKey()) + .billSeCd(document.getXit_property().getBill_acpt_data().getBillSe()) + .orgMng(OrgMng.builder().orgCd(reqDTO.getOrg_cd()).build()) +// .docBillKko(CmmnUtil.isEmpty(document.getXit_property().getBill_acpt_data().getBill_kko()) ? null : gson.toJson(document.getXit_property().getBill_acpt_data().getBill_kko())) +// .docBillNv(CmmnUtil.isEmpty(document.getXit_property().getBill_acpt_data().getBill_nv()) ? null : gson.toJson(document.getXit_property().getBill_acpt_data().getBill_nv())) + .build(); + } + bills.add(bill); + } + + IntgrnSendDetail sendDetail = IntgrnSendDetail.builder() + .intgrnSendMast(intgrnSendMast) + .linkedUuid(document.getLinked_uuid()) + .ci(document.getReceiver().getCi()) +// .jid(document.getReceiver().getJid()) + .jid(aes256.encrypt(document.getReceiver().getJid())) + .mblphonNo(document.getReceiver().getMblphon_no()) + .jTmpltMsgData(CmmnUtil.isEmpty(document.getXit_property().getTmplt_msg_data()) ? null : gson.toJson(document.getXit_property().getTmplt_msg_data())) + .jMblPageData(CmmnUtil.isEmpty(document.getXit_property().getMbl_page_data()) ? null : gson.toJson(document.getXit_property().getMbl_page_data())) + .jAcptDocKkoAt(CmmnUtil.isEmpty(document.getAcpt_data().getKko_at()) ? null : gson.toJson(document.getAcpt_data().getKko_at())) + .jAcptDocKkoMd(CmmnUtil.isEmpty(document.getAcpt_data().getKko_md()) ? null : gson.toJson(document.getAcpt_data().getKko_md())) + .jAcptDocNvSt(CmmnUtil.isEmpty(document.getAcpt_data().getNv_st()) ? null : gson.toJson(document.getAcpt_data().getNv_st())) + .jAcptDocKtSt(CmmnUtil.isEmpty(document.getAcpt_data().getKt_st()) ? null : gson.toJson(document.getAcpt_data().getKt_st())) + .jAcptDocKtGbs(CmmnUtil.isEmpty(document.getAcpt_data().getKt_gbs()) ? null : gson.toJson(document.getAcpt_data().getKt_gbs())) + .curPostSe(tmpltMngIntgrnDTO.getTry1()) + .curStatCd(IntgrnDtlStatCd.REG) + .sendDetailIdKkoAt(null) + .sendDetailIdKkoMd(null) + .sendDetailIdNvSt(null) + .sendDetailIdKtSt(null) + .sendDetailIdKtGbs(null) + .mkBillUseYn(CmmnUtil.isEmpty(bill) ? "N" : "Y") +// .mkBillUid(bill == null ? null : bill.getBillUid()) + .bill(bill) + .build(); + intgrnSendDetails.add(sendDetail); + + } catch (Exception e) { + throw new EnsException(EnsErrCd.ACPT500, String.format("%d번째 데이터 접수처리 중 오류 발생. 실패사유: %s", i.get(), e.getMessage())); + } + }); + if (CmmnUtil.isEmpty(intgrnSendDetails)) + throw new EnsException(EnsErrCd.ACPT410, "발송상세 자료가 없습니다."); + + + billRepository.saveAll(bills.stream() + .filter(row -> CmmnUtil.isEmpty(row.getBillId())) + .collect(Collectors.toList()) + ); + intgrnSendDetailRepository.saveAll(intgrnSendDetails); + + +// MakerFactory makerFactory = new AcceptDataMakerFactory(intgrnSendMast, intgrnSendDetails, true); +// +// applicationEventPublisher.publishEvent(makerFactory.get(reqDTO.getTry1())); +// +// intgrnSendMast.setTrySeq(1); +// intgrnSendMast.setTryStatCd(TryStatCd.sndRsrv); +// intgrnSendMastRepository.save(intgrnSendMast); + + Map resultInfo = new HashMap<>(); + resultInfo.put("intSendMastId", intgrnSendMast.getIntSendMastId()); + responseVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } catch (EnsException e) { + throw e; + } catch (Exception e) { + throw new EnsException(EnsErrCd.ACPT500, String.format("오류가 발생하여 접수에 실패 했습니다. 실패사유: %s", e.getMessage())); + } + + return responseVO; + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiMaker.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiMaker.java new file mode 100644 index 0000000..c04d95b --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiMaker.java @@ -0,0 +1,203 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.monitor.slack.event.MonitorEvent; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.biztmplt.MakeProcTemplate; +import cokr.xit.ens.modules.common.code.IntgrnDtlStatCd; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.code.TryStatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendMastRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.TmpltMngIntgrnDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.strategy.TmpltMngStrategyIntegration; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import cokr.xit.ens.modules.common.monitor.MessageByPhase; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class IntgrnNotiMaker extends MakeProcTemplate { + private final IntgrnSendMastRepository intgrnSendMastRepository; + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + private final TmpltMngStrategyIntegration tmpltMngService; + private final ApplicationEventPublisher applicationEventPublisher; + + + /** + * 제작준비 + * + * @param intSendMastIds + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List intSendMastIds) { + EnsResponseVO respVO = null; + try { + /** + * 필수값 확인 + */ + if (CmmnUtil.isEmpty(intSendMastIds)) + throw new EnsException(EnsErrCd.MAKE410, "발송마스터ID(은)는 필수조건 입니다."); + + /** + * 저장 + * -. 발송마스터의 상태를 "제작준비(makerdy)" 으로 변경 한다. + */ + List resultInfo = intgrnSendMastRepository.findAllByIntSendMastIdIn(intSendMastIds).stream() + .map(row -> { + row.setStatCd(StatCd.makerdy); + return row.getIntSendMastId(); + }) + .collect(Collectors.toList()); + ; + + respVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } catch (EnsException e) { + + respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(); + } catch (Exception e) { + + respVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.MAKE500).errMsg(e.getMessage()).build(); + } + + return respVO; + } + + + /** + * 제작시작 + * + * @param intSendMastId + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(Long intSendMastId) { + + EnsResponseVO respVO = null; + try { + /** + * 필수값 확인 + */ + if (CmmnUtil.isEmpty(intSendMastId)) + throw new EnsException(EnsErrCd.MAKE410, "발송마스터ID(은)는 필수조건 입니다."); + + /** + * 저장 + * -. 발송마스터의 상태를 "제작중(making)" 으로 변경 한다. + */ + IntgrnSendMast intgrnSendMast = intgrnSendMastRepository.findById(intSendMastId).orElseThrow(() -> new EnsException(EnsErrCd.MAKE404, String.format("일치하는 발송마스터 자료가 없습니다. [ intSendMastId %s ]", intSendMastId))); + intgrnSendMast.setStatCd(StatCd.making); + + + respVO = EnsResponseVO.okBuilder().resultInfo(intSendMastId).build(); + } catch (EnsException e) { + + respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(); + } catch (Exception e) { + + respVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.MAKE500).errMsg(e.getMessage()).build(); + } + + return respVO; + } + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(Long intSendMastId) { + IntgrnSendMast intgrnSendMast = null; + List intgrnSendDetails = null; + EnsResponseVO respVO = null; + try { + if (CmmnUtil.isEmpty(intSendMastId)) + throw new EnsException(EnsErrCd.MAKE410, "발송마스터ID(은)는 필수조건 입니다."); + + intgrnSendMast = intgrnSendMastRepository.findById(intSendMastId) + .orElseThrow(() -> new EnsException(EnsErrCd.MAKE404, String.format("일치하는 발송마스터 자료가 없습니다. [ intSendMastId %s ]", intSendMastId))); + intgrnSendDetails = intgrnSendDetailRepository.findAllByIntgrnSendMast(intgrnSendMast); + IntgrnSendMast finalIntgrnSendMast = intgrnSendMast; + TmpltMngIntgrnDTO tmpltMngDTO = tmpltMngService.find(intgrnSendMast.getOrgCd(), intgrnSendMast.getTmpltCd()) + .orElseThrow(() -> new EnsException(EnsErrCd.MAKE404, String.format("일치하는 템플릿 자료가 없습니다. [ intSendMastId %s orgCd %s TmpltCd %s ]", intSendMastId, finalIntgrnSendMast.getOrgCd(), finalIntgrnSendMast.getTmpltCd()))); + if (!"Y".equals(tmpltMngDTO.getUseYn())) + throw new EnsException(EnsErrCd.MAKE521, String.format("미사용 상태의 템플릿 입니다. [ intSendMastId %s orgCd %s TmpltCd %s ]", intSendMastId, finalIntgrnSendMast.getOrgCd(), finalIntgrnSendMast.getTmpltCd())); + + + Optional cntSuccess = intgrnSendDetails.stream() + .map(row -> { + try { + row.setCurStatCd(IntgrnDtlStatCd.MAKING); + + row.setError(FieldError.initBuilder().build()); + + return 1; + } catch (EnsException e) { + row.setError(FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()); + return 0; + } + }) + .reduce(Integer::sum); + + + + if (cntSuccess.get() > 0) + respVO = EnsResponseVO.okBuilder().resultInfo(String.format("총 %d건 중 %d건 제작 성공. [ intSendMastId %s ]", intgrnSendDetails.size(), cntSuccess.get(), intSendMastId)).build(); + else + throw new EnsException(EnsErrCd.MAKE500, String.format("총 %d 건 제작 실패", intgrnSendDetails.size())); + } catch (EnsException e) { + + respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(); + } catch (Exception e) { + + respVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.MAKE500).errMsg(e.getMessage()).build(); + } finally { + if (!CmmnUtil.isEmpty(intgrnSendMast)) + if (EnsErrCd.OK.equals(respVO.getErrCode())) { + intgrnSendMast.setStatCd(StatCd.makeok); + intgrnSendMast.setTryStatCd(TryStatCd.stby); + intgrnSendMast.setError(FieldError.initBuilder().build()); + } else { + intgrnSendMast.setStatCd(StatCd.makefail); + intgrnSendMast.setError(FieldError.initBuilder() + .errorCode(respVO.getErrCode().getCode()) + .errorMessage(respVO.getErrMsg()) + .build()); + + applicationEventPublisher.publishEvent(MonitorEvent.builder() + .message(MessageByPhase.builder() + .oClass(getClass().getSimpleName() + "." + new Throwable().getStackTrace()[0].getMethodName()) + .postSeCd(PostSeCd.intgrnNoti) + .statCd(StatCd.makefail) + .errCd(respVO.getErrCode()) + .message("-.IntSendMastId: " + intSendMastId + "\n" + respVO.getErrMsg()) + .build()) + .build()); + } + } + + + return respVO; + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiRsltFetcher.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiRsltFetcher.java new file mode 100644 index 0000000..dcc41e1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiRsltFetcher.java @@ -0,0 +1,182 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.biztmplt.ResultProcTemplate; +import cokr.xit.ens.modules.common.code.IntgrnDtlStatCd; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.code.TryStatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendMastRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnDetailStatVO; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Component +@RequiredArgsConstructor +public class IntgrnNotiRsltFetcher extends ResultProcTemplate { + + private final IntgrnSendMastRepository intgrnSendMastRepository; + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(Long intSendMastId) { + + + IntgrnSendMast intgrnSendMast = null; + List sendDetails = null; + EnsResponseVO respVO = null; + Map resultInfo = new HashMap<>(); + resultInfo.put("intSendMastId", intSendMastId); + try { + if (CmmnUtil.isEmpty(intSendMastId)) + throw new EnsException(EnsErrCd.RSLT410, "발송마스터ID(은)는 필수조건 입니다."); + + intgrnSendMast = intgrnSendMastRepository.findById(intSendMastId).orElseThrow(() -> new EnsException(EnsErrCd.RSLT404, String.format("일치하는 발송마스터 자료가 없습니다. [ intSendMastId %s ]", intSendMastId))); + + + List list = intgrnSendDetailRepository.findIntgrnDetailStatVOsByIntSendMastIdAndCurPostSe(intgrnSendMast.getIntSendMastId()); + + intgrnSendDetailRepository.modifyDetailStatCdByIntgrnDetailStatVO(list); + + sendDetails = intgrnSendDetailRepository.findAllByIntgrnSendMast(intgrnSendMast); + + + + respVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } catch (EnsException e) { + + respVO = EnsResponseVO.errRsltBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).resultInfo(resultInfo).build(); + } catch (Exception e) { + + respVO = EnsResponseVO.errRsltBuilder().errCode(EnsErrCd.RSLT500).errMsg(e.getMessage()).resultInfo(resultInfo).build(); + } finally { + if (!CmmnUtil.isEmpty(intgrnSendMast)) + if (EnsErrCd.OK.equals(respVO.getErrCode())) { + intgrnSendMast.setError(FieldError.initBuilder().build()); + + + Integer readCnt = sendDetails.stream() + .map(row -> IntgrnDtlStatCd.READ.equals(row.getCurStatCd()) ? 1 : 0) + .reduce(Integer::sum) + .orElseGet(() -> 0); + intgrnSendMast.setReadCnt(readCnt); + + if (StatCd.sendok.equals(intgrnSendMast.getStatCd()) + || StatCd.sendcmplt.equals(intgrnSendMast.getStatCd())) { + if (readCnt > 0) + intgrnSendMast.setStatCd(StatCd.open); + else + intgrnSendMast.setStatCd(StatCd.sendcmplt); + } else if (StatCd.open.equals(intgrnSendMast.getStatCd()) + || StatCd.close.equals(intgrnSendMast.getStatCd())) { + } else { + int sendOkCnt = 0; + int sendFailCnt = 0; + + + for (IntgrnSendDetail sendDetail : sendDetails) { + if (sendDetail.getCurStatCd().isSuccess()) + sendOkCnt++; + else if (sendDetail.getCurStatCd().isFail()) + sendFailCnt++; + } + if (sendOkCnt > 0) + intgrnSendMast.setStatCd(StatCd.sendok); + else if (sendFailCnt == sendDetails.size()) + intgrnSendMast.setStatCd(StatCd.sendfail); + else + intgrnSendMast.setStatCd(StatCd.sending); + } + } else { + intgrnSendMast.setError(FieldError.initBuilder() + .errorCode(respVO.getErrCode().getCode()) + .errorMessage(respVO.getErrMsg()) + .build()); + } + + + + if (!CmmnUtil.isEmpty(intgrnSendMast)) { + + this.tryStatCdToClosed(intgrnSendMast, sendDetails); + + if (TryStatCd.sndRsrv.equals(intgrnSendMast.getTryStatCd()) || TryStatCd.sndRtme.equals(intgrnSendMast.getTryStatCd())) { + + PostSeCd postSeCd = intgrnSendMast.getTry1(); + if (intgrnSendMast.getTrySeq() == 2) postSeCd = intgrnSendMast.getTry2(); + else if (intgrnSendMast.getTrySeq() == 3) postSeCd = intgrnSendMast.getTry3(); + int sendOkCnt = 0; + int sendFailCnt = 0; + int unknownCnt = 0; + int curPostTotCnt = 0; + for (IntgrnSendDetail sendDetail : sendDetails) { + if (!postSeCd.equals(sendDetail.getCurPostSe())) + continue; + curPostTotCnt++; + + + if (sendDetail.getCurStatCd().isSuccess()) + sendOkCnt++; + else if (sendDetail.getCurStatCd().isFail()) + sendFailCnt++; + else + unknownCnt++; + + } + if (unknownCnt < curPostTotCnt) + if (sendOkCnt > 0) + intgrnSendMast.setTryStatCd(TryStatCd.ok); + else if (sendFailCnt == curPostTotCnt) + intgrnSendMast.setTryStatCd(TryStatCd.fail); + + + } + } + } + + + return respVO; + } + + private void tryStatCdToClosed(IntgrnSendMast intgrnSendMast, List sendDetails) { + if (TryStatCd.cmplt.equals(intgrnSendMast.getTryStatCd())) + return; + + + if (intgrnSendMast.getTrySeq() == intgrnSendMast.getTryCnt() + && (TryStatCd.ok.equals(intgrnSendMast.getTryStatCd()) + || TryStatCd.fail.equals(intgrnSendMast.getTryStatCd()) + || StatCd.sendfail.equals(intgrnSendMast.getStatCd())) + ) { + intgrnSendMast.setTryStatCd(TryStatCd.cmplt); + return; + } + + + int sendOkCnt = 0; + for (IntgrnSendDetail sendDetail : sendDetails) + if (sendDetail.getCurStatCd().isSuccess()) + sendOkCnt++; + if (sendDetails.size() == sendOkCnt) + intgrnSendMast.setTryStatCd(TryStatCd.cmplt); + + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiRsltProvider.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiRsltProvider.java new file mode 100644 index 0000000..4adb56f --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiRsltProvider.java @@ -0,0 +1,98 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.code.TryStatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendMastRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnDetailStatVO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnNotiRsltRespDTO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.time.format.DateTimeFormatter; +import java.util.List; + +@Slf4j +@Component +@RequiredArgsConstructor +public class IntgrnNotiRsltProvider implements EnsPhaseProcSupport { + + private final IntgrnSendMastRepository intgrnSendMastRepository; + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statReady(List args) { + log.info("no process"); + return null; + } + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(Long arg) { + log.info("no process"); + return null; + } + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(Long intSendMastId) { + try { + IntgrnSendMast intgrnSendMast = intgrnSendMastRepository.findById(intSendMastId) + .orElseThrow(() -> new EnsException(EnsErrCd.PRVD404, String.format("일치하는 통합발송마스터 자료가 없습니다. [ intSendMastId %s ]", intSendMastId))); + List sendDetailStats = intgrnSendDetailRepository.findIntgrnDetailStatVOsByIntSendMastId(intSendMastId); + + + IntgrnNotiRsltRespDTO respDTO = IntgrnNotiRsltRespDTO.builder() + .intSendMastId(intgrnSendMast.getIntSendMastId()) + .statCd(intgrnSendMast.getStatCd()) + .orgCd(intgrnSendMast.getOrgCd()) + .tmpltCd(intgrnSendMast.getTmpltCd()) + .postBundleTitle(intgrnSendMast.getPostBundleTitle()) + .sendDt(intgrnSendMast.getSendDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .closeDt(intgrnSendMast.getCloseDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .closeAt(this.getCloseAt(intgrnSendMast)) + .tryStatCd(intgrnSendMast.getTryStatCd()) + .documents(sendDetailStats) + .build(); + + + return EnsResponseVO.okBuilder().resultInfo(respDTO).build(); + } catch (EnsException e) { + return EnsResponseVO.errRsltBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .resultInfo(IntgrnNotiRsltRespDTO.builder() + .intSendMastId(intSendMastId) + .build()) + .build(); + } catch (Exception e) { + return EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ERR999) + .errMsg(String.format("전송결과 응답 처리 실패. 실패사유: %s", e.getMessage())) + .resultInfo(IntgrnNotiRsltRespDTO.builder() + .intSendMastId(intSendMastId) + .build()) + .build(); + } + + } + + private boolean getCloseAt(IntgrnSendMast intgrnSendMast) { + if (StatCd.close.equals(intgrnSendMast.getStatCd())) + return true; + else if (StatCd.sendfail.equals(intgrnSendMast.getStatCd()) + && TryStatCd.cmplt.equals(intgrnSendMast.getTryStatCd())) + return true; + else + return false; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiSender.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiSender.java new file mode 100644 index 0000000..f721d0f --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiSender.java @@ -0,0 +1,116 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.biztmplt.SendProcTemplate; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.code.TryStatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendMastRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.List; + +@Slf4j +@Component +@RequiredArgsConstructor +public class IntgrnNotiSender extends SendProcTemplate { + + private final IntgrnSendMastRepository intgrnSendMastRepository; + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + private final ApplicationEventPublisher applicationEventPublisher; + + + /** + * 전송시작 + * + * @param intSendMastId + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO statBegin(Long intSendMastId) { + + EnsResponseVO respVO = null; + try { + if (CmmnUtil.isEmpty(intSendMastId)) + throw new EnsException(EnsErrCd.SEND410, "발송마스터ID(은)는 필수조건 입니다."); + + IntgrnSendMast sendMast = intgrnSendMastRepository.findById(intSendMastId).orElseThrow(() -> new EnsException(EnsErrCd.SEND404, String.format("일치하는 발송마스터 자료가 없습니다. [ intSendMastId %s ]", intSendMastId))); + sendMast.setTryStatCd(TryStatCd.start); + + + respVO = EnsResponseVO.okBuilder().resultInfo(intSendMastId).build(); + } catch (EnsException e) { + + respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(); + } catch (Exception e) { + + respVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.SEND500).errMsg(e.getMessage()).build(); + } + + return respVO; + } + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public EnsResponseVO execute(Long intSendMastId) { + + IntgrnSendMast intgrnSendMast = null; + List intgrnSendDetails = null; + EnsResponseVO respVO = null; + try { + if (CmmnUtil.isEmpty(intSendMastId)) + throw new EnsException(EnsErrCd.SEND410, "발송마스터ID(은)는 필수조건 입니다."); + + intgrnSendMast = intgrnSendMastRepository.findById(intSendMastId).orElseThrow(() -> new EnsException(EnsErrCd.SEND404, String.format("일치하는 발송마스터 자료가 없습니다. [ intSendMastId %s ]", intSendMastId))); + intgrnSendDetails = intgrnSendDetailRepository.findAllBySendTargetAndSendMastAndTryStatCdIn(intgrnSendMast, Arrays.asList(TryStatCd.start)); + if (intgrnSendDetails.size() < 1) + throw new EnsException(EnsErrCd.SEND500, "조회된 발송상세 자료가 없음."); + + + PostSeCd postSeCd = null; + final int currentTryNum = intgrnSendMast.getTrySeq() + 1; + final boolean isReserve = currentTryNum == 1 ? true : false; + final TryStatCd tryStatCd = currentTryNum == 1 ? TryStatCd.sndRsrv : TryStatCd.sndRtme; + if (currentTryNum == 1) postSeCd = intgrnSendMast.getTry1(); + else if (currentTryNum == 2) postSeCd = intgrnSendMast.getTry2(); + else if (currentTryNum == 3) postSeCd = intgrnSendMast.getTry3(); + AcceptDataFactory makerFactory = new AcceptDataMakerFactory(intgrnSendMast, intgrnSendDetails, isReserve); + + applicationEventPublisher.publishEvent(makerFactory.get(postSeCd)); + + + intgrnSendMast.setTrySeq(currentTryNum); + intgrnSendMast.setTryStatCd(tryStatCd); + + PostSeCd finalPostSeCd = postSeCd; + intgrnSendDetails.forEach(data -> data.setCurPostSe(finalPostSeCd)); + + + + respVO = EnsResponseVO.okBuilder().build(); + + } catch (EnsException e) { + + respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(); + } catch (Exception e) { + + respVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.SEND500).errMsg(e.getMessage()).build(); + } + + + return respVO; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkoalimtalk/AcceptByKkoAlimtalkEventListener.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkoalimtalk/AcceptByKkoAlimtalkEventListener.java new file mode 100644 index 0000000..5ec118e --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkoalimtalk/AcceptByKkoAlimtalkEventListener.java @@ -0,0 +1,113 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.kkoalimtalk; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.monitor.slack.event.MonitorEvent; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.AcceptDataEventListener; +import cokr.xit.ens.modules.common.monitor.MessageByPhase; +import cokr.xit.ens.modules.kkoalimtalk.domain.SendDetailKkoAlimtalk; +import cokr.xit.ens.modules.kkoalimtalk.service.KkoAlimtalkService; +import cokr.xit.ens.modules.kkoalimtalk.service.event.KkoAlimtalkSendRealtimeEvent; +import cokr.xit.ens.modules.kkoalimtalk.service.event.KkoAlimtalkSendReserveEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class AcceptByKkoAlimtalkEventListener implements AcceptDataEventListener { + + private final ApplicationEventPublisher applicationEventPublisher; + private final KkoAlimtalkService kkoAlimtalkService; + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + + + @Override + public void accept(AcceptDataByKkoAlimtalk ev) { + final PostSeCd POST_SE_CD = PostSeCd.kkoAlimtalk; + EnsResponseVO responseVO = null; + try { + + responseVO = kkoAlimtalkService.accept(ev.createReqDto()); + + + Map resultInfo = (Map) responseVO.getResultInfo(); + Long sendMastId = (Long) resultInfo.get("sendMastId"); + if (EnsErrCd.OK.equals(responseVO.getErrCode())) { + List sendDetails = (List) resultInfo.get("sendDetails"); + Map sendDetailIdMap = convertSendDetailIdMap(sendDetails); + this.acceptSuccess(ev.getIntgrnSendDetails(), POST_SE_CD, sendDetailIdMap); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + } else { + this.acceptFail(ev.getIntgrnSendDetails(), POST_SE_CD, responseVO.getErrCode(), String.format("%s %s", responseVO.getErrMsg(), responseVO.getResultInfo().toString())); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + return; + } + + + if (ev.IsReserveSend()) { + KkoAlimtalkSendReserveEvent event = KkoAlimtalkSendReserveEvent.builder() + .sendMastIds(Arrays.asList(sendMastId)) + .build(); + applicationEventPublisher.publishEvent(event); + + } else { + KkoAlimtalkSendRealtimeEvent event = KkoAlimtalkSendRealtimeEvent.builder() + .sendMastIds(Arrays.asList(sendMastId)) +// .callback(() -> this.fetch(sendMastId, ev.getSendDetails())) + .build(); + applicationEventPublisher.publishEvent(event); + } + } catch (Exception e) { + this.acceptFail(ev.getIntgrnSendDetails(), POST_SE_CD, EnsErrCd.ACPT999, e.getMessage()); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + responseVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.ERR999).errMsg(e.getMessage()).build(); + } finally { + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) { + String message = createFailMessage(ev.getIntgrnSendDetails().get(0).getIntgrnSendMast().getIntSendMastId(), POST_SE_CD, responseVO); + applicationEventPublisher.publishEvent(MonitorEvent.builder() + .message(MessageByPhase.builder() + .oClass(getClass().getSimpleName() + "." + new Throwable().getStackTrace()[0].getMethodName()) + .postSeCd(PostSeCd.intgrnNoti) + .statCd(StatCd.sendfail) + .errCd(responseVO.getErrCode()) + .message(message) + .build()) + .build()); + } + } + + } + + @Override + public Map convertSendDetailIdMap(List sendDetails) { + + Map sendDetailIdMap = sendDetails.stream() + .map(row -> { + Map m = new HashMap<>(); + m.put("key", row.getMsgIdx()); + m.put("value", row.getSendDetailId()); + return m; + }) + .collect(Collectors.toMap(m -> String.valueOf(m.get("key")), m -> (Long) m.get("value"), (k1, k2) -> k1)); + + return sendDetailIdMap; + } + + @Override + public void setSendDetailId(IntgrnSendDetail intgrnSendDetail, Long sendDetailId) { + intgrnSendDetail.setSendDetailIdKkoAt(sendDetailId); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkoalimtalk/AcceptDataByKkoAlimtalk.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkoalimtalk/AcceptDataByKkoAlimtalk.java new file mode 100644 index 0000000..58cd687 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkoalimtalk/AcceptDataByKkoAlimtalk.java @@ -0,0 +1,82 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.kkoalimtalk; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.model.EnsBillAcptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.AcceptData; +import cokr.xit.ens.modules.kkoalimtalk.model.KkoAlimtalkAcceptReqDTO; +import cokr.xit.ens.modules.kkoalimtalk.model.config.Document; +import cokr.xit.ens.modules.kkoalimtalk.model.config.DocumentConfKkoAt; +import cokr.xit.ens.modules.kkoalimtalk.model.config.XitProperty; + +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class AcceptDataByKkoAlimtalk extends AcceptData { + + + public AcceptDataByKkoAlimtalk(IntgrnSendMast intgrnSendMast, List intgrnSendDetails, Boolean isReserveSend) { + super(intgrnSendMast, intgrnSendDetails, isReserveSend); + } + + @Override + public KkoAlimtalkAcceptReqDTO createReqDto() { + KkoAlimtalkAcceptReqDTO acceptReqDTO = KkoAlimtalkAcceptReqDTO.builder() + .vender(intgrnSendMast.getVender().getCode()) + .org_cd(intgrnSendMast.getOrgCd()) + .tmplt_cd(intgrnSendMast.getTmpltCd()) + .post_bundle_title(intgrnSendMast.getPostBundleTitle()) + .send_dt(intgrnSendMast.getSendDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .close_dt(intgrnSendMast.getCloseDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .documents(intgrnSendDetails.stream().map(data -> this.createDocument(data)).collect(Collectors.toList())) + .build(); + + return acceptReqDTO; + } + + protected Document createDocument(IntgrnSendDetail intgrnSendDetail) { + DocumentConfKkoAt documentConf = gson.fromJson(intgrnSendDetail.getJAcptDocKkoAt(), DocumentConfKkoAt.class); + + return Document.builder() + .msg_idx(intgrnSendDetail.getLinkedUuid()) + .country_code(documentConf.getCountry_code()) + .recipient(intgrnSendDetail.getMblphonNo()) + .app_user_id(documentConf.getApp_user_id()) + .title(documentConf.getTitle()) + .res_method(documentConf.getRes_method()) + .attach(documentConf.getAttach()) + .supplement(documentConf.getSupplement()) + .message_type(documentConf.getMessage_type()) + .use_failback(documentConf.getUse_failback()) + .mms_attach(documentConf.getMms_attach()) + .xit_property(this.createXitProperty(intgrnSendDetail)) + .build(); + } + + protected XitProperty createXitProperty(IntgrnSendDetail intgrnSendDetail) { + return XitProperty.builder() + .bill_acpt_data(this.createBillAcptData(intgrnSendDetail)) + .tmplt_msg_data(this.createTmpltMsgData(intgrnSendDetail)) + .build(); + } + + protected EnsBillAcptReqDTO createBillAcptData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getBill())) + return null; + return EnsBillAcptReqDTO.builder() + .billUid(intgrnSendDetail.getBill().getBillUid()) + .billerUserKey(intgrnSendDetail.getBill().getBillerUserKey()) + .billSe(intgrnSendDetail.getBill().getBillSeCd()) + .build(); + } + + protected Map createTmpltMsgData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getJTmpltMsgData())) + return null; + else + return gson.fromJson(intgrnSendDetail.getJTmpltMsgData(), Map.class); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkomydoc/AcceptByKkoMydocEventListener.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkomydoc/AcceptByKkoMydocEventListener.java new file mode 100644 index 0000000..dff3ba7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkomydoc/AcceptByKkoMydocEventListener.java @@ -0,0 +1,112 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.kkomydoc; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.monitor.slack.event.MonitorEvent; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.AcceptDataEventListener; +import cokr.xit.ens.modules.common.monitor.MessageByPhase; +import cokr.xit.ens.modules.kkomydoc.domain.SendDetailKkoMydoc; +import cokr.xit.ens.modules.kkomydoc.service.KkoMydocService; +import cokr.xit.ens.modules.kkomydoc.service.event.KkoMydocSendRealtimeEvent; +import cokr.xit.ens.modules.kkomydoc.service.event.KkoMydocSendReserveEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class AcceptByKkoMydocEventListener implements AcceptDataEventListener { + + private final ApplicationEventPublisher applicationEventPublisher; + private final KkoMydocService kkoMydocService; + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + + + @Override + public void accept(AcceptDataByKkoMydoc ev) { + final PostSeCd POST_SE_CD = PostSeCd.kkoMydoc; + EnsResponseVO responseVO = null; + try { + + responseVO = kkoMydocService.accept(ev.createReqDto()); + + + Map resultInfo = (Map) responseVO.getResultInfo(); + Long sendMastId = (Long) resultInfo.get("sendMastId"); + List sendDetails = (List) resultInfo.get("sendDetails"); + if (EnsErrCd.OK.equals(responseVO.getErrCode())) { + Map sendDetailIdMap = convertSendDetailIdMap(sendDetails); + this.acceptSuccess(ev.getIntgrnSendDetails(), POST_SE_CD, sendDetailIdMap); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + } else { + this.acceptFail(ev.getIntgrnSendDetails(), POST_SE_CD, responseVO.getErrCode(), String.format("%s %s", responseVO.getErrMsg(), responseVO.getResultInfo().toString())); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + return; + } + + + if (ev.IsReserveSend()) { + KkoMydocSendReserveEvent event = KkoMydocSendReserveEvent.builder() + .sendMastIds(Arrays.asList(sendMastId)) + .build(); + applicationEventPublisher.publishEvent(event); + + } else { + KkoMydocSendRealtimeEvent event = KkoMydocSendRealtimeEvent.builder() + .sendMastIds(Arrays.asList(sendMastId)) +// .callback(() -> this.fetch(sendMastId, ev.getSendDetails())) + .build(); + applicationEventPublisher.publishEvent(event); + } + } catch (Exception e) { + this.acceptFail(ev.getIntgrnSendDetails(), POST_SE_CD, EnsErrCd.ACPT999, e.getMessage()); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + responseVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.ERR999).errMsg(e.getMessage()).build(); + } finally { + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) { + String message = createFailMessage(ev.getIntgrnSendDetails().get(0).getIntgrnSendMast().getIntSendMastId(), POST_SE_CD, responseVO); + applicationEventPublisher.publishEvent(MonitorEvent.builder() + .message(MessageByPhase.builder() + .oClass(getClass().getSimpleName() + "." + new Throwable().getStackTrace()[0].getMethodName()) + .postSeCd(PostSeCd.intgrnNoti) + .statCd(StatCd.sendfail) + .errCd(responseVO.getErrCode()) + .message(message) + .build()) + .build()); + } + } + } + + @Override + public Map convertSendDetailIdMap(List sendDetails) { + + Map sendDetailIdMap = sendDetails.stream() + .map(row -> { + Map m = new HashMap<>(); + m.put("key", row.getPropExternalDocumentUuid()); + m.put("value", row.getSendDetailId()); + return m; + }) + .collect(Collectors.toMap(m -> String.valueOf(m.get("key")), m -> (Long) m.get("value"), (k1, k2) -> k1)); + + return sendDetailIdMap; + } + + @Override + public void setSendDetailId(IntgrnSendDetail intgrnSendDetail, Long sendDetailId) { + intgrnSendDetail.setSendDetailIdKkoMd(sendDetailId); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkomydoc/AcceptDataByKkoMydoc.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkomydoc/AcceptDataByKkoMydoc.java new file mode 100644 index 0000000..af9709d --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkomydoc/AcceptDataByKkoMydoc.java @@ -0,0 +1,99 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.kkomydoc; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.utils.crypto.AES256; +import cokr.xit.ens.core.utils.crypto.Crypto; +import cokr.xit.ens.core.model.EnsBillAcptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.AcceptData; +import cokr.xit.ens.modules.kkomydoc.model.KkoMydocAcceptReqDTO; +import cokr.xit.ens.modules.kkomydoc.model.config.Document; +import cokr.xit.ens.modules.kkomydoc.model.config.DocumentConfKkoMd; +import cokr.xit.ens.modules.kkomydoc.model.config.Receiver; +import cokr.xit.ens.modules.kkomydoc.model.config.XitProperty; + +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class AcceptDataByKkoMydoc extends AcceptData { + + private AES256 aes256 = new AES256(Crypto.AES256.getKey()); + + public AcceptDataByKkoMydoc(IntgrnSendMast intgrnSendMast, List intgrnSendDetails, Boolean isReserveSend) { + super(intgrnSendMast, intgrnSendDetails, isReserveSend); + } + + @Override + public KkoMydocAcceptReqDTO createReqDto() { + KkoMydocAcceptReqDTO acceptReqDTO = KkoMydocAcceptReqDTO.builder() + .vender(intgrnSendMast.getVender().getCode()) + .org_cd(intgrnSendMast.getOrgCd()) + .tmplt_cd(intgrnSendMast.getTmpltCd()) + .post_bundle_title(intgrnSendMast.getPostBundleTitle()) + .send_dt(intgrnSendMast.getSendDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .close_dt(intgrnSendMast.getCloseDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .documents(intgrnSendDetails.stream().map(data -> this.createDocument(data)).collect(Collectors.toList())) + .build(); + + return acceptReqDTO; + } + + protected Document createDocument(IntgrnSendDetail intgrnSendDetail) { + + DocumentConfKkoMd documentConf = gson.fromJson(intgrnSendDetail.getJAcptDocKkoMd(), DocumentConfKkoMd.class); + + return Document.builder() + .external_document_uuid(intgrnSendDetail.getLinkedUuid()) + .hash(documentConf.getHash()) + .common_categories(documentConf.getCommon_categories()) + .read_expired_at(documentConf.getRead_expired_at()) + .read_expired_sec(documentConf.getRead_expired_sec()) + .receiver(this.createReceiver(intgrnSendDetail)) + .property(documentConf.getProperty()) + .bridge(documentConf.getBridge()) + .xit_property(this.createXitProperty(intgrnSendDetail)) + .build(); + } + + protected Receiver createReceiver(IntgrnSendDetail intgrnSendDetail) { + return Receiver.builder() + .ci(intgrnSendDetail.getCi()) + .phone_number(null) + .name(null) + .birthday(null) + .is_required_verify_name(null) + .build(); + } + + protected XitProperty createXitProperty(IntgrnSendDetail intgrnSendDetail) { + return XitProperty.builder() + .mbl_page_data(CmmnUtil.isEmpty(intgrnSendDetail.getJMblPageData()) ? null : gson.fromJson(intgrnSendDetail.getJMblPageData(), Map.class)) +// .bill_link_info(this.createBillLinkInfo(intgrnSendDetail)) + .bill_acpt_data(this.createBillAcptData(intgrnSendDetail)) +// .jid(intgrnSendDetail.getJids()) + .jid(aes256.decrypt(intgrnSendDetail.getJid())) + .tmplt_msg_data(this.createTmpltMsgData(intgrnSendDetail)) + .build(); + } + + protected EnsBillAcptReqDTO createBillAcptData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getBill())) + return null; + return EnsBillAcptReqDTO.builder() + .billUid(intgrnSendDetail.getBill().getBillUid()) + .billerUserKey(intgrnSendDetail.getBill().getBillerUserKey()) + .billSe(intgrnSendDetail.getBill().getBillSeCd()) + .build(); + } + + protected Map createTmpltMsgData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getJTmpltMsgData())) + return null; + else + return gson.fromJson(intgrnSendDetail.getJTmpltMsgData(), Map.class); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktGibis/AcceptByKtGibisEventListener.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktGibis/AcceptByKtGibisEventListener.java new file mode 100644 index 0000000..19396db --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktGibis/AcceptByKtGibisEventListener.java @@ -0,0 +1,113 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.ktGibis; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.monitor.slack.event.MonitorEvent; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.AcceptDataEventListener; +import cokr.xit.ens.modules.common.monitor.MessageByPhase; +import cokr.xit.ens.modules.ktsigntalk.gibis.domain.SendDetailKtGibis; +import cokr.xit.ens.modules.ktsigntalk.gibis.service.KtGibisService; +import cokr.xit.ens.modules.ktsigntalk.gibis.service.event.KtGibisSendRealtimeEvent; +import cokr.xit.ens.modules.ktsigntalk.gibis.service.event.KtGibisSendReserveEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class AcceptByKtGibisEventListener implements AcceptDataEventListener { + + private final ApplicationEventPublisher applicationEventPublisher; + private final KtGibisService ktGibisService; + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + + + @Override + public void accept(AcceptDataByKtGibis ev) { + final PostSeCd POST_SE_CD = PostSeCd.ktGibis; + EnsResponseVO responseVO = null; + try { + + responseVO = ktGibisService.accept(ev.createReqDto()); + + + if (EnsErrCd.OK.equals(responseVO.getErrCode())) { + Map resultInfo = (Map) responseVO.getResultInfo(); + List sendDetails = (List) resultInfo.get("sendDetails"); + Map sendDetailIdMap = convertSendDetailIdMap(sendDetails); + this.acceptSuccess(ev.getIntgrnSendDetails(), POST_SE_CD, sendDetailIdMap); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + } else { + this.acceptFail(ev.getIntgrnSendDetails(), POST_SE_CD, responseVO.getErrCode(), String.format("%s %s", responseVO.getErrMsg(), responseVO.getResultInfo().toString())); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + return; + } + + + Map resultInfo = (Map) responseVO.getResultInfo(); + Long sendMastId = (Long) resultInfo.get("sendMastId"); + if (ev.IsReserveSend()) { + KtGibisSendReserveEvent event = KtGibisSendReserveEvent.builder() + .sendMastIds(Arrays.asList(sendMastId)) + .build(); + applicationEventPublisher.publishEvent(event); + + } else { + KtGibisSendRealtimeEvent event = KtGibisSendRealtimeEvent.builder() + .sendMastIds(Arrays.asList(sendMastId)) +// .callback(() -> this.fetch(sendMastId, ev.getSendDetails())) + .build(); + applicationEventPublisher.publishEvent(event); + } + } catch (Exception e) { + this.acceptFail(ev.getIntgrnSendDetails(), POST_SE_CD, EnsErrCd.ACPT999, e.getMessage()); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + responseVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.ERR999).errMsg(e.getMessage()).build(); + } finally { + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) { + String message = createFailMessage(ev.getIntgrnSendDetails().get(0).getIntgrnSendMast().getIntSendMastId(), POST_SE_CD, responseVO); + applicationEventPublisher.publishEvent(MonitorEvent.builder() + .message(MessageByPhase.builder() + .oClass(getClass().getSimpleName() + "." + new Throwable().getStackTrace()[0].getMethodName()) + .postSeCd(PostSeCd.intgrnNoti) + .statCd(StatCd.sendfail) + .errCd(responseVO.getErrCode()) + .message(message) + .build()) + .build()); + } + } + } + + @Override + public Map convertSendDetailIdMap(List sendDetails) { + + Map sendDetailIdMap = sendDetails.stream() + .map(row -> { + Map m = new HashMap<>(); + m.put("key", row.getLinkedUuid()); + m.put("value", row.getSendDetailId()); + return m; + }) + .collect(Collectors.toMap(m -> String.valueOf(m.get("key")), m -> (Long) m.get("value"), (k1, k2) -> k1)); + + return sendDetailIdMap; + } + + @Override + public void setSendDetailId(IntgrnSendDetail intgrnSendDetail, Long sendDetailId) { + intgrnSendDetail.setSendDetailIdKtGbs(sendDetailId); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktGibis/AcceptDataByKtGibis.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktGibis/AcceptDataByKtGibis.java new file mode 100644 index 0000000..37d70ee --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktGibis/AcceptDataByKtGibis.java @@ -0,0 +1,85 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.ktGibis; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.utils.crypto.AES256; +import cokr.xit.ens.core.utils.crypto.Crypto; +import cokr.xit.ens.core.model.EnsBillAcptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.AcceptData; +import cokr.xit.ens.modules.ktsigntalk.gibis.model.KtGibisAcceptReqDTO; +import cokr.xit.ens.modules.ktsigntalk.gibis.model.config.Document; +import cokr.xit.ens.modules.ktsigntalk.gibis.model.config.DocumentConfKtGbs; +import cokr.xit.ens.modules.ktsigntalk.gibis.model.config.XitProperty; + +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class AcceptDataByKtGibis extends AcceptData { + + private AES256 aes256 = new AES256(Crypto.AES256.getKey()); + + public AcceptDataByKtGibis(IntgrnSendMast intgrnSendMast, List intgrnSendDetails, Boolean isReserveSend) { + super(intgrnSendMast, intgrnSendDetails, isReserveSend); + } + + @Override + public KtGibisAcceptReqDTO createReqDto() { + KtGibisAcceptReqDTO acceptReqDTO = KtGibisAcceptReqDTO.builder() + .vender(intgrnSendMast.getVender().getCode()) + .org_cd(intgrnSendMast.getOrgCd()) + .tmplt_cd(intgrnSendMast.getTmpltCd()) + .post_bundle_title(intgrnSendMast.getPostBundleTitle()) + .send_dt(intgrnSendMast.getSendDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .close_dt(intgrnSendMast.getCloseDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .documents(intgrnSendDetails.stream().map(data -> this.createDocument(data)).collect(Collectors.toList())) + .build(); + + return acceptReqDTO; + } + + protected Document createDocument(IntgrnSendDetail intgrnSendDetail) { + + DocumentConfKtGbs documentConf = gson.fromJson(intgrnSendDetail.getJAcptDocKtGbs(), DocumentConfKtGbs.class); + + return Document.builder() + .linkedUuid(intgrnSendDetail.getLinkedUuid()) + .ci(intgrnSendDetail.getCi()) + .hash(documentConf.getHash()) + .srcSeq(documentConf.getSrcSeq()) + .mmsDtlCnts(documentConf.getMmsDtlCnts()) + .rcsDtlCnts(documentConf.getRcsDtlCnts()) + .url(documentConf.getUrl()) + .mdn(documentConf.getMdn()) + .xit_property(this.createXitProperty(intgrnSendDetail)) + .build(); + } + + protected XitProperty createXitProperty(IntgrnSendDetail intgrnSendDetail) { + return XitProperty.builder() + .mobile_page(CmmnUtil.isEmpty(intgrnSendDetail.getJMblPageData()) ? null : gson.fromJson(intgrnSendDetail.getJMblPageData(), Map.class)) + .bill_acpt_data(this.createBillAcptData(intgrnSendDetail)) + .jid(aes256.decrypt(intgrnSendDetail.getJid())) + .tmplt_msg_data(this.createTmpltMsgData(intgrnSendDetail)) + .build(); + } + + protected EnsBillAcptReqDTO createBillAcptData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getBill())) + return null; + return EnsBillAcptReqDTO.builder() + .billUid(intgrnSendDetail.getBill().getBillUid()) + .billerUserKey(intgrnSendDetail.getBill().getBillerUserKey()) + .billSe(intgrnSendDetail.getBill().getBillSeCd()) + .build(); + } + + protected Map createTmpltMsgData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getJTmpltMsgData())) + return null; + else + return gson.fromJson(intgrnSendDetail.getJTmpltMsgData(), Map.class); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktSigntalk/AcceptByKtSigntalkEventListener.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktSigntalk/AcceptByKtSigntalkEventListener.java new file mode 100644 index 0000000..bae43d5 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktSigntalk/AcceptByKtSigntalkEventListener.java @@ -0,0 +1,113 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.ktSigntalk; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.monitor.slack.event.MonitorEvent; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.AcceptDataEventListener; +import cokr.xit.ens.modules.common.monitor.MessageByPhase; +import cokr.xit.ens.modules.ktsigntalk.direct.domain.SendDetailKtSigntalk; +import cokr.xit.ens.modules.ktsigntalk.direct.service.KtSigntalkService; +import cokr.xit.ens.modules.ktsigntalk.direct.service.event.KtSigntalkSendRealtimeEvent; +import cokr.xit.ens.modules.ktsigntalk.direct.service.event.KtSigntalkSendReserveEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class AcceptByKtSigntalkEventListener implements AcceptDataEventListener { + + private final ApplicationEventPublisher applicationEventPublisher; + private final KtSigntalkService ktSigntalkService; + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + + + @Override + public void accept(AcceptDataByKtSigntalk ev) { + final PostSeCd POST_SE_CD = PostSeCd.ktSigntalk; + EnsResponseVO responseVO = null; + try { + + responseVO = ktSigntalkService.accept(ev.createReqDto()); + + + if (EnsErrCd.OK.equals(responseVO.getErrCode())) { + Map resultInfo = (Map) responseVO.getResultInfo(); + List sendDetails = (List) resultInfo.get("sendDetails"); + Map sendDetailIdMap = convertSendDetailIdMap(sendDetails); + this.acceptSuccess(ev.getIntgrnSendDetails(), POST_SE_CD, sendDetailIdMap); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + } else { + this.acceptFail(ev.getIntgrnSendDetails(), POST_SE_CD, responseVO.getErrCode(), String.format("%s %s", responseVO.getErrMsg(), responseVO.getResultInfo().toString())); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + return; + } + + + Map resultInfo = (Map) responseVO.getResultInfo(); + Long sendMastId = (Long) resultInfo.get("sendMastId"); + if (ev.IsReserveSend()) { + KtSigntalkSendReserveEvent event = KtSigntalkSendReserveEvent.builder() + .sendMastIds(Arrays.asList(sendMastId)) + .build(); + applicationEventPublisher.publishEvent(event); + + } else { + KtSigntalkSendRealtimeEvent event = KtSigntalkSendRealtimeEvent.builder() + .sendMastIds(Arrays.asList(sendMastId)) +// .callback(() -> this.fetch(sendMastId, ev.getSendDetails())) + .build(); + applicationEventPublisher.publishEvent(event); + } + } catch (Exception e) { + this.acceptFail(ev.getIntgrnSendDetails(), POST_SE_CD, EnsErrCd.ACPT999, e.getMessage()); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + responseVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.ERR999).errMsg(e.getMessage()).build(); + } finally { + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) { + String message = createFailMessage(ev.getIntgrnSendDetails().get(0).getIntgrnSendMast().getIntSendMastId(), POST_SE_CD, responseVO); + applicationEventPublisher.publishEvent(MonitorEvent.builder() + .message(MessageByPhase.builder() + .oClass(getClass().getSimpleName() + "." + new Throwable().getStackTrace()[0].getMethodName()) + .postSeCd(PostSeCd.intgrnNoti) + .statCd(StatCd.sendfail) + .errCd(responseVO.getErrCode()) + .message(message) + .build()) + .build()); + } + } + } + + @Override + public Map convertSendDetailIdMap(List sendDetails) { + + Map sendDetailIdMap = sendDetails.stream() + .map(row -> { + Map m = new HashMap<>(); + m.put("key", row.getClientSrcKey()); + m.put("value", row.getSendDetailId()); + return m; + }) + .collect(Collectors.toMap(m -> String.valueOf(m.get("key")), m -> (Long) m.get("value"), (k1, k2) -> k1)); + + return sendDetailIdMap; + } + + @Override + public void setSendDetailId(IntgrnSendDetail intgrnSendDetail, Long sendDetailId) { + intgrnSendDetail.setSendDetailIdKtSt(sendDetailId); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktSigntalk/AcceptDataByKtSigntalk.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktSigntalk/AcceptDataByKtSigntalk.java new file mode 100644 index 0000000..00459df --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktSigntalk/AcceptDataByKtSigntalk.java @@ -0,0 +1,97 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.ktSigntalk; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.utils.crypto.AES256; +import cokr.xit.ens.core.utils.crypto.Crypto; +import cokr.xit.ens.core.model.EnsBillAcptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.AcceptData; +import cokr.xit.ens.modules.ktsigntalk.direct.model.KtSigntalkAcceptReqDTO; +import cokr.xit.ens.modules.ktsigntalk.direct.model.config.Document; +import cokr.xit.ens.modules.ktsigntalk.direct.model.config.DocumentConfKtSt; +import cokr.xit.ens.modules.ktsigntalk.direct.model.config.XitProperty; + +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class AcceptDataByKtSigntalk extends AcceptData { + + private AES256 aes256 = new AES256(Crypto.AES256.getKey()); + + public AcceptDataByKtSigntalk(IntgrnSendMast intgrnSendMast, List intgrnSendDetails, Boolean isReserveSend) { + super(intgrnSendMast, intgrnSendDetails, isReserveSend); + } + + @Override + public KtSigntalkAcceptReqDTO createReqDto() { + KtSigntalkAcceptReqDTO acceptReqDTO = KtSigntalkAcceptReqDTO.builder() + .vender(intgrnSendMast.getVender().getCode()) + .org_cd(intgrnSendMast.getOrgCd()) + .tmplt_cd(intgrnSendMast.getTmpltCd()) + .post_bundle_title(intgrnSendMast.getPostBundleTitle()) + .send_dt(intgrnSendMast.getSendDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .close_dt(intgrnSendMast.getCloseDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .documents(intgrnSendDetails.stream().map(data -> this.createDocument(data)).collect(Collectors.toList())) + .build(); + + return acceptReqDTO; + } + + protected Document createDocument(IntgrnSendDetail intgrnSendDetail) { + + DocumentConfKtSt documentConf = gson.fromJson(intgrnSendDetail.getJAcptDocKtSt(), DocumentConfKtSt.class); + + return Document.builder() + .clientSrcKey(intgrnSendDetail.getLinkedUuid()) + .ci(intgrnSendDetail.getCi()) + .hash(documentConf.getHash()) + .srcSeq(documentConf.getSrcSeq()) + .dBirth(documentConf.getDBirth()) + .juminFirstNo(documentConf.getJuminFirstNo()) + .cnPerson(documentConf.getCnPerson()) + .cZip(documentConf.getCZip()) + .addr(documentConf.getAddr()) + .rcvTelNo(documentConf.getRcvTelNo()) + .sndTelNo(documentConf.getSndTelNo()) + .rcvPwdUseYn(documentConf.getRcvPwdUseYn()) + .mmsDtlCnts(documentConf.getMmsDtlCnts()) + .mmsTitle(documentConf.getMmsTitle()) + .sendTel(documentConf.getSendTel()) + .url(documentConf.getUrl()) + .exTime(documentConf.getExTime()) + .mType(documentConf.getMType()) + .rcvType(documentConf.getRcvType()) + .xit_property(this.createXitProperty(intgrnSendDetail)) + .build(); + } + + protected XitProperty createXitProperty(IntgrnSendDetail intgrnSendDetail) { + return XitProperty.builder() + .mobile_page(CmmnUtil.isEmpty(intgrnSendDetail.getJMblPageData()) ? null : gson.fromJson(intgrnSendDetail.getJMblPageData(), Map.class)) +// .bill_link_info(this.createBillLinkInfo(intgrnSendDetail)) + .bill_acpt_data(this.createBillAcptData(intgrnSendDetail)) + .jid(aes256.decrypt(intgrnSendDetail.getJid())) + .tmplt_msg_data(this.createTmpltMsgData(intgrnSendDetail)) + .build(); + } + + protected EnsBillAcptReqDTO createBillAcptData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getBill())) + return null; + return EnsBillAcptReqDTO.builder() + .billUid(intgrnSendDetail.getBill().getBillUid()) + .billerUserKey(intgrnSendDetail.getBill().getBillerUserKey()) + .billSe(intgrnSendDetail.getBill().getBillSeCd()) + .build(); + } + + protected Map createTmpltMsgData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getJTmpltMsgData())) + return null; + else + return gson.fromJson(intgrnSendDetail.getJTmpltMsgData(), Map.class); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/nvsigntalk/AcceptByNvSigntalkEventListener.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/nvsigntalk/AcceptByNvSigntalkEventListener.java new file mode 100644 index 0000000..8658622 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/nvsigntalk/AcceptByNvSigntalkEventListener.java @@ -0,0 +1,113 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.nvsigntalk; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.monitor.slack.event.MonitorEvent; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.AcceptDataEventListener; +import cokr.xit.ens.modules.common.monitor.MessageByPhase; +import cokr.xit.ens.modules.nvsigntalk.domain.SendDetailNvSigntalk; +import cokr.xit.ens.modules.nvsigntalk.service.NvSigntalkService; +import cokr.xit.ens.modules.nvsigntalk.service.event.NvSigntalkSendRealtimeEvent; +import cokr.xit.ens.modules.nvsigntalk.service.event.NvSigntalkSendReserveEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class AcceptByNvSigntalkEventListener implements AcceptDataEventListener { + + private final ApplicationEventPublisher applicationEventPublisher; + private final NvSigntalkService nvSigntalkService; + private final IntgrnSendDetailRepository intgrnSendDetailRepository; + + + @Override + public void accept(AcceptDataByNvSigntalk ev) { + final PostSeCd POST_SE_CD = PostSeCd.nvSigntalk; + EnsResponseVO responseVO = null; + try { + + responseVO = nvSigntalkService.accept(ev.createReqDto()); + + + if (EnsErrCd.OK.equals(responseVO.getErrCode())) { + Map resultInfo = (Map) responseVO.getResultInfo(); + List sendDetails = (List) resultInfo.get("sendDetails"); + Map sendDetailIdMap = convertSendDetailIdMap(sendDetails); + this.acceptSuccess(ev.getIntgrnSendDetails(), POST_SE_CD, sendDetailIdMap); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + } else { + this.acceptFail(ev.getIntgrnSendDetails(), POST_SE_CD, responseVO.getErrCode(), String.format("%s %s", responseVO.getErrMsg(), responseVO.getResultInfo().toString())); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + return; + } + + + Map resultInfo = (Map) responseVO.getResultInfo(); + Long sendMastId = (Long) resultInfo.get("sendMastId"); + if (ev.IsReserveSend()) { + NvSigntalkSendReserveEvent event = NvSigntalkSendReserveEvent.builder() + .sendMastIds(Arrays.asList(sendMastId)) + .build(); + applicationEventPublisher.publishEvent(event); + + } else { + NvSigntalkSendRealtimeEvent event = NvSigntalkSendRealtimeEvent.builder() + .sendMastIds(Arrays.asList(sendMastId)) +// .callback(() -> this.fetch(sendMastId, ev.getSendDetails())) + .build(); + applicationEventPublisher.publishEvent(event); + } + } catch (Exception e) { + this.acceptFail(ev.getIntgrnSendDetails(), POST_SE_CD, EnsErrCd.ACPT999, e.getMessage()); + intgrnSendDetailRepository.saveAll(ev.getIntgrnSendDetails()); + responseVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.ERR999).errMsg(e.getMessage()).build(); + } finally { + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) { + String message = createFailMessage(ev.getIntgrnSendDetails().get(0).getIntgrnSendMast().getIntSendMastId(), POST_SE_CD, responseVO); + applicationEventPublisher.publishEvent(MonitorEvent.builder() + .message(MessageByPhase.builder() + .oClass(getClass().getSimpleName() + "." + new Throwable().getStackTrace()[0].getMethodName()) + .postSeCd(PostSeCd.intgrnNoti) + .statCd(StatCd.sendfail) + .errCd(responseVO.getErrCode()) + .message(message) + .build()) + .build()); + } + } + } + + @Override + public Map convertSendDetailIdMap(List sendDetails) { + + Map sendDetailIdMap = sendDetails.stream() + .map(row -> { + Map m = new HashMap<>(); + m.put("key", row.getClientDocId()); + m.put("value", row.getSendDetailId()); + return m; + }) + .collect(Collectors.toMap(m -> String.valueOf(m.get("key")), m -> (Long) m.get("value"), (k1, k2) -> k1)); + + return sendDetailIdMap; + } + + @Override + public void setSendDetailId(IntgrnSendDetail intgrnSendDetail, Long sendDetailId) { + intgrnSendDetail.setSendDetailIdNvSt(sendDetailId); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/nvsigntalk/AcceptDataByNvSigntalk.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/nvsigntalk/AcceptDataByNvSigntalk.java new file mode 100644 index 0000000..f47ecc3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/nvsigntalk/AcceptDataByNvSigntalk.java @@ -0,0 +1,89 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.nvsigntalk; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.utils.crypto.AES256; +import cokr.xit.ens.core.utils.crypto.Crypto; +import cokr.xit.ens.core.model.EnsBillAcptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast; +import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.AcceptData; +import cokr.xit.ens.modules.nvsigntalk.model.NvSigntalkAcceptReqDTO; +import cokr.xit.ens.modules.nvsigntalk.model.config.Document; +import cokr.xit.ens.modules.nvsigntalk.model.config.DocumentConfNvSt; +import cokr.xit.ens.modules.nvsigntalk.model.config.XitProperty; + +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class AcceptDataByNvSigntalk extends AcceptData { + + private AES256 aes256 = new AES256(Crypto.AES256.getKey()); + + public AcceptDataByNvSigntalk(IntgrnSendMast intgrnSendMast, List intgrnSendDetails, Boolean isReserveSend) { + super(intgrnSendMast, intgrnSendDetails, isReserveSend); + } + + @Override + public NvSigntalkAcceptReqDTO createReqDto() { + NvSigntalkAcceptReqDTO acceptReqDTO = NvSigntalkAcceptReqDTO.builder() + .vender(intgrnSendMast.getVender().getCode()) + .org_cd(intgrnSendMast.getOrgCd()) + .tmplt_cd(intgrnSendMast.getTmpltCd()) + .post_bundle_title(intgrnSendMast.getPostBundleTitle()) + .send_dt(intgrnSendMast.getSendDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .close_dt(intgrnSendMast.getCloseDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) + .documents(intgrnSendDetails.stream().map(data -> this.createDocument(data)).collect(Collectors.toList())) + .build(); + + return acceptReqDTO; + } + + protected Document createDocument(IntgrnSendDetail intgrnSendDetail) { + + DocumentConfNvSt documentConf = gson.fromJson(intgrnSendDetail.getJAcptDocNvSt(), DocumentConfNvSt.class); + + return Document.builder() + .client_doc_id(intgrnSendDetail.getLinkedUuid()) + .ci(intgrnSendDetail.getCi()) + .valid_duration(documentConf.getValid_duration()) + .valid_duration_at(documentConf.getValid_duration_at()) + .redirect_url(documentConf.getRedirect_url()) + .publish_document_yn(documentConf.getPublish_document_yn()) + .document_hash(documentConf.getDocument_hash()) + .call_center_no(documentConf.getCall_center_no()) + .org_id(documentConf.getOrg_id()) + .auth_require_yn(documentConf.getAuth_require_yn()) + .notification(documentConf.getNotification()) + .xit_property(this.createXitProperty(intgrnSendDetail)) + .build(); + } + + protected XitProperty createXitProperty(IntgrnSendDetail intgrnSendDetail) { + return XitProperty.builder() + .mbl_page_data(CmmnUtil.isEmpty(intgrnSendDetail.getJMblPageData()) ? null : gson.fromJson(intgrnSendDetail.getJMblPageData(), Map.class)) + .bill_acpt_data(this.createBillAcptData(intgrnSendDetail)) + .jid(aes256.decrypt(intgrnSendDetail.getJid())) + .tmplt_msg_data(this.createTmpltMsgData(intgrnSendDetail)) + .build(); + } + + protected EnsBillAcptReqDTO createBillAcptData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getBill())) + return null; + return EnsBillAcptReqDTO.builder() + .billUid(intgrnSendDetail.getBill().getBillUid()) + .billerUserKey(intgrnSendDetail.getBill().getBillerUserKey()) + .billSe(intgrnSendDetail.getBill().getBillSeCd()) + .build(); + } + + + protected Map createTmpltMsgData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getJTmpltMsgData())) + return null; + else + return gson.fromJson(intgrnSendDetail.getJTmpltMsgData(), Map.class); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/domain/SendDetailMblPage.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/domain/SendDetailMblPage.java new file mode 100644 index 0000000..9a7adf6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/domain/SendDetailMblPage.java @@ -0,0 +1,39 @@ +package cokr.xit.ens.modules.common.ctgy.mblpage.domain; + +import cokr.xit.ens.modules.common.domain.BaseEntity; +import cokr.xit.ens.modules.common.ctgy.mblpage.domain.ids.SendDetailMblPageIds; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +import javax.persistence.*; + +@Entity +@Getter @ToString +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@IdClass(SendDetailMblPageIds.class) +@Table(name = "ens_snd_dtl_mbl_page", schema = "", catalog = "") +public class SendDetailMblPage extends BaseEntity { + + @Id + @Column(name = "post_se") +// @Enumerated(EnumType.STRING) + +// private PostSeCd postSe; + private String postSe; + @Id + @Column(name = "send_detail_id") + private Long sendDetailId; +// @EmbeddedId +// private SendDetailMblPageIds id; + + + @Column(name = "details", nullable = false) + @Lob + private String details; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/domain/ids/SendDetailMblPageIds.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/domain/ids/SendDetailMblPageIds.java new file mode 100644 index 0000000..77665cf --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/domain/ids/SendDetailMblPageIds.java @@ -0,0 +1,20 @@ +package cokr.xit.ens.modules.common.ctgy.mblpage.domain.ids; + +import lombok.*; + +import java.io.Serializable; + +@Getter +@Setter +@EqualsAndHashCode +@NoArgsConstructor +@Builder +@AllArgsConstructor +//@Embeddable +public class SendDetailMblPageIds implements Serializable { + + private String postSe; + + private Long sendDetailId; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/domain/repository/SendDetailMblPageRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/domain/repository/SendDetailMblPageRepository.java new file mode 100644 index 0000000..ce39596 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/domain/repository/SendDetailMblPageRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.modules.common.ctgy.mblpage.domain.repository; + +import cokr.xit.ens.modules.common.ctgy.mblpage.domain.SendDetailMblPage; +import cokr.xit.ens.modules.common.ctgy.mblpage.domain.ids.SendDetailMblPageIds; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SendDetailMblPageRepository extends JpaRepository { +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/model/SendDetailMblPageDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/model/SendDetailMblPageDTO.java new file mode 100644 index 0000000..34c8f8c --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/model/SendDetailMblPageDTO.java @@ -0,0 +1,33 @@ +package cokr.xit.ens.modules.common.ctgy.mblpage.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Map; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Schema(name = "SendDetailMblPageDTO") +public class SendDetailMblPageDTO { + + @NotBlank(message = "우편구분은 필수 입력값 입니다.") + @Schema(required = true, title = "우편구분", example = "testMblPage") + private String postSe; + + @NotNull(message = "발송상세ID는 필수 입력값 입니다.") + @Schema(required = true, title = "발송상세ID(PK)", example = "1") + private Long sendDetailId; + + @NotNull(message = "페이지데이터는 필수 입력값 입니다.") + @Schema(required = true, title = "페이지 내에 보여줄 상세 정보", example = "{\"details\":[{\"title\":\"텍스트 타입\",\"item_type\":\"TEXT\",\"properties\":{\"use_toggle\":false,\"style\":{\"highlight\":{\"하하하\":{\"use-clipboard\":true,\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"}}},\"hyperlink\":[\"http://www.naver.com\",\"http://www.xit.co.kr\"]},\"elements\":[\"test\",\"하하하\"]},{\"title\":\"PRE 텍스트 타입\",\"item_type\":\"PRE_TEXT\",\"properties\":{\"use_toggle\":false,\"style\":{\"highlight\":{\"다라마\":{\"use-clipboard\":true,\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"},\"1111-23123-12313\":{\"use-clipboard\":false,\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"}}},\"hyperlink\":[\"http://www.naver.com\",\"http://www.xit.co.kr\"]},\"elements\":\"가나다라마\\r\\nABCDEFGHI\\n1234567890\\n1111-23123-12313 카카오\\n카카오뱅크\\nhttp://www.naver.com\"},{\"title\":\"키-밸류 타입\",\"item_type\":\"KEY_VALUE\",\"properties\":{\"use_toggle\":false,\"style\":{\"highlight\":{\"액\":{\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"}}},\"hyperlink\":[\"http://www.naver.com\",\"http://www.xit.co.kr\"]},\"elements\":[{\"key\":\"당월 부과 금액\",\"value\":\"200,203원\",\"level\":1},{\"key\":\"미납액\",\"value\":\"1,200원\",\"level\":1}]},{\"title\":\"테이블 타입\",\"item_type\":\"TABLE\",\"properties\":{\"use_toggle\":false,\"style\":{\"text_align\":[\"center\",\"left\",\"right\"],\"highlight\":{\"전기료\":{\"font-size\":\"large\",\"font-color\":\"red\",\"font-weight\":\"bold\",\"font-style\":\"italic\"}}},\"hyperlink\":[\"http://www.naver.com\",\"http://www.xit.co.kr\"]},\"elements\":{\"head\":[\"항목\",\"당월금액\",\"전월대비\"],\"rows\":[[\"전기료\",\"1,000,000원\",\"+500,000\"],[\"수도료\",\"300,000원\",\"-100,000\"]]}},{\"title\":\"이미지 타입\",\"item_type\":\"IMAGE\",\"print_type\":\"이미지출력타입(공백: img태그(default), SLIDE: 슬라이드 기능 적용)\",\"properties\":{\"use_toggle\":false},\"elements\":[{\"key\":\"링크 이미지\",\"value\":\"http://www.xit.co.kr/....\"},{\"key\":\"Base64 이미지\",\"value\":\"data:image/png;base64,iVBORw0KGgoAAAAN....\"}]},{\"title\":\"링크버튼 타입\",\"item_type\":\"BUTTON\",\"link_url\":\"https://www.naver.com\"},{\"title\":\"결제버튼 타입\",\"item_type\":\"PAY_BUTTON\"}]}") + private Map>> document; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/presentation/MblPageControllerSupport.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/presentation/MblPageControllerSupport.java new file mode 100644 index 0000000..80d0032 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/presentation/MblPageControllerSupport.java @@ -0,0 +1,37 @@ +package cokr.xit.ens.modules.common.ctgy.mblpage.presentation; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.domain.SendMast; +import com.google.gson.Gson; +import org.springframework.beans.factory.annotation.Value; + +import java.util.HashMap; +import java.util.Map; + + +public abstract class MblPageControllerSupport { + private Gson gson = new Gson(); + @Value("${xit.mblpage.payinf.host}") + private String payInfHost; + + /** + * 페이버튼 결제정보 + * + * @param bill + * @param sendMast + * @return + */ + protected String getJsonPayBtnInf(Bill bill, SendMast sendMast) { + if (CmmnUtil.isEmpty(bill)) + return null; + + Map payBtnInf = new HashMap<>(); + payBtnInf.put("billUid", bill.getBillUid()); + payBtnInf.put("billSe", bill.getBillSeCd().getCode()); + payBtnInf.put("postSe", sendMast.getPostSe().getCode()); + payBtnInf.put("payInfHost", payInfHost); + + return gson.toJson(payBtnInf); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/presentation/SendDetailMblPageApiController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/presentation/SendDetailMblPageApiController.java new file mode 100644 index 0000000..b363a0d --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/presentation/SendDetailMblPageApiController.java @@ -0,0 +1,50 @@ +package cokr.xit.ens.modules.common.ctgy.mblpage.presentation; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.mblpage.domain.SendDetailMblPage; +import cokr.xit.ens.modules.common.ctgy.mblpage.model.SendDetailMblPageDTO; +import cokr.xit.ens.modules.common.ctgy.mblpage.service.SendDetailMblPageService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +@Tag(name = "SendDetailMblPageApiController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class SendDetailMblPageApiController { + + private final SendDetailMblPageService sendDetailMblPageTestService; + + + @Operation(summary = "테스트 모바일페이지 생성") + @PostMapping(value = "/cmft/mbl/page") + public ResponseEntity> mblPageCreate(@RequestBody SendDetailMblPageDTO dto) { + + EnsResponseVO responseVO = sendDetailMblPageTestService.create(dto); + + Map resultInfo = new HashMap<>(); + resultInfo.put("errCode", responseVO.getErrCode()); + resultInfo.put("errMsg", responseVO.getErrMsg()); + if (EnsErrCd.OK.equals(responseVO.getErrCode())) { + resultInfo.put("guide", String.format("[:도메인 or :IP]/cmft/mbl/page/%s/%d 를 호출하면 페이지를 확인 할 수 있습니다.", responseVO.getResultInfo().getPostSe(), responseVO.getResultInfo().getSendDetailId())); + resultInfo.put("uri", String.format("/cmft/mbl/page/%s/%d", responseVO.getResultInfo().getPostSe(), responseVO.getResultInfo().getSendDetailId())); + } else { + resultInfo.put("errDetails", responseVO.getResultInfo()); + } + + return new ResponseEntity>(resultInfo, HttpStatus.OK); + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/presentation/SendDetailMblPageController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/presentation/SendDetailMblPageController.java new file mode 100644 index 0000000..6440887 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/presentation/SendDetailMblPageController.java @@ -0,0 +1,64 @@ +package cokr.xit.ens.modules.common.ctgy.mblpage.presentation; + +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.mblpage.domain.SendDetailMblPage; +import cokr.xit.ens.modules.common.ctgy.mblpage.domain.ids.SendDetailMblPageIds; +import cokr.xit.ens.modules.common.ctgy.mblpage.domain.repository.SendDetailMblPageRepository; +import cokr.xit.ens.modules.common.domain.SendMast; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.Arrays; +import java.util.Optional; + +@Tag(name = "SendDetailMblPageTestController") +@Slf4j +@RequiredArgsConstructor +@Controller +public class SendDetailMblPageController extends MblPageControllerSupport { + + private final SendDetailMblPageRepository sendDetailMblPageRepository; + + + @Operation(summary = "모바일페이지 출력") + @GetMapping(value = "/cmft/mbl/page/{postSe}/{sendDetailId}") + public String mblPagePrnt(@PathVariable String postSe, @PathVariable Long sendDetailId, ModelMap model, @RequestParam(required = false, defaultValue = "") String billUid, @RequestParam(required = false, defaultValue = "") String billSe) { + + Optional sendDetailMblPage = sendDetailMblPageRepository.findById(SendDetailMblPageIds.builder() + .postSe(postSe) + .sendDetailId(sendDetailId) + .build()); + model.put("details", sendDetailMblPage.isPresent() ? sendDetailMblPage.get().getDetails() : "{}"); + Bill bill = Bill.builder() + .billUid(billUid) + .billSeCd(Arrays.stream(BillSeCd.values()) + .noneMatch(billSeCd -> billSeCd.getCode().equals(billSe)) + ? BillSeCd.all + : BillSeCd.valueOf(billSe)) + .build(); + SendMast sendMast = SendMast.builder() + .postSe(Arrays.stream(PostSeCd.values()) + .noneMatch(postSeCd -> postSeCd.getCode().equals(postSe)) + ? PostSeCd.kkoMydoc + : PostSeCd.valueOf(postSe)) + .build(); + model.put("payBtnInf", getJsonPayBtnInf(bill, sendMast)); + model.put("errCode", EnsErrCd.OK); + model.put("errMsg", EnsErrCd.OK.getCodeNm()); + + + return "modules/mblpage/notiprnt"; + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/service/SendDetailMblPageService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/service/SendDetailMblPageService.java new file mode 100644 index 0000000..25f13b8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/service/SendDetailMblPageService.java @@ -0,0 +1,76 @@ +package cokr.xit.ens.modules.common.ctgy.mblpage.service; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.MapDeserailizer; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.ctgy.mblpage.domain.SendDetailMblPage; +import cokr.xit.ens.modules.common.ctgy.mblpage.domain.repository.SendDetailMblPageRepository; +import cokr.xit.ens.modules.common.ctgy.mblpage.model.SendDetailMblPageDTO; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional(propagation = Propagation.REQUIRES_NEW) +public class SendDetailMblPageService { + + private final SendDetailMblPageRepository sendDetailMblPageRepository; + + private Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).serializeNulls().create(); + + /** + * 접수 서비스 + * + * @param dto + * @return + */ + public EnsResponseVO create(SendDetailMblPageDTO dto) { + + final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + Set> list = validator.validate(dto); + if (list.size() > 0) { + return EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ERR402) + .errMsg("유효하지 않은 요청값 입니다.") + .resultInfo(list.stream() + .map(row -> String.format("%s [ %s ]", row.getMessageTemplate(), row.getPropertyPath())) + .collect(Collectors.toList())) + .build(); + } + try { + PostSeCd.valueOf(dto.getPostSe()); + } catch (IllegalArgumentException e) { + throw new EnsException(EnsErrCd.ERR403, String.format("우편구분 \"%s\" 값이 유효하지 않습니다. %s", dto.getPostSe(), Arrays.stream(PostSeCd.values()).map(revnSeCd -> revnSeCd.getCode()).collect(Collectors.toList()).toString())); + } + + + + SendDetailMblPage sendDetailMblPage = SendDetailMblPage.builder() + .postSe(dto.getPostSe()) + .sendDetailId(dto.getSendDetailId()) + .details(gson.toJson(dto.getDocument())) + .build(); + sendDetailMblPageRepository.save(sendDetailMblPage); + + + return EnsResponseVO.okBuilder().resultInfo(sendDetailMblPage).build(); + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/code/LinkType.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/code/LinkType.java new file mode 100644 index 0000000..c1e8a54 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/code/LinkType.java @@ -0,0 +1,20 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.code; + +import cokr.xit.ens.core.code.CodeMapperType; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum LinkType implements CodeMapperType { + + socket("소켓통신"), rest("RESTful API"); + + @Getter + private final String codeNm; + + @Override + public String getCode() { + return this.name(); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/NiceCiMng.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/NiceCiMng.java new file mode 100644 index 0000000..1af6cc5 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/NiceCiMng.java @@ -0,0 +1,41 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.annotations.CreationTimestamp; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +@Getter @ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_nice_ci_mng", schema = "", catalog = "") +public class NiceCiMng { + + @Id +// @GeneratedValue(strategy=GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.TABLE, generator = "NiceCiMng_Generator") + @TableGenerator(table = "ens_seq_generator", name = "NiceCiMng_Generator" + ,pkColumnName = "seq_name", pkColumnValue = "NiceCiMng_id" + ,initialValue = 0, allocationSize = 200) + private Long niceCiMngId; + + + @Column(name = "ci", nullable = true) + private String ci; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "jid_mng_id") + private NiceJidMng niceJidMng; + + + @Column(name = "regist_dt", nullable = true) + @CreationTimestamp + private LocalDateTime registDt; + + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/NiceJidMng.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/NiceJidMng.java new file mode 100644 index 0000000..54809d7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/NiceJidMng.java @@ -0,0 +1,38 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.domain; + +import cokr.xit.ens.modules.common.domain.support.FieldError; +import lombok.*; +import org.hibernate.annotations.CreationTimestamp; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +@Getter @ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_nice_jid_mng", schema = "", catalog = "") +public class NiceJidMng { + + @Id +// @GeneratedValue(strategy=GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.TABLE, generator = "NiceJidMng_Generator") + @TableGenerator(table = "ens_seq_generator", name = "NiceJidMng_Generator" + ,pkColumnName = "seq_name", pkColumnValue = "NiceJidMng_id" + ,initialValue = 0, allocationSize = 200) + private Long jidMngId; + + + @Column(name = "jid", nullable = true) + private String jid; + + + @Column(name = "regist_dt", nullable = true) + @CreationTimestamp + private LocalDateTime registDt; + + @Embedded + private FieldError error; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceCiMngRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceCiMngRepository.java new file mode 100644 index 0000000..2cda057 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceCiMngRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.domain.repository; + +import cokr.xit.ens.modules.common.ctgy.nicedici.domain.NiceCiMng; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface NiceCiMngRepository extends JpaRepository, NiceCiMngRepositoryCustom { + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceCiMngRepositoryCustom.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceCiMngRepositoryCustom.java new file mode 100644 index 0000000..fb57826 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceCiMngRepositoryCustom.java @@ -0,0 +1,14 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.domain.repository; + +import java.util.Optional; + +public interface NiceCiMngRepositoryCustom { + + + /** + * ci 를 조회 한다. + * @param jid + * @return + */ + Optional findCiByJid(String jid); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceCiMngRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceCiMngRepositoryImpl.java new file mode 100644 index 0000000..810dffd --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceCiMngRepositoryImpl.java @@ -0,0 +1,36 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.domain.repository; + +import cokr.xit.ens.core.exception.code.EnsErrCd; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.util.Optional; + +import static cokr.xit.ens.modules.common.ctgy.nicedici.domain.QNiceCiMng.niceCiMng; +import static cokr.xit.ens.modules.common.ctgy.nicedici.domain.QNiceJidMng.niceJidMng; + +@RequiredArgsConstructor +public class NiceCiMngRepositoryImpl implements NiceCiMngRepositoryCustom { + + private final JPAQueryFactory query; + + @Override + public Optional findCiByJid(String jid) { + + return Optional.ofNullable( + query.select(niceCiMng.ci) + .from(niceCiMng) + .innerJoin(niceCiMng.niceJidMng, niceJidMng) + .where( + niceJidMng.jid.eq(jid) + .and(niceCiMng.ci.isNotNull()) + .and( + niceJidMng.error.errorCode.isEmpty() + .or(niceJidMng.error.errorCode.eq(EnsErrCd.OK.getCode())) + ) + ) + .fetchFirst() + ); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceJidMngRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceJidMngRepository.java new file mode 100644 index 0000000..d1e7797 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceJidMngRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.domain.repository; + +import cokr.xit.ens.modules.common.ctgy.nicedici.domain.NiceJidMng; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface NiceJidMngRepository extends JpaRepository, NiceJidMngRepositoryCustom { + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceJidMngRepositoryCustom.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceJidMngRepositoryCustom.java new file mode 100644 index 0000000..bea2ba6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceJidMngRepositoryCustom.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.domain.repository; + +public interface NiceJidMngRepositoryCustom { + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceJidMngRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceJidMngRepositoryImpl.java new file mode 100644 index 0000000..044b8fc --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/domain/repository/NiceJidMngRepositoryImpl.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.domain.repository; + +import com.querydsl.jpa.impl.JPAQueryFactory; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class NiceJidMngRepositoryImpl implements NiceJidMngRepositoryCustom{ + + private final JPAQueryFactory query; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/model/NiceDiCiRespDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/model/NiceDiCiRespDTO.java new file mode 100644 index 0000000..268a7ec --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/model/NiceDiCiRespDTO.java @@ -0,0 +1,19 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.model; + +import cokr.xit.ens.modules.common.domain.support.Error; +import lombok.Builder; +import lombok.Data; +import lombok.RequiredArgsConstructor; + +@Data +@RequiredArgsConstructor +public class NiceDiCiRespDTO extends Error { + + private String dici; + + + @Builder + public NiceDiCiRespDTO(String dici) { + this.dici = dici; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/presentation/NiceDiCiController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/presentation/NiceDiCiController.java new file mode 100644 index 0000000..4e012ac --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/presentation/NiceDiCiController.java @@ -0,0 +1,202 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.presentation; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.nicedici.code.LinkType; +import cokr.xit.ens.modules.common.ctgy.nicedici.service.NiceDiCiService; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.NiceCiApiExecutor; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.NiceCiRespDTO; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.NiceCiRespVO; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyCiResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodySymkeyResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils.SymmetricKey; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Arrays; + +@Tag(name = "NiceDiCiController") +@RestController +@RequiredArgsConstructor +public class NiceDiCiController { + + private final NiceDiCiService niceDiCiService; + + + @Value("${contract.nice.dici.rest.host}") + private String HOST; + @Value("${contract.nice.dici.rest.client-id}") + private String CLIENT_ID; + @Value("${contract.nice.dici.rest.client-secret}") + private String CLIENT_SECRET; + @Value("${contract.nice.dici.rest.api.generate-token}") + private String API_GENERATE_TOKEN; + @Value("${contract.nice.dici.rest.api.revoke-token}") + private String API_REVOKE_TOKEN; + @Value("${contract.nice.dici.rest.api.publickey}") + private String API_PUBLICKEY; + @Value("${contract.nice.dici.rest.api.symmetrickey}") + private String API_SYMMETRICKEY; + @Value("${contract.nice.dici.rest.api.ci}") + private String API_CI; + + + @Parameters({ + @Parameter(in = ParameterIn.PATH, name = "siteCode"), + @Parameter(in = ParameterIn.PATH, name = "sitePw"), + @Parameter(in = ParameterIn.QUERY, name = "jid"), + }) + @Operation(summary = "ci 변환") + @GetMapping("/cmft/nice/ci/{siteCode}/{sitePw}") + public ResponseEntity ci(@PathVariable String siteCode, @PathVariable String sitePw, @RequestParam String jid) { + EnsResponseVO responseVO = null; + + EnsResponseVO resp = niceDiCiService.ci(LinkType.socket, siteCode, sitePw, Arrays.asList(jid)); + + if (EnsErrCd.OK.equals(resp.getErrCode())) { + responseVO = EnsResponseVO.okBuilder() + .resultInfo(resp.getResultInfo()) + .build(); + + } else { + responseVO = resp; + } + + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + +// @Operation(summary = "1.토큰발급") +// @GetMapping("/cmft/nice/ci/rest/step1") +// public ResponseEntity> step1() { +// EnsResponseVO restResponseVO = niceCiApi.generateToken(SITE_CODE, SITE_PW); +// +// return new ResponseEntity>(restResponseVO, HttpStatus.OK); +// } +// +// @Operation(summary = "1-2.토큰폐기") +// @GetMapping("/cmft/nice/ci/rest/step1-2") +// public ResponseEntity> step1_2(@RequestBody Map mParam) { +// String accessToken = mParam.get("accessToken"); +// EnsResponseVO restResponseVO = niceCiApi.revokeToken(accessToken, SITE_CODE); +// +// return new ResponseEntity>(restResponseVO, HttpStatus.OK); +// } +// +// @Operation(summary = "2.공개키 요청") +// @GetMapping("/cmft/nice/ci/rest/step2") +// public ResponseEntity> step2(@RequestBody Map mParam) { +// String accessToken = mParam.get("accessToken"); +// String clientId = mParam.get("clientId"); +// String pubkeyVersion = mParam.get("pubkeyVersion"); +// String symkeyRegInfo = mParam.get("symkeyRegInfo"); +// EnsResponseVO restResponseVO = niceCiApi.generatePublickey(accessToken, clientId, pubkeyVersion, symkeyRegInfo); +// +// return new ResponseEntity>(restResponseVO, HttpStatus.OK); +// } +// +// @Operation(summary = "3.대칭키 요청") +// @GetMapping("/cmft/nice/ci/rest/step3") +// public ResponseEntity> step3(@RequestBody Map mParam) { +// String accessToken = mParam.get("accessToken"); +// String clientId = mParam.get("clientId"); +// String pubkeyVersion = mParam.get("pubkeyVersion"); +// String symkeyRegInfo = mParam.get("symkeyRegInfo"); +// EnsResponseVO restResponseVO = niceCiApi.generateSymmetrickey(accessToken, clientId, pubkeyVersion, symkeyRegInfo); +// +// return new ResponseEntity>(restResponseVO, HttpStatus.OK); +// } +// +// @Operation(summary = "4.CI 변환") +// @GetMapping("/cmft/nice/ci/rest/step4") +// public ResponseEntity> step4(@RequestBody Map mParam) { +// String clientId = mParam.get("clientId"); +// String clientSecret = mParam.get("clientSecret"); +// String symkeyVersion = mParam.get("symkeyVersion"); +// String encData = mParam.get("encData"); +// String integrityValue = mParam.get("integrityValue"); +// EnsResponseVO restResponseVO = niceCiApi.getCi(clientId, clientSecret, symkeyVersion, encData, integrityValue); +// +// return new ResponseEntity>(restResponseVO, HttpStatus.OK); +// } + + @Parameters({ + @Parameter(in = ParameterIn.PATH, name = "clientId"), + @Parameter(in = ParameterIn.PATH, name = "clientSecret"), + @Parameter(in = ParameterIn.QUERY, name = "jid"), + }) + @Operation(summary = "CI 변환(rest API)") + @GetMapping(value = "/cmft/nice/ci/rest/{clientId}/{clientSecret}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity getCi(@PathVariable String clientId, @PathVariable String clientSecret, @RequestParam String jid) { + EnsResponseVO responseVO = null; + + EnsResponseVO resp = niceDiCiService.ci(LinkType.rest, clientId, clientSecret, Arrays.asList(jid)); + + if (EnsErrCd.OK.equals(resp.getErrCode())) { + responseVO = EnsResponseVO.okBuilder() + .resultInfo(resp.getResultInfo()) + .build(); + + } else { + responseVO = resp; + } + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + + @Parameters({ + @Parameter(in = ParameterIn.PATH, name = "jid"), + }) + @Operation(summary = "CI 변환(rest API) 테스트") + @GetMapping(value = "/cmft/nice/ci/rest/{jid}/test", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity getCiTest(@PathVariable String jid) throws Exception { + + final ObjectMapper mapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + final String respBody = "{ \"dataHeader\": { \"CNTY_CD\": \"ko\", \"GW_RSLT_CD\": \"1200\", \"GW_RSLT_MSG\": \"오류 없음\" }, \"dataBody\": { \"rsp_cd\": \"P000\", \"result_cd\": \"0000\", \"symkey_stat_info\": \"{\\\"cur_symkey_version\\\":\\\"2022050990141666-D28C-IP9E-A61E-8C54984218ED\\\",\\\"cur_valid_dtim\\\":\\\"20221109142207\\\",\\\"bef_symkey_version\\\":\\\"20220506A6834B1B-1288-IPCD-965C-8C9B30558CCF\\\",\\\"bef_valid_dtim\\\":\\\"20221106180509\\\"}\" }}"; + + String strRespBody = respBody.replace("\"\"", "null"); + strRespBody = strRespBody.replace("\\", "").replace("\"{", "{").replace("}\"", "}"); + NiceCiRespDTO respDTO = mapper.readValue(strRespBody, new TypeReference>() { + }); + if (!(respDTO.getDataBody() == null || "".equals(respDTO.getDataBody()))) { + respDTO.getDataBody().setSiteCode("R0k3Nw=="); + respDTO.getDataBody().setRequestNo("tpvqiofuregohiogpcsuxtdejqkfwj"); + respDTO.getDataBody().setKey("quwvgxnyqalbguobfbtmfrlhroprqdwi"); + respDTO.getDataBody().setIv("ealxvqbxgrmcvrgs"); + respDTO.getDataBody().setHmacKey("oldiptsfqlrrqkkvbpihjtjyqgdajxym"); + } + NiceCiApiExecutor executor = NiceCiApiExecutor.builder() + .HOST(this.HOST) + .CLIENT_ID(this.CLIENT_ID) + .CLIENT_SECRET(this.CLIENT_SECRET) + .API_GENERATE_TOKEN(this.API_GENERATE_TOKEN) + .API_REVOKE_TOKEN(this.API_REVOKE_TOKEN) + .API_PUBLICKEY(this.API_PUBLICKEY) + .API_SYMMETRICKEY(this.API_SYMMETRICKEY) + .API_CI(this.API_CI) + .build(); + SymmetricKey.getInstance(this.CLIENT_ID, respDTO.getDataBody()); + NiceCiRespVO ciResponseVO = executor.ci(jid, "127.0.0.1"); + + + EnsResponseVO responseVO = EnsResponseVO.okBuilder().resultInfo(ciResponseVO).build(); + return new ResponseEntity(responseVO, HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/service/NiceDiCiService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/service/NiceDiCiService.java new file mode 100644 index 0000000..4217343 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/service/NiceDiCiService.java @@ -0,0 +1,233 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.service; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.nicedici.code.LinkType; +import cokr.xit.ens.modules.common.ctgy.nicedici.domain.NiceCiMng; +import cokr.xit.ens.modules.common.ctgy.nicedici.domain.NiceJidMng; +import cokr.xit.ens.modules.common.ctgy.nicedici.domain.repository.NiceCiMngRepository; +import cokr.xit.ens.modules.common.ctgy.nicedici.domain.repository.NiceJidMngRepository; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.NiceCiGenerator; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils.SymmetricKey; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.socket.Interop; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class NiceDiCiService { + + private final NiceJidMngRepository niceJidMngRepository; + private final NiceCiMngRepository niceCiMngRepository; + + + @Value("${contract.nice.dici.type}") + private String type; + @Value("${contract.nice.dici.socket.proxy.use}") + private boolean isProxyUse; + @Value("${contract.nice.dici.socket.proxy.origin}") + private String proxyOrigin; + @Value("${contract.nice.dici.socket.proxy.path}") + private String proxyPath; + + private final NiceCiGenerator niceCiGenerator; + + + /** + * 주민번호로 CI를 취득 한다. + * -.CI: 연계정보(Connecting Information) + * -.국가표준 규격에 따라 사용자의 주민번호를 암호화한 개인 식별값. + * -.서비스에 상관없이 값이 일정 함. + * -.주민번호 -> 해쉬 -> CI 값 (88 byte) + * + * @param siteCode + * @param sitePw + * @param jids + */ + @SuppressWarnings("deprecation") +// @Transactional(noRollbackFor = Exception.class) + @Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor = Exception.class) + public EnsResponseVO ci(String siteCode, String sitePw, String clientId, String clientSecret, List jids) { + LinkType type = LinkType.valueOf(this.type); + switch (type) { + case socket: + return this.ci(type, siteCode, sitePw, jids); + case rest: + return this.ci(type, clientId, clientSecret, jids); + default: + return this.ci(LinkType.socket, siteCode, sitePw, jids); + } + } + + @Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor = Exception.class) + public EnsResponseVO ci(LinkType linkType, String id, String pw, List jids) { + + EnsResponseVO responseVO = null; + try { + if (CmmnUtil.isEmpty(id)) + throw new EnsException(EnsErrCd.ERR401, "사이트코드(은)는 필수조건 입니다."); + if (CmmnUtil.isEmpty(pw)) + throw new EnsException(EnsErrCd.ERR401, "사이트 패스워드(은)는 필수조건 입니다."); + if (CmmnUtil.isEmpty(jids)) + throw new EnsException(EnsErrCd.ERR401, "서비스 구분값(주민번호:JID)(은)는 필수조건 입니다."); + + + jids = jids.stream() + .map(jid -> jid.replaceAll("[^0-9]", "")) + .collect(Collectors.toList()) + .stream() + .distinct() + .collect(Collectors.toList()); + AtomicInteger i = new AtomicInteger(); + List responseVOList = jids.stream() + .map(jid -> { + EnsResponseVO result = null; + String encJid = null; + String ci = null; + try { + try { + encJid = hexSha256(jid); + } catch (NoSuchAlgorithmException | IOException e) { + log.error("주민번호(%s) 단방향암호화(sha256) 실패:: %e", jid, e.getMessage(), e); + } + + Optional findCi = niceCiMngRepository.findCiByJid(encJid); + if (findCi.isPresent()) { + ci = findCi.get(); + result = EnsResponseVO.okBuilder().build(); + + } else { + if (linkType.equals(LinkType.socket)) { + if (isProxyUse) { + result = Interop.getCIProxy(proxyOrigin, proxyPath, id, pw, jid); + } else { + result = Interop.getCI(id, pw, jid); + } + } else { + if (0 == i.getAndIncrement()) + if (!SymmetricKey.isValidStat(id)) + niceCiGenerator.initialKey(id, pw); + result = niceCiGenerator.getCI(jid, null, id, pw); + } + + ci = EnsErrCd.OK.equals(result.getErrCode()) ? String.valueOf(result.getResultInfo()) : null; + return result; + } + + } catch (Exception e) { + result = EnsResponseVO.errBuilder() + .errCode(EnsErrCd.ERR904) + .errMsg(String.format("%s. %s", EnsErrCd.ERR904, e.getMessage())) + .build(); + + } finally { + Map resultInfo = new HashMap<>(); + resultInfo.put("jid", jid); + resultInfo.put("ci", ci); + if (EnsErrCd.OK.equals(result.getErrCode())) + return EnsResponseVO.>okBuilder().resultInfo(resultInfo).build(); + else + return EnsResponseVO.>errRsltBuilder() + .errCode(result.getErrCode()) + .errMsg(result.getErrMsg()) + .resultInfo(resultInfo) + .build(); + } + }) + .collect(Collectors.toList()); + + + + List niceCiMngs = responseVOList.stream() + .map(row -> { + Map resultInfo = (Map) row.getResultInfo(); + String encJid = null; + String ci = resultInfo.get("ci"); + try { + String onlyNumJid = resultInfo.get("jid").replaceAll("[^0-9]", ""); + encJid = hexSha256(onlyNumJid); + } catch (NoSuchAlgorithmException | IOException e) { + log.error("주민번호(%s) 단방향암호화(sha256) 실패:: %e", resultInfo.get("jid"), e.getMessage(), e); + } + NiceJidMng niceJidMng = NiceJidMng.builder() + .jid(encJid) + .error(FieldError.initBuilder() + .errorCode(row.getErrCode().getCode()) + .errorMessage(row.getErrMsg()) + .build()) + .build(); + return NiceCiMng.builder() + .ci(ci) + .niceJidMng(niceJidMng) + .build(); + }) + .collect(Collectors.toList()); + niceJidMngRepository.saveAll(niceCiMngs.stream() + .map(row -> row.getNiceJidMng()) + .collect(Collectors.toList())); + niceJidMngRepository.flush(); + niceCiMngRepository.saveAll(niceCiMngs); + niceCiMngRepository.flush(); + + + responseVO = EnsResponseVO.okBuilder().resultInfo(responseVOList).build(); + + } catch (EnsException e) { + responseVO = EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + + + return responseVO; + + } + + + /** + * sha256 암호화 + * + * @param text + * @return + * @throws IOException + * @throws NoSuchAlgorithmException + */ + public static String hexSha256(String text) throws IOException, NoSuchAlgorithmException { + StringBuffer sbuf = new StringBuffer(); + + MessageDigest mDigest = MessageDigest.getInstance("SHA-256"); + mDigest.update(text.getBytes()); + + byte[] msgStr = mDigest.digest(); + + for (int i = 0; i < msgStr.length; i++) { + byte tmpStrByte = msgStr[i]; + String tmpEncTxt = Integer.toString((tmpStrByte & 0xff) + 0x100, 16).substring(1); + + sbuf.append(tmpEncTxt); + } + + return sbuf.toString(); + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/NiceCiApiExecutor.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/NiceCiApiExecutor.java new file mode 100644 index 0000000..b35d630 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/NiceCiApiExecutor.java @@ -0,0 +1,112 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest; + +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.api.CiRequest; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.api.PubkeyRequest; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.api.SymkeyRegist; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.api.TokenGenerate; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.code.NiceCiApiCd; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.NiceCiRespVO; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyCiResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyGenerateTokenResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyPubkeyResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodySymkeyResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils.PublicKey; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils.SymmetricKey; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils.Token; +import lombok.Builder; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RequiredArgsConstructor +@Builder +public class NiceCiApiExecutor { + private final String HOST; + private final String CLIENT_ID; + private final String CLIENT_SECRET; + private final String API_GENERATE_TOKEN; + private final String API_REVOKE_TOKEN; + private final String API_PUBLICKEY; + private final String API_SYMMETRICKEY; + private final String API_CI; + + + public NiceCiRespVO token() throws Exception { + NiceCiRespVO result = null; + if (Token.isValidStat(this.CLIENT_ID)) { + result = NiceCiRespVO.okBuilder() + .resultInfo(Token.getInstance().getData(this.CLIENT_ID)) + .build(); + } else { + result = TokenGenerate.builder() + .HOST(this.HOST) + .API_URL_GENERATE_TOKEN(this.API_GENERATE_TOKEN) + .API_URL_REVOKE_TOKEN(this.API_REVOKE_TOKEN) + .build() + .execute(CLIENT_ID, CLIENT_SECRET); + + if (NiceCiApiCd.OK.equals(result.getErrCode())) + Token.getInstance(this.CLIENT_ID, result.getResultInfo()); + } + + + return result; + } + + + public NiceCiRespVO pubkey() throws Exception { + NiceCiRespVO result = null; + if (PublicKey.isValidStat(this.CLIENT_ID)) { + result = NiceCiRespVO.okBuilder() + .resultInfo(PublicKey.getInstance().getData(this.CLIENT_ID)) + .build(); + } else { + result = PubkeyRequest.builder() + .HOST(this.HOST) + .API_URL(this.API_PUBLICKEY) + .build() + .execute(this.CLIENT_ID); + + if (NiceCiApiCd.OK.equals(result.getErrCode())) + PublicKey.getInstance(this.CLIENT_ID, result.getResultInfo()); + } + + return result; + } + + + public NiceCiRespVO symkey() throws Exception { + NiceCiRespVO result = null; + if (SymmetricKey.isValidStat(this.CLIENT_ID)) { + result = NiceCiRespVO.okBuilder() + .resultInfo(SymmetricKey.getInstance().getData(this.CLIENT_ID)) + .build(); + } else { + result = SymkeyRegist.builder() + .HOST(this.HOST) + .API_URL(this.API_SYMMETRICKEY) + .build() + .execute(this.CLIENT_ID); + + if (NiceCiApiCd.OK.equals(result.getErrCode())) + SymmetricKey.getInstance(this.CLIENT_ID, result.getResultInfo()); + } + + + return result; + } + + + public NiceCiRespVO ci(String jid, String clientIp) throws Exception { + + NiceCiRespVO result = CiRequest.builder() + .HOST(this.HOST) + .API_URL(this.API_CI) + .build() + .execute(this.CLIENT_ID, this.CLIENT_SECRET, jid, clientIp); + + return result; + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/NiceCiGenerator.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/NiceCiGenerator.java new file mode 100644 index 0000000..cb6c443 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/NiceCiGenerator.java @@ -0,0 +1,135 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.code.NiceCiApiCd; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.domain.NiceCiSymkeyMng; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.domain.repository.NiceCiSymkeyMngRepository; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.NiceCiRespVO; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyCiResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyGenerateTokenResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyPubkeyResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodySymkeyResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils.SymmetricKey; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Optional; + +@Log4j2 +@Component +@RequiredArgsConstructor +public class NiceCiGenerator { + + private final NiceCiSymkeyMngRepository niceCiSymkeyMngRepository; + + @Value("${contract.nice.dici.rest.host}") + private String HOST; + @Value("${contract.nice.dici.rest.api.generate-token}") + private String API_GENERATE_TOKEN; + @Value("${contract.nice.dici.rest.api.revoke-token}") + private String API_REVOKE_TOKEN; + @Value("${contract.nice.dici.rest.api.publickey}") + private String API_PUBLICKEY; + @Value("${contract.nice.dici.rest.api.symmetrickey}") + private String API_SYMMETRICKEY; + @Value("${contract.nice.dici.rest.api.ci}") + private String API_CI; + + public EnsResponseVO initialKey(String clientId, String clientSecret) { + + NiceCiApiExecutor executor = buildExecutor(clientId, clientSecret); + try { + + NiceCiRespVO tokenResponseVO = executor.token(); + if (!NiceCiApiCd.OK.equals(tokenResponseVO.getErrCode())) + return EnsResponseVO.errRsltBuilder().errCode(EnsErrCd.ERR600).errMsg(tokenResponseVO.getErrCode().getCode() + " " + tokenResponseVO.getErrMsg()).build(); + + NiceCiRespVO pubkeyResponseVO = executor.pubkey(); + if (!NiceCiApiCd.OK.equals(pubkeyResponseVO.getErrCode())) + return EnsResponseVO.errRsltBuilder().errCode(EnsErrCd.ERR600).errMsg(pubkeyResponseVO.getErrCode().getCode() + " " + pubkeyResponseVO.getErrMsg()).build(); + +// NiceCiRespVO symkeyResponseVO = executor.symkey(); +// if (!NiceCiApiCd.OK.equals(symkeyResponseVO.getErrCode())) +// return EnsResponseVO.errRsltBuilder().errCode(EnsErrCd.ERR600).errMsg(symkeyResponseVO.getErrCode().getCode() + " " + symkeyResponseVO.getErrMsg()).build(); + ObjectMapper mapper = new ObjectMapper(); + DataBodySymkeyResp dataBodySymkeyResp = null; + if (SymmetricKey.isValidStat(clientId)) { + dataBodySymkeyResp = SymmetricKey.getInstance().getData(clientId); + } else { + +// Optional niceCiSymkeyMng = niceCiSymkeyMngRepository.findByClientIdAndPubkey(clientId, pubkeyResponseVO.getResultInfo().getPublicKey()); + List niceCiSymkeyMngs = niceCiSymkeyMngRepository.findAllByClientIdAndPubkeyOrderByRegistDtDesc(clientId, pubkeyResponseVO.getResultInfo().getPublicKey()); + Optional niceCiSymkeyMng = Optional.ofNullable(niceCiSymkeyMngs == null || niceCiSymkeyMngs.isEmpty() ? null : niceCiSymkeyMngs.get(0)); + + + if (niceCiSymkeyMng.isPresent() + && (Long.parseLong(niceCiSymkeyMng.get().getExpireDt()) > Long.parseLong(LocalDateTime.now().plusDays(1).format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))))) { + dataBodySymkeyResp = mapper.readValue(niceCiSymkeyMng.get().getRespJsonData(), DataBodySymkeyResp.class); + + + SymmetricKey.getInstance(clientId, dataBodySymkeyResp); + + } else { + + NiceCiRespVO symkeyResponseVO = executor.symkey(); + if (!NiceCiApiCd.OK.equals(symkeyResponseVO.getErrCode())) + return EnsResponseVO.errRsltBuilder().errCode(EnsErrCd.ERR600).errMsg(symkeyResponseVO.getErrCode().getCode() + " " + symkeyResponseVO.getErrMsg()).build(); + dataBodySymkeyResp = symkeyResponseVO.getResultInfo(); + + + niceCiSymkeyMngRepository.save(NiceCiSymkeyMng.builder() + .clientId(clientId) + .pubkey(pubkeyResponseVO.getResultInfo().getPublicKey()) + .symkey(dataBodySymkeyResp.getKey()) + .expireDt(dataBodySymkeyResp.getSymkeyStatInfo().getCurValidDtim()) + .version(dataBodySymkeyResp.getSymkeyStatInfo().getCurSymkeyVersion()) + .iv(dataBodySymkeyResp.getIv()) + .hmacKey(dataBodySymkeyResp.getHmacKey()) + .respJsonData(mapper.writeValueAsString(dataBodySymkeyResp)) + .build()); + } + } + + + return EnsResponseVO.okBuilder().build(); + } catch (Exception e) { + return EnsResponseVO.errRsltBuilder().errCode(EnsErrCd.ERR699).errMsg(e.getMessage()).build(); + } + } + + public EnsResponseVO getCI(String jid, String clientIp, String clientId, String clientSecret) { + + NiceCiApiExecutor executor = buildExecutor(clientId, clientSecret); + + try { + NiceCiRespVO ciResponseVO = executor.ci(jid, clientIp); + if (!NiceCiApiCd.OK.equals(ciResponseVO.getErrCode())) + return EnsResponseVO.errRsltBuilder().errCode(EnsErrCd.ERR600).errMsg(ciResponseVO.getErrCode().getCode() + " " + ciResponseVO.getErrMsg()).build(); + + + return EnsResponseVO.okBuilder().resultInfo(ciResponseVO.getResultInfo().getDecEncData().getCi1()).build(); + } catch (Exception e) { + return EnsResponseVO.errRsltBuilder().errCode(EnsErrCd.ERR699).errMsg(e.getMessage()).build(); + } + } + + private NiceCiApiExecutor buildExecutor(String clientId, String clientSecret) { + return NiceCiApiExecutor.builder() + .HOST(this.HOST) + .CLIENT_ID(clientId) + .CLIENT_SECRET(clientSecret) + .API_GENERATE_TOKEN(this.API_GENERATE_TOKEN) + .API_REVOKE_TOKEN(this.API_REVOKE_TOKEN) + .API_PUBLICKEY(this.API_PUBLICKEY) + .API_SYMMETRICKEY(this.API_SYMMETRICKEY) + .API_CI(this.API_CI) + .build(); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/CiRequest.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/CiRequest.java new file mode 100644 index 0000000..4fe0cb1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/CiRequest.java @@ -0,0 +1,245 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.api; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.code.NiceCiApiCd; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.NiceCiRespDTO; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.NiceCiRespVO; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyCiResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodySymkeyResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.EncData; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils.SymmetricKey; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.experimental.SuperBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Base64Util; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.Base64Utils; + +import javax.crypto.*; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.Charset; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@SuperBuilder +public class CiRequest extends NiceCiApiAbstract { + + protected final String HOST; + protected final String API_URL; + + + public NiceCiRespVO execute(String clientId, String clientSecret, String jumin, String clientIp) throws Exception { + if (CmmnUtil.isEmpty(clientId)) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("클라이언트ID는 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(clientSecret)) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("클라이언트비밀번호는 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(SymmetricKey.getInstance().getData(clientId).getKey())) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("대칭키는 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(SymmetricKey.getInstance().getData(clientId).getSymkeyStatInfo().getCurSymkeyVersion())) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("대칭키 버전은 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(SymmetricKey.getInstance().getData(clientId).getSiteCode())) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("사이트코드는 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(SymmetricKey.getInstance().getData(clientId).getRequestNo())) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("신청번호는 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(SymmetricKey.getInstance().getData(clientId).getIv())) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("IV는 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(SymmetricKey.getInstance().getData(clientId).getHmacKey())) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("HmacKey는 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(jumin)) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("주민번호는 필수 입력값 입니다.").build(); + + + NiceCiRespDTO responseDTO = this.getCi(clientId, clientSecret, SymmetricKey.getInstance().getData(clientId), jumin, clientIp); + + + if (!"1200".equals(responseDTO.getDataHeader().getGW_RSLT_CD())) + return NiceCiRespVO.errBuilder() + .errCode(NiceCiApiCd.valueOfEnum("HEAD_" + responseDTO.getDataHeader().getGW_RSLT_CD())) + .errMsg(String.format("[%s]: %s", responseDTO.getDataHeader().getGW_RSLT_CD(), responseDTO.getDataHeader().getGW_RSLT_MSG())) + .build(); + if (!"P000".equals(responseDTO.getDataBody().getRspCd())) + return NiceCiRespVO.errBuilder() + .errCode(NiceCiApiCd.valueOfEnum(responseDTO.getDataBody().getRspCd())) + .errMsg(String.format("[%s]: %s. %s", responseDTO.getDataBody().getRspCd(), NiceCiApiCd.valueOfEnum(responseDTO.getDataBody().getRspCd()).getCodeNm(), responseDTO.getDataBody().getResMsg())) + .build(); + if (!"0000".equals(responseDTO.getDataBody().getResultCd())) + return NiceCiRespVO.errBuilder() + .errCode(NiceCiApiCd.valueOfEnum("CI_" + responseDTO.getDataBody().getResultCd())) + .errMsg(String.format("[%s]: %s", responseDTO.getDataBody().getResultCd(), NiceCiApiCd.valueOfEnum("CI_" + responseDTO.getDataBody().getResultCd()).getCodeNm())) + .build(); + + + if (!responseDTO.getDataBody().getIntegrityValue().equals(createIntegrityValue(responseDTO.getDataBody().getEncData(), SymmetricKey.getInstance().getData(clientId).getHmacKey()))) + return NiceCiRespVO.errBuilder() + .errCode(NiceCiApiCd.FAIL) + .errMsg("응답데이터 무결성 체크 오류") + .build(); + String decEncDataStr = this.decEncData(responseDTO.getDataBody().getEncData(), SymmetricKey.getInstance().getData(clientId).getKey(), SymmetricKey.getInstance().getData(clientId).getIv()); + responseDTO.getDataBody().setDecEncData(mapper.readValue(decEncDataStr, EncData.class)); + + + return NiceCiRespVO.okBuilder().resultInfo(responseDTO.getDataBody()).build(); + + } + + + protected NiceCiRespDTO getCi(String clientId, String clientSecret, DataBodySymkeyResp symkeyResp, String jumin, String clientIp) throws Exception { + try { + + +// String authorizationToken = Base64.getEncoder().encodeToString(String.format("%s:%s", clientId, clientSecret).getBytes(StandardCharsets.UTF_8)); + String authorizationToken = Base64Util.encode(String.format("%s:%s", clientId, clientSecret)); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + headers.set("Authorization", String.format("Basic %s", authorizationToken)); + headers.set("productID", PRODUCT_ID); + + + StringBuilder url = new StringBuilder(); + url.append(this.HOST) + .append(this.API_URL); + final String strEncData = this.createEncData(symkeyResp.getSiteCode(), jumin, symkeyResp.getRequestNo(), LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")), clientIp); + final String encData = this.encEncData(strEncData, symkeyResp.getKey(), symkeyResp.getIv()); + final String integrityValue = this.createIntegrityValue(encData, symkeyResp.getHmacKey()); + final String jsonStr = this.createMessage(symkeyResp.getSymkeyStatInfo().getCurSymkeyVersion(), encData, integrityValue); + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers); + log.info("=================================================================================="); + log.info("==== 아이핀 CI 요청 Info... ===="); + log.info("[Body]: " + jsonStr); + log.info("[encData]: " + strEncData); + log.info("==== 아이핀 CI 요청 Result Info... ===="); + log.info("[Headers]: " + resp.getHeaders().toString()); + log.info("[Body]: " + resp.getBody()); + log.info("=================================================================================="); + + + + String strRespBody = resp.getBody().replace("\"\"", "null"); + NiceCiRespDTO respDTO = mapper.readValue(strRespBody, new TypeReference>(){}); + + + return respDTO; + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("아이핀 CI 요청 실패." + e.getMessage()); + } + + + } + + + /** + * JSON 포맷의 요청메시지 생성 + * + * @param symkeyVersion + * @param encData + * @param integrityValue + * @return + * @throws JsonProcessingException + */ + protected String createMessage(String symkeyVersion, String encData, String integrityValue) throws JsonProcessingException { + Map dataHeader = new HashMap<>(); + dataHeader.put("CNTY_CD", "ko"); + dataHeader.put("TRAN_ID", null); + + Map dataBody = new HashMap<>(); + dataBody.put("symkey_version", symkeyVersion); + dataBody.put("enc_data", encData); + dataBody.put("integrity_value", integrityValue); + + Map m = new HashMap<>(); + m.put("dataHeader", dataHeader); + m.put("dataBody", dataBody); + + return mapper.writeValueAsString(m); + } + + private String createEncData(String siteCode, String jid, String reqNo, String reqDtim, String clientIp) throws JsonProcessingException { + Map m = new HashMap<>(); + m.put("site_code", siteCode); + m.put("info_req_type", "1"); + m.put("jumin_id", jid.replaceAll("[^0-9]", "")); + m.put("req_no", reqNo); + m.put("req_dtim", reqDtim); + m.put("client_ip", clientIp); + + return mapper.writeValueAsString(m); + + + } + + private String encEncData(String encData, String symkey, String iv) throws IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException { + + + SecretKey secureKey = new SecretKeySpec(symkey.getBytes(), "AES"); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, secureKey, new IvParameterSpec(iv.getBytes())); + byte[] encrypted = cipher.doFinal(encData.trim().getBytes()); + + + String reqDataEnc = Base64Utils.encodeToString(encrypted); + + return reqDataEnc; + } + + + private String decEncData(String encData, String symkey, String iv) throws IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException { + + + byte[] respDataEnc = Base64Utils.decode(encData.getBytes()); + + + SecretKey secureKey = new SecretKeySpec(symkey.getBytes(), "AES"); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, secureKey, new IvParameterSpec(iv.getBytes())); + byte[] decrypted = cipher.doFinal(respDataEnc); + String strDecrypted = new String(decrypted); + + return strDecrypted; + } + + + /** + * Hmac 무결성체크값(integrity_value) 생성 + * + * @param encData + * @param hmacKey + * @return + */ + private String createIntegrityValue(String encData, String hmacKey) { + byte[] hmacSha256 = hmac256(hmacKey.getBytes(), encData.getBytes()); + String integrityValue = Base64.getEncoder().encodeToString(hmacSha256); + + return integrityValue; + } + + private byte[] hmac256(byte[] secretKey, byte[] message) { + byte[] hmac256 = null; + try { + Mac mac = Mac.getInstance("HmacSHA256"); + SecretKeySpec sks = new SecretKeySpec(secretKey, "HmacSHA256"); + mac.init(sks); + hmac256 = mac.doFinal(message); + return hmac256; + } catch (Exception e) { + throw new RuntimeException("Failed to generate HMACSHA256 encrypt"); + } + } + + +} + diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/NiceCiApiAbstract.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/NiceCiApiAbstract.java new file mode 100644 index 0000000..424bcc3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/NiceCiApiAbstract.java @@ -0,0 +1,121 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.api; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.experimental.SuperBuilder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.*; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.Random; + +@Slf4j +@SuperBuilder +public class NiceCiApiAbstract { + + protected final String PRODUCT_ID = "2101466024"; + + protected final ObjectMapper mapper = new ObjectMapper() + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + + + /** + *

메소드 설명: API 호출
+     * 
+ * + * @param method + * @param url + * @param body + * @param headers + * @return ResponseEntity 요청처리 후 응답객체 + * @author: 박민규 + */ + protected final ResponseEntity callApi(HttpMethod method, String url, Object body, HttpHeaders headers) { + + StringBuffer sb = new StringBuffer(); + ResponseEntity responseEntity = null; + try { + + HttpEntity entity = null; + UriComponents uri = null; + switch (method) { + case GET: + entity = new HttpEntity<>(headers); + uri = UriComponentsBuilder + .fromHttpUrl(String.format("%s?%s", url, body == null ? "" : body)) +// .encode(StandardCharsets.UTF_8) //"%"기호가 "%25"로 인코딩 발생하여 주석처리 함. + .build(false); + break; + case POST: + entity = new HttpEntity<>(body, headers); + uri = UriComponentsBuilder + .fromHttpUrl(url) + .encode(StandardCharsets.UTF_8) + .build(); + break; + + default: + break; + } + + + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + factory.setConnectTimeout(3000); +// factory.setReadTimeout(3000); + factory.setReadTimeout(10000); + RestTemplate restTemplate = new RestTemplate(factory); + sb.append("\n url => " + uri.toString()) + .append("\n method => " + method) + .append("\n headers => " + entity.getHeaders().toString()) + .append("\n body => " + entity.getBody()); + responseEntity = restTemplate.exchange(URI.create(uri.toString()), method, entity, String.class); + + /* + * HttpStatus 정보 확인 방법 + * -.코드: responseEntity.getStatusCodeValue() + * -.메시지: responseEntity.getStatusCode() + */ + + } catch (HttpServerErrorException e) { + responseEntity = new ResponseEntity(e.getResponseBodyAsString(), e.getStatusCode()); + log.error(String.format("call API 서버오류[url =>%s param => %s error => %s]", url, body, e.getMessage())); + } catch (HttpClientErrorException e) { + responseEntity = new ResponseEntity(e.getResponseBodyAsString(), e.getStatusCode()); + log.error(String.format("call API 클라이언트오류[url =>%s param => %s error => %s]", url, body, e.getMessage())); + } catch (RestClientException e) { + responseEntity = new ResponseEntity(e.getMessage(), HttpStatus.REQUEST_TIMEOUT); + log.error(String.format("RestAPI 호출 오류[url =>%s param => %s error => %s]", url, body, e.getMessage())); + } catch (Exception e) { + responseEntity = new ResponseEntity(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + log.error(String.format("call API 기타오류[url =>%s param => %s error => %s]", url, body, e.getMessage())); + } finally { + log.info("나이스 API(CI변환) API\n[ REQUEST ]-----------------------------------------------------------------------\n{}\n[ RESPONSE ]-----------------------------------------------------------------------\n{}", sb.toString(), responseEntity.getBody()); + } + + + return responseEntity; + } + + + protected final String randomAlphaWord(int wordLength) { + Random r = new Random(); + + StringBuilder sb = new StringBuilder(wordLength); + for (int i = 0; i < wordLength; i++) { + char tmp = (char) ('a' + r.nextInt('z' - 'a')); + sb.append(tmp); + + } + return sb.toString(); + + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/PubkeyRequest.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/PubkeyRequest.java new file mode 100644 index 0000000..cbd4257 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/PubkeyRequest.java @@ -0,0 +1,124 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.api; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.code.NiceCiApiCd; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.NiceCiRespDTO; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.NiceCiRespVO; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyPubkeyResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils.Token; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.experimental.SuperBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Base64Util; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; + +import java.nio.charset.Charset; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@SuperBuilder +public class PubkeyRequest extends NiceCiApiAbstract { + + protected final String HOST; + protected final String API_URL; + + + public NiceCiRespVO execute(String clientId) throws Exception { + if (CmmnUtil.isEmpty(Token.getInstance().getData(clientId).getAccessToken())) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("엑세스토큰은 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(clientId)) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("클라이언트ID는 필수 입력값 입니다.").build(); + + + NiceCiRespDTO responseDTO = this.generatePublickey(Token.getInstance().getData(clientId).getAccessToken(), clientId); + + + if (!"1200".equals(responseDTO.getDataHeader().getGW_RSLT_CD())) + return NiceCiRespVO.errBuilder() + .errCode(NiceCiApiCd.valueOfEnum("HEAD_" + responseDTO.getDataHeader().getGW_RSLT_CD())) + .errMsg(String.format("[%s]: %s", responseDTO.getDataHeader().getGW_RSLT_CD(), responseDTO.getDataHeader().getGW_RSLT_MSG())) + .build(); + if (!"P000".equals(responseDTO.getDataBody().getRspCd())) + return NiceCiRespVO.errBuilder() + .errCode(NiceCiApiCd.valueOfEnum(responseDTO.getDataBody().getRspCd())) + .errMsg(String.format("[%s]: %s. %s", responseDTO.getDataBody().getRspCd(), NiceCiApiCd.valueOfEnum(responseDTO.getDataBody().getRspCd()).getCodeNm(), responseDTO.getDataBody().getResMsg())) + .build(); + if (!"0000".equals(responseDTO.getDataBody().getResultCd())) + return NiceCiRespVO.errBuilder() + .errCode(NiceCiApiCd.valueOfEnum("PUBKEY_" + responseDTO.getDataBody().getResultCd())) + .errMsg(String.format("[%s]: %s", responseDTO.getDataBody().getResultCd(), NiceCiApiCd.valueOfEnum("PUBKEY_" + responseDTO.getDataBody().getResultCd()).getCodeNm())) + .build(); + + + return NiceCiRespVO.okBuilder().resultInfo(responseDTO.getDataBody()).build(); + } + + + protected NiceCiRespDTO generatePublickey(String accessToken, String clientId) throws Exception { + try { + String bearerToken = Base64Util.encode(String.format("%s:%s:%s", accessToken, (new Date().getTime() / 1000), clientId)); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + headers.set("Authorization", String.format("bearer %s", bearerToken)); + headers.set("client_id", clientId); + headers.set("productID", PRODUCT_ID); + + + StringBuilder url = new StringBuilder(); + url.append(this.HOST) + .append(this.API_URL); + String jsonStr = this.createMessage(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers); + log.info("=================================================================================="); + log.info("==== 공개키 요청 Result Info... ===="); + log.info("[Headers]: " + resp.getHeaders().toString()); + log.info("[Body]: " + resp.getBody()); + log.info("=================================================================================="); + + + +// NiceCiRespDTO respDTO = mapper.readValue(resp.getBody(), NiceCiRespDTO.class); + String strRespBody = resp.getBody().replace("\"\"", "null"); + NiceCiRespDTO respDTO = mapper.readValue(strRespBody, new TypeReference>(){}); + + + return respDTO; + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("공개키 요청 실패." + e.getMessage()); + } + } + + + /** + * JSON 포맷의 요청메시지 생성 + * + * @param reqDtim + * @return + * @throws JsonProcessingException + */ + protected String createMessage(String reqDtim) throws JsonProcessingException { + Map dataHeader = new HashMap<>(); + dataHeader.put("CNTY_CD", "ko"); + dataHeader.put("TRAN_ID", null); + + Map dataBody = new HashMap<>(); + dataBody.put("req_dtim", reqDtim); + + Map m = new HashMap<>(); + m.put("dataHeader", dataHeader); + m.put("dataBody", dataBody); + + return mapper.writeValueAsString(m); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/SymkeyRegist.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/SymkeyRegist.java new file mode 100644 index 0000000..7ac0005 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/SymkeyRegist.java @@ -0,0 +1,255 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.api; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.code.NiceCiApiCd; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.NiceCiRespDTO; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.NiceCiRespVO; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodySymkeyResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils.PublicKey; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils.Token; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.experimental.SuperBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Base64Util; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.Base64Utils; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.nio.charset.Charset; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@SuperBuilder +public class SymkeyRegist extends NiceCiApiAbstract { + + protected final String HOST; + protected final String API_URL; + + + public NiceCiRespVO execute(String clientId) throws Exception { + if (CmmnUtil.isEmpty(Token.getInstance().getData(clientId).getAccessToken())) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("엑세스토큰은 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(clientId)) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("클라이언트ID는 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(PublicKey.getInstance().getData(clientId).getSiteCode())) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("사이트코드는 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(PublicKey.getInstance().getData(clientId).getPublicKey())) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("공개키는 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(PublicKey.getInstance().getData(clientId).getKeyVersion())) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("공개키버전은 필수 입력값 입니다.").build(); + + + NiceCiRespDTO responseDTO = this.generateSymmetrickey(Token.getInstance().getData(clientId).getAccessToken(), clientId, PublicKey.getInstance().getData(clientId).getSiteCode(), PublicKey.getInstance().getData(clientId).getPublicKey(), PublicKey.getInstance().getData(clientId).getKeyVersion()); + + + if (!"1200".equals(responseDTO.getDataHeader().getGW_RSLT_CD())) + return NiceCiRespVO.errBuilder() + .errCode(NiceCiApiCd.valueOfEnum("HEAD_" + responseDTO.getDataHeader().getGW_RSLT_CD())) + .errMsg(String.format("[%s]: %s", responseDTO.getDataHeader().getGW_RSLT_CD(), responseDTO.getDataHeader().getGW_RSLT_MSG())) + .build(); + if (!"P000".equals(responseDTO.getDataBody().getRspCd())) + return NiceCiRespVO.errBuilder() + .errCode(NiceCiApiCd.valueOfEnum(responseDTO.getDataBody().getRspCd())) + .errMsg(String.format("[%s]: %s. %s", responseDTO.getDataBody().getRspCd(), NiceCiApiCd.valueOfEnum(responseDTO.getDataBody().getRspCd()).getCodeNm(), responseDTO.getDataBody().getResMsg())) + .build(); + if (!"0000".equals(responseDTO.getDataBody().getResultCd())) + return NiceCiRespVO.errBuilder() + .errCode(NiceCiApiCd.valueOfEnum("SYMKEY_" + responseDTO.getDataBody().getResultCd())) + .errMsg(String.format("[%s]: %s", responseDTO.getDataBody().getResultCd(), NiceCiApiCd.valueOfEnum("SYMKEY_" + responseDTO.getDataBody().getResultCd()).getCodeNm())) + .build(); + + + return NiceCiRespVO.okBuilder().resultInfo(responseDTO.getDataBody()).build(); + + } + + + protected NiceCiRespDTO generateSymmetrickey(String accessToken, String clientId, String siteCode, String publicKey, String pubkeyVersion) throws Exception { + try { + String bearerToken = Base64Util.encode(String.format("%s:%s:%s", accessToken, (new Date().getTime() / 1000), clientId)); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + headers.set("Authorization", String.format("bearer %s", bearerToken)); + headers.set("client_id", clientId); + headers.set("productID", PRODUCT_ID); + + + StringBuilder url = new StringBuilder(); + url.append(this.HOST) + .append(this.API_URL); + final String requestNo = createRequestNo(); + final String key = this.createKey(); + final String iv = this.createIv(); + final String hmacKey = this.createHmacKey(); + final String strSymkeyRegInfo = this.createSymkeyRegInfo(siteCode, requestNo, key, iv, hmacKey); + final String jsonStr = this.createMessage(pubkeyVersion, encSymkeyRegInfo(strSymkeyRegInfo, publicKey)); + + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers); + log.info("=================================================================================="); + log.info("==== 대칭키 등록 요청 Info... ===="); + log.info("[Body]: " + jsonStr); + log.info("[symkeyRegInfo]: " + strSymkeyRegInfo); + log.info("==== 대칭키 등록 요청 Result Info... ===="); + log.info("[Headers]: " + resp.getHeaders().toString()); + log.info("[Body]: " + resp.getBody()); + log.info("=================================================================================="); + + + +// NiceCiRespDTO respDTO = mapper.readValue(resp.getBody(), NiceCiRespDTO.class); + String strRespBody = resp.getBody().replace("\"\"", "null"); + strRespBody = strRespBody.replace("\\", "").replace("\"{", "{").replace("}\"", "}"); + NiceCiRespDTO respDTO = mapper.readValue(strRespBody, new TypeReference>(){}); + if (!(respDTO.getDataBody() == null || "".equals(respDTO.getDataBody()))) { + respDTO.getDataBody().setSiteCode(siteCode); + respDTO.getDataBody().setRequestNo(requestNo); + respDTO.getDataBody().setKey(key); + respDTO.getDataBody().setIv(iv); + respDTO.getDataBody().setHmacKey(hmacKey); + } + + return respDTO; + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("대칭키 등록 요청 실패." + e.getMessage()); + } + } + + + private String createSymkeyRegInfo(String siteCode, String requestNo, String key, String iv, String hmacKey) throws JsonProcessingException { + Map m = new HashMap<>(); + m.put("site_code", siteCode); + m.put("request_no", requestNo); + m.put("key", key); + m.put("iv", iv); + m.put("hmac_key", hmacKey); + + return mapper.writeValueAsString(m); + } + + + /** + * 대칭키 생성 + * -. KEY를 NICE에 등록 후 6개월 내 갱신이 필요 함 + * -. 6개월 내 현재 등록키, 이전 등록키 사용 가능하므로 대칭키 등록 후 AP에서 암호화키 변경 적용 필요 + * -. 6개월 내 키등록이 없으면 암복호화 오류 발생 + *

+ * [예시] + * 1) 이용기관에서 대칭키 드록 후, 암복호화를 진행 + * 2) 적절한 시점에 신규 대칭키를 등록 + * 3) API에서도 신규 대칭키로 암호화(enc_data) 키 변경 진행 + * => 직전 등록된 대칭키는 유효기간 내 사용가능하므로 대칭키 등록과 API의 암호화 키변경은 이용기관 일정에 따라 진행) + * + * @return + */ + private String createKey() { + return randomAlphaWord(32); + } + + /** + * Initail Vector 생성 + * -. 데이터를 암호화할 Initial Vector + * -. 16 byte 딱 맞게 생성 해야 함 + * + * @return + */ + private String createIv() { + return randomAlphaWord(16); + } + + /** + * 요청고유번호 + * -.이용기관에서 임의 생성한 값 + * + * @return + */ + private String createRequestNo() { + return randomAlphaWord(30); + } + + /** + * hamc_key 생성 + * -. 무결성체크값에 사용할 Hmac Key + * -. 32 byte 딱 맞게 생성 해야 함 + * + * @return + */ + private String createHmacKey() { + return randomAlphaWord(32); + } + + + /** + * 공개키로 암호화를 수행 후 반환 한다. + * + * @param symkeyRegInfo + * @param sPublicKey + * @return + * @throws NoSuchAlgorithmException + * @throws InvalidKeySpecException + * @throws NoSuchPaddingException + * @throws InvalidKeyException + * @throws IllegalBlockSizeException + * @throws BadPaddingException + */ + protected final String encSymkeyRegInfo(String symkeyRegInfo, String sPublicKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); +// byte[] cipherEnc = Base64Utils.decode(sPublicKey.getBytes()); + byte[] cipherEnc = Base64.getDecoder().decode(sPublicKey); + X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(cipherEnc); + java.security.PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); + + + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + byte[] bytePlain = cipher.doFinal(symkeyRegInfo.getBytes()); + + + String keyInfoEnc = Base64Utils.encodeToString(bytePlain); + + return keyInfoEnc; + } + + + /** + * JSON 포맷의 요청메시지 생성 + * + * @param pubkeyVersion + * @param symkeyRegInfo + * @return + * @throws JsonProcessingException + */ + protected String createMessage(String pubkeyVersion, String symkeyRegInfo) throws JsonProcessingException { + Map dataHeader = new HashMap<>(); + dataHeader.put("CNTY_CD", "ko"); + dataHeader.put("TRAN_ID", null); + + Map dataBody = new HashMap<>(); + dataBody.put("pubkey_version", pubkeyVersion); + dataBody.put("symkey_reg_info", symkeyRegInfo); + + Map m = new HashMap<>(); + m.put("dataHeader", dataHeader); + m.put("dataBody", dataBody); + + return mapper.writeValueAsString(m); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/TokenGenerate.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/TokenGenerate.java new file mode 100644 index 0000000..f24fcc4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/api/TokenGenerate.java @@ -0,0 +1,188 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.api; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.core.utils.DateUtil; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.code.NiceCiApiCd; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.NiceCiRespDTO; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.NiceCiRespVO; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyGenerateTokenResp; +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyRevokeTokenResp; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.experimental.SuperBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Base64Util; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import java.nio.charset.Charset; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +@Slf4j +@SuperBuilder +public class TokenGenerate extends NiceCiApiAbstract { + + protected final String HOST; + protected final String API_URL_GENERATE_TOKEN; + protected final String API_URL_REVOKE_TOKEN; + + + public NiceCiRespVO execute(String clientId, String clientSecret) throws Exception { + if (CmmnUtil.isEmpty(clientId)) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("클라이언트ID는 필수 입력값 입니다.").build(); + if (CmmnUtil.isEmpty(clientSecret)) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg("클라이언트비밀번호는 필수 입력값 입니다.").build(); + + + + NiceCiRespDTO generateResponseDTO = this.generateToken(clientId, clientSecret); + + + if ("1800".equals(generateResponseDTO.getDataHeader().getGW_RSLT_CD())) + generateResponseDTO = this.generateToken(clientId, clientSecret); + if (!"1200".equals(generateResponseDTO.getDataHeader().getGW_RSLT_CD())) + return NiceCiRespVO.errBuilder() + .errCode(NiceCiApiCd.valueOfEnum("HEAD_" + generateResponseDTO.getDataHeader().getGW_RSLT_CD())) + .errMsg(String.format("[%s]: %s", generateResponseDTO.getDataHeader().getGW_RSLT_CD(), generateResponseDTO.getDataHeader().getGW_RSLT_MSG())) + .build(); + if (DateUtil.secToDays(generateResponseDTO.getDataBody().getExpiresIn()) < 30) { + + NiceCiRespDTO revokeResponseDTO = this.revokeToken(generateResponseDTO.getDataBody().getAccessToken(), clientId); + if (!"1200".equals(revokeResponseDTO.getDataHeader().getGW_RSLT_CD())) + return NiceCiRespVO.errBuilder() + .errCode(NiceCiApiCd.valueOfEnum("HEAD_" + generateResponseDTO.getDataHeader().getGW_RSLT_CD())) + .errMsg(String.format("[%s]: %s", generateResponseDTO.getDataHeader().getGW_RSLT_CD(), generateResponseDTO.getDataHeader().getGW_RSLT_MSG())) + .build(); + if(!revokeResponseDTO.getDataBody().getResult()) + return NiceCiRespVO.errBuilder().errCode(NiceCiApiCd.FAIL).errMsg(String.format("토큰(%s) 폐기에 실패 했습니다.", generateResponseDTO.getDataBody().getAccessToken())).build(); + + generateResponseDTO = this.generateToken(clientId, clientSecret); + if (!"1200".equals(generateResponseDTO.getDataHeader().getGW_RSLT_CD())) + return NiceCiRespVO.errBuilder() + .errCode(NiceCiApiCd.valueOfEnum("HEAD_" + generateResponseDTO.getDataHeader().getGW_RSLT_CD())) + .errMsg(String.format("[%s]: %s", generateResponseDTO.getDataHeader().getGW_RSLT_CD(), generateResponseDTO.getDataHeader().getGW_RSLT_MSG())) + .build(); + } + + + + return NiceCiRespVO.okBuilder().resultInfo(generateResponseDTO.getDataBody()).build(); + } + + + protected NiceCiRespDTO generateToken(String clientId, String clientSecret) throws Exception { + try { + + + String authorizationToken = Base64Util.encode(String.format("%s:%s", clientId, clientSecret)); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_FORM_URLENCODED, Charset.forName("utf-8"))); + headers.set("Authorization", String.format("Basic %s", authorizationToken)); + + + StringBuilder url = new StringBuilder(); + url.append(this.HOST) + .append(API_URL_GENERATE_TOKEN); + MultiValueMap body = this.createMessage(); + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), body, headers); + log.info("=================================================================================="); + log.info("==== 토큰발급 요청 Result Info... ===="); + log.info("[Headers]: " + resp.getHeaders().toString()); + log.info("[Body]: " + resp.getBody()); + log.info("=================================================================================="); + + +// NiceCiRespDTO respDTO = mapper.readValue(resp.getBody(), NiceCiRespDTO.class); + String strRespBody = resp.getBody().replace("\"\"", "null"); + NiceCiRespDTO respDTO = mapper.readValue(strRespBody, new TypeReference>(){}); + if(!(respDTO.getDataBody()==null||"".equals(respDTO.getDataBody()))) + respDTO.getDataBody().setExpiredDt(this.addSec(respDTO.getDataBody().getExpiresIn(), "yyyyMMddHHmmss")); + + + return respDTO; + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("토큰발급 요청 실패." + e.getMessage()); + } + } + + + protected NiceCiRespDTO revokeToken(String accessToken, String clientId) throws Exception { + try { + String bearerToken = Base64Util.encode(String.format("%s:%s:%s", accessToken, (new Date().getTime() / 1000), clientId)); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_FORM_URLENCODED, Charset.forName("utf-8"))); + headers.set("Authorization", String.format("Basic %s", bearerToken)); + + + StringBuilder url = new StringBuilder(); + url.append(this.HOST) + .append(API_URL_REVOKE_TOKEN); + + + ResponseEntity resp = this.callApi(HttpMethod.POST, url.toString(), null, headers); + log.info("=================================================================================="); + log.info("==== 토큰폐기 요청 Result Info... ===="); + log.info("[Headers]: " + resp.getHeaders().toString()); + log.info("[Body]: " + resp.getBody()); + log.info("=================================================================================="); + + +// NiceCiRespDTO respDTO = mapper.readValue(resp.getBody(), NiceCiRespDTO.class); + String strRespBody = resp.getBody().replace("\"\"", "null"); + NiceCiRespDTO respDTO = mapper.readValue(strRespBody, new TypeReference>(){}); + + + return respDTO; + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("토큰폐기 요청 실패." + e.getMessage()); + } + } + + + /** + * JSON 포맷의 요청메시지 생성 + * + * @return + * @throws JsonProcessingException + */ + protected MultiValueMap createMessage() throws JsonProcessingException { + MultiValueMap m = new LinkedMultiValueMap<>(); + m.add("grant_type", "client_credentials"); + m.add("scope", "default"); + + return m; + } + + + + /** + * 현재날짜에 초(sec)를 더한 날짜를 반환 한다. + * @param sec + * @param pattern + * @return + */ + private String addSec(Integer sec, String pattern){ + if(sec==null) + return null; + + if("".equals(pattern)||pattern==null) + pattern = "yyyyMMdd"; + + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis((sec*1000L) + (new Date().getTime())); + Date date = calendar.getTime(); + + return new SimpleDateFormat(pattern).format(date); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/code/NiceCiApiCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/code/NiceCiApiCd.java new file mode 100644 index 0000000..f533a54 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/code/NiceCiApiCd.java @@ -0,0 +1,150 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.code; + +public enum NiceCiApiCd { + + UNKNOWN("알수없음") + , OK("정상") + , FAIL("실패") + +// , HTTP_200("No Error") +// , HTTP_400("Bad Request or Inavalid Token") +// , HTTP_401("Authorized required") +// , HTTP_402("unAuthorized") +// , HTTP_403("service Disabled") +// , HTTP_404("Service Not Found") +// , HTTP_500("Internal Server Error") +// , HTTP_501("Access Denied by Protected Service") +// , HTTP_502("Bad Response from Protected Service") +// , HTTP_503("Service Temporarily Unavailable") + + , HEAD_1200("오류 없음 (정상)") + , HEAD_1300("request body가 비었습니다.") + , HEAD_1400("잘못된 요청") + , HEAD_1401("인증 필요") + , HEAD_1402("권한없음") + , HEAD_1403("서비스 사용 중지됨") + , HEAD_1404("서비스를 찾을 수 없음") + , HEAD_1500("서버 내부 오류") + , HEAD_1501("보호된 서비스에서 엑세스가 거부되었습니다.") + , HEAD_1502("보호된 서비스에서 응답이 잘못되었습니다.") + , HEAD_1503("일시적으로 사용할 수 없는 서비스") + , HEAD_1700("엑세스가 허용되지 않습니다. - Client ID") + , HEAD_1701("엑세스가 허용되지 않습니다. - Service URI") + , HEAD_1702("엑세스가 허용되지 않습니다. - Client ID + Client IP") + , HEAD_1703("엑세스가 허용되지 않습니다. - Client ID + Service URI") + , HEAD_1705("엑세스가 허용되지 않습니다. - Client ID + Black List Client IP") + , HEAD_1706("액세스가 허용되지 않습니다 - Client ID + Product Code") + , HEAD_1711("거래제한된 요일입니다.") + , HEAD_1712("거래제한된 시간입니다.") + , HEAD_1713("거래제한된 요일/시간입니다.") + , HEAD_1714("거래제한된 일자입니다.") + , HEAD_1715("거래제한된 일자/시간입니다.") + , HEAD_1716("공휴일 거래가 제한된 서비스입니다.") + , HEAD_1717("SQL인젝션, XSS방어") + , HEAD_1800("잘못된 토큰") + , HEAD_1801("잘못된 클라이언트 정보") + , HEAD_1900("초과된 연결 횟수") + , HEAD_1901("초과 된 토큰 조회 실패") + , HEAD_1902("초과된 토큰 체크 실패") + , HEAD_1903("초과된 접속자 수 ") + , HEAD_1904("전송 크기 초과") + , HEAD_1905("접속량이 너무 많음") + , HEAD_1906("상품이용 한도 초과") + , HEAD_1907("API 이용 주기 초과") + , HEAD_1908("상품 이용 주기 초과") + + + , P000("정상응답") + , S603("내부 DB 오류") + , P013("이용기관 개시상태 아님") + , E998("서비스 권한 오류") + , E999("내부시스템 오류") + , Exxx("기타시스템 오류") + + + , EAPI2500("맵핑정보 없음 - {0}") + , EAPI2510("요청맵핑 데이터가 없습니다.") + , EAPI2530("응답전문 맵핑 오류") + , EAPI2540("대응답 정보 없음") + , EAPI2550("숫자타입 입력 오류") + , EAPI2560("실수타입 입력 오류") + , EAPI2561("실수형 타입 길이정보 문법 에러 ( 형식 : \"전체길이,실수부길이\")") + , EAPI2562("실수형 타입 논리 에러 ( 전체 길이는 소수부 길이보다 커야합니다. )") + , EAPI2563("실수형 타입 파싱 에러( 입력값을 실수값으로 변환할 수 없습니다. )") + , EAPI2564("실수형 타입 정수부 길이 에러") + , EAPI2565("실수형 타입 소수부 길이 에러") + , EAPI2600("내부 시스템 오류") + , EAPI2700("외부 시스템 연동 오류") + , EAPI2701("타임아웃이 발생하였습니다.") + , EAPI2702("DISCONNECTION_OK") + , EAPI2703("DISCONNECTION_FAIL") + , EAPI2704("RESULT_OK") + , EAPI2705("RESULT_FAIL") + , EAPI2892("반복부 카운터 에러(지정된 건수보다 크거나 작습니다)") + , EAPI5001("schema 검증 정보가 없습니다.") + , EAPI5002("schema 검증 실패") + + + , PUBKEY_0000("공개키 발급") + , PUBKEY_0001("필수입력값 오류") + , PUBKEY_0003("공개키 발급 대상 회원사 아님") + , PUBKEY_0099("기타오류") + + , SYMKEY_0000("대칭키 발급") + , SYMKEY_0001("공개키 기간 만료") + , SYMKEY_0002("공개키를 찾을 수 없음") + , SYMKEY_0003("공개키를 발급한 회원사 아님") + , SYMKEY_0004("복호화 오류") + , SYMKEY_0005("필수입력값 오류 (key_version, key_info 필수값 확인)") + , SYMKEY_0006("대칭키 등록 가능 회원사 아님") + , SYMKEY_0007("key 중복 오류 (현재 및 직전에 사용한 Key 사용 불가)") + , SYMKEY_0008("요청사이트코드와 공개키발급 사이트코드 다름") + , SYMKEY_0099("기타오류") + + , CI_0000("처리완료") + , CI_0001("대칭키 기간 만료") + , CI_0002("대칭키를 찾을 수 없음") + , CI_0003("대칭키를 발급한 회원사 아님") + , CI_0004("복호화 오류") + , CI_0005("필수입력값 오류 (integrity_value, enc_data 내 필수값 확인)") + , CI_0006("데이터 무결성 오류 (hmac값 불일치)") + , CI_0007("정보요청유형 입력값 오류 (info_req_type이 1 아님)") + , CI_0008("주민번호 유효성 오류 (생년월일 유효성 및 숫자 아님)") + , CI_0009("거래요청시간 포멧오류 (req_dtim 자릿수 및 숫자 아님)") + , CI_0099("기타오류") + + + ; + + + + + private final String code; + private final String codeNm; + NiceCiApiCd(String codeNm) { + this.code = this.name(); + this.codeNm = codeNm; + } + + public String getCode() { + return this.code; + } + + public String getCodeNm() { + return this.codeNm; + } + + + public static NiceCiApiCd valueOfEnum(String code){ + if(code == null) + return NiceCiApiCd.UNKNOWN; + + NiceCiApiCd ensErrCd = null; + try { + ensErrCd = NiceCiApiCd.valueOf(code); + } catch (IllegalArgumentException e){ + ensErrCd = NiceCiApiCd.UNKNOWN; + } + return ensErrCd; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/domain/NiceCiSymkeyMng.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/domain/NiceCiSymkeyMng.java new file mode 100644 index 0000000..d73ceb2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/domain/NiceCiSymkeyMng.java @@ -0,0 +1,72 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_nice_ci_symkey_mng", schema = "", catalog = "", indexes = { + @Index(name = "idx_nice_ci_symkey_mng_01", columnList = "client_id"), +}) +@Schema(name = "NiceCiSymkeyMng") +public class NiceCiSymkeyMng { + + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long niceCiSymkeyMngId; + + @Schema(required = true, title = "(계약정보)클라이언트ID", example = " ") + @Column(name = "client_id", nullable = false, length = 255) + private String clientId; + + @Schema(required = true, title = "공개키(PK)", example = " ") + @Column(name = "pubkey", nullable = false, length = 1000) + private String pubkey; + + @Schema(required = true, title = "대칭키", example = " ") + @Column(name = "symkey", nullable = false, length = 32) + private String symkey; + + @Schema(required = false, title = "만료일시", example = " ") + @Column(name = "expire_dt", nullable = true, length = 14) + private String expireDt; + + @Schema(required = false, title = "버전", example = " ") + @Column(name = "version", nullable = true, length = 50) + private String version; + + @Schema(required = true, title = "Initial Vector 값", example = " ") + @Column(name = "iv", nullable = false, length = 16) + private String iv; + + @Schema(required = true, title = "hmac key", example = " ") + @Column(name = "hmac_key", nullable = false, length = 32) + private String hmacKey; + + @Schema(required = true, title = "대체키등록API 응답 Json 데이터", example = " ") + @Column(name = "resp_json_data", nullable = false, length = 1000) + private String respJsonData; + + + @Schema(required = false, title = "등록일시", example = " ") + @Column(name = "regist_dt", nullable = true) + @CreationTimestamp + private LocalDateTime registDt; + + @Schema(required = false, title = "최종 수정일시", example = " ") + @Column(name = "last_updt_dt", nullable = true) + @UpdateTimestamp + private LocalDateTime lastUpdtDt; + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/domain/repository/NiceCiSymkeyMngRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/domain/repository/NiceCiSymkeyMngRepository.java new file mode 100644 index 0000000..b7fcfdf --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/domain/repository/NiceCiSymkeyMngRepository.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.domain.repository; + +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.domain.NiceCiSymkeyMng; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface NiceCiSymkeyMngRepository extends JpaRepository { + + + List findAllByClientIdAndPubkeyOrderByRegistDtDesc(String clientId, String pubkey); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/NiceCiRespDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/NiceCiRespDTO.java new file mode 100644 index 0000000..403e858 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/NiceCiRespDTO.java @@ -0,0 +1,22 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model; + +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataHeader; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Data +public class NiceCiRespDTO { + + + private DataHeader dataHeader; + + private T dataBody; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/NiceCiRespVO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/NiceCiRespVO.java new file mode 100644 index 0000000..58741bc --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/NiceCiRespVO.java @@ -0,0 +1,34 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model; + +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.code.NiceCiApiCd; +import lombok.Builder; +import lombok.Getter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Getter +@ToString +public class NiceCiRespVO { + + private NiceCiApiCd errCode; + private String errMsg; + + + private T resultInfo; + + + @Builder(builderClassName = "okBuilder" ,builderMethodName = "okBuilder") + NiceCiRespVO(T resultInfo) { + this.errCode = NiceCiApiCd.OK; + this.errMsg = NiceCiApiCd.OK.getCodeNm(); + this.resultInfo = resultInfo; + } + + @Builder(builderClassName = "errBuilder" ,builderMethodName = "errBuilder") + NiceCiRespVO(NiceCiApiCd errCode, String errMsg, T resultInfo) { + this.errCode = errCode; + this.errMsg = errMsg; + this.resultInfo = resultInfo; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodyCiResp.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodyCiResp.java new file mode 100644 index 0000000..16b668a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodyCiResp.java @@ -0,0 +1,41 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf; + +import com.fasterxml.jackson.annotation.JsonAlias; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; + +@Getter +@ToString +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "DataBodyCiResp") +public class DataBodyCiResp { + + @JsonAlias({"rsp_cd"}) + @Schema(required = true, title = "dataBody 응답 코드", example = "P000") + private String rspCd; + + @JsonAlias({"res_msg"}) + @Schema(required = false, title = "dataBody 응답 메시지", example = " ") + private String resMsg; + + @JsonAlias({"result_cd"}) + @Schema(required = false, title = "상세결과코드", example = " ") + private String resultCd; + + @JsonAlias({"enc_data"}) + @Schema(required = false, title = "JSON 암호화값", example = " ") + private String encData; + + @JsonAlias({"integrity_value"}) + @Schema(required = false, title = "base64 인코딩 값", example = " ") + private String integrityValue; + + + @Schema(required = false, title = "JSON 디코딩 값", example = " ") + @Setter + private EncData decEncData; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodyGenerateTokenResp.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodyGenerateTokenResp.java new file mode 100644 index 0000000..0e7b545 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodyGenerateTokenResp.java @@ -0,0 +1,35 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf; + +import com.fasterxml.jackson.annotation.JsonAlias; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; + +@Getter +@ToString +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "DataBodyGenerateTokenResp") +public class DataBodyGenerateTokenResp { + + @JsonAlias({"access_token"}) + @Schema(required = true, title = "엑세스토큰", example = " ") + private String accessToken; + + @JsonAlias({"expires_in"}) + @Schema(required = true, title = "엑세스토큰 만료 절대시간(sec)", example = " ") + private Integer expiresIn; + + @JsonAlias({"token_type"}) + @Schema(required = true, title = "토큰타입", example = " ") + private String tokenType; + + @JsonAlias({"scope"}) + @Schema(required = true, title = "요청한 scope값", example = " ") + private String scope; + + @Setter + @Schema(required = true, title = "access token 만료시간(yyyyMmddHHmmss)", example = " ") + private String expiredDt; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodyPubkeyResp.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodyPubkeyResp.java new file mode 100644 index 0000000..aed0ba7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodyPubkeyResp.java @@ -0,0 +1,50 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf; + +import com.fasterxml.jackson.annotation.JsonAlias; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +@Getter +@ToString +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "DataBodyPubkeyResp") +public class DataBodyPubkeyResp { + + @JsonAlias({"rsp_cd"}) + @Schema(required = true, title = "dataBody 응답코드", example = " ") + private String rspCd; + + @JsonAlias({"res_msg"}) + @Schema(required = false, title = "dataBody 응답메시지", example = " ") + private String resMsg; + + @JsonAlias({"result_cd"}) + @Schema(required = false, title = "상세결과코드", example = " ") + private String resultCd; + + @JsonAlias({"site_code"}) + @Schema(required = false, title = "사이트코드", example = " ") + private String siteCode; + + @JsonAlias({"key_version"}) + @Schema(required = false, title = "공개키 버전", example = " ") + private String keyVersion; + + @JsonAlias({"public_key"}) + @Schema(required = false, title = "공개키", example = " ") + private String publicKey; + + @JsonAlias({"valid_dtim"}) + @Schema(required = false, title = "공개키 만료일시", example = " ") + private String validDtim; + + + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodyRevokeTokenResp.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodyRevokeTokenResp.java new file mode 100644 index 0000000..94be71c --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodyRevokeTokenResp.java @@ -0,0 +1,23 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf; + +import com.fasterxml.jackson.annotation.JsonAlias; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +@Getter +@ToString +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "DataBodyRevokeTokenResp") +public class DataBodyRevokeTokenResp { + + @JsonAlias({"result"}) + @Schema(required = true, title = "토큰폐기 여부", example = " ") + private Boolean result; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodySymkeyResp.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodySymkeyResp.java new file mode 100644 index 0000000..d4a5f71 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataBodySymkeyResp.java @@ -0,0 +1,45 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf; + +import com.fasterxml.jackson.annotation.JsonAlias; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; + +@Getter +@ToString +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "DataBodySymkeyResp") +public class DataBodySymkeyResp { + + @JsonAlias({"rsp_cd"}) + @Schema(required = true, title = "dataBody 응답코드", example = " ") + private String rspCd; + + @JsonAlias({"res_msg"}) + @Schema(required = false, title = "dataBody 응답메시지", example = " ") + private String resMsg; + + @JsonAlias({"result_cd"}) + @Schema(required = false, title = "상세결과코드", example = " ") + private String resultCd; + + @JsonAlias({"symkey_stat_info"}) + @Schema(required = false, title = "JSON값", example = " ") + private SymkeyStatInfo symkeyStatInfo; + + + + @Setter + private String siteCode; + @Setter + private String requestNo; + @Setter + private String key; + @Setter + private String iv; + @Setter + private String hmacKey; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataHeader.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataHeader.java new file mode 100644 index 0000000..5d689d6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/DataHeader.java @@ -0,0 +1,34 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf; + +import com.fasterxml.jackson.annotation.JsonAlias; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; + +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Data +public class DataHeader { + @NotEmpty(message = "응답코드 값이 없습니다.") + @Length(max = 4, message = "응답코드의 최대길이를 초과 했습니다.") + @Schema(required = true, title = "응답코드", example = "1200") + @JsonAlias({"GW_RSLT_CD"}) + private String GW_RSLT_CD; + + @NotEmpty(message = "응답메시지 값이 없습니다.") + @Length(max = 200, message = "응답메시지의 최대길이를 초과 했습니다.") + @Schema(required = true, title = "응답메시지", example = " ") + @JsonAlias({"GW_RSLT_MSG"}) + private String GW_RSLT_MSG; + + @Length(max = 24, message = "TRAN_ID의 최대길이를 초과 했습니다.") + @Schema(required = false, title = "교환ID", example = " ") + @JsonAlias({"TRAN_ID"}) + private String TRAN_ID; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/EncData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/EncData.java new file mode 100644 index 0000000..6249e0c --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/EncData.java @@ -0,0 +1,32 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf; + + +import com.fasterxml.jackson.annotation.JsonAlias; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "EncData") +public class EncData { + + @JsonAlias({"ci1"}) + @Schema(required = false, title = "연계정보1", example = " ") + private String ci1; + + @JsonAlias({"ci2"}) + @Schema(required = false, title = "연계정보2", example = " ") + private String ci2; + + @JsonAlias({"updt_cnt"}) + @Schema(required = false, title = "갱신횟수", example = " ") + private String updtCnt; + + @JsonAlias({"tx_unique_no"}) + @Schema(required = false, title = "거래고유번호", example = " ") + private String txUniqueNo; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/SymkeyStatInfo.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/SymkeyStatInfo.java new file mode 100644 index 0000000..f5c61da --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/model/conf/SymkeyStatInfo.java @@ -0,0 +1,33 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf; + + +import com.fasterxml.jackson.annotation.JsonAlias; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "SymkeyStatInfo") +public class SymkeyStatInfo { + + @JsonAlias({"cur_symkey_version"}) + @Schema(required = false, title = "현재 대칭키 버전", example = " ") + private String curSymkeyVersion; + + @JsonAlias({"cur_valid_dtim"}) + @Schema(required = false, title = "현재 대칭키 만료일시", example = " ") + private String curValidDtim; + + @JsonAlias({"bef_symkey_version"}) + @Schema(required = false, title = "이전 대칭키 버전", example = " ") + private String befSymkeyVersion; + + @JsonAlias({"bef_valid_dtim"}) + @Schema(required = false, title = "이전 대칭키 만료일시", example = " ") + private String befValidDtim; + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/utils/PublicKey.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/utils/PublicKey.java new file mode 100644 index 0000000..d263221 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/utils/PublicKey.java @@ -0,0 +1,67 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils; + +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyPubkeyResp; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; + +public class PublicKey { + + + private volatile static PublicKey instance; + private static Map data = new HashMap<>(); + +// private PubkeyInfo() { +// +// } +// +// public static PubkeyInfo getInstance() { +// if (instance == null) +// synchronized (PubkeyInfo.class) { +// if (instance == null) +// instance = new PubkeyInfo(); +// } +// +// return instance; +// } + + private PublicKey(String clientId, DataBodyPubkeyResp data) { + this.data.put(clientId, data); + } + + public static PublicKey getInstance() { + return instance; + } + + public static PublicKey getInstance(String clientId, DataBodyPubkeyResp data) { + if (!isValidStat(clientId)) + synchronized (PublicKey.class) { + if (!isValidStat(clientId)) + instance = new PublicKey(clientId, data); + } + + return instance; + } + + + public static boolean isValidStat(String clientId) { + if (instance == null) + return false; + if (data == null) + return false; + if (data.getOrDefault(clientId, null) == null) + return false; + if (Long.parseLong(data.get(clientId).getValidDtim()) < Long.parseLong(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")))) + return false; + + return true; + } + + + public DataBodyPubkeyResp getData(String clientId) { + return data.get(clientId); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/utils/SymmetricKey.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/utils/SymmetricKey.java new file mode 100644 index 0000000..7d2fc90 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/utils/SymmetricKey.java @@ -0,0 +1,72 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils; + +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodySymkeyResp; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; + +public class SymmetricKey { + + + private volatile static SymmetricKey instance; + private static Map data = new HashMap<>(); + +// private static String version; +// private static Long expireDt; + +// private SymkeyInfo() { +// +// } +// +// public static SymkeyInfo getInstance() { +// if (instance == null) +// synchronized (SymkeyInfo.class) { +// if (instance == null) +// instance = new SymkeyInfo(); +// } +// +// return instance; +// } + + private SymmetricKey(String clientId, DataBodySymkeyResp data) { + this.data.put(clientId, data); + } + + public static SymmetricKey getInstance() { + + return instance; + } + + public static SymmetricKey getInstance(String clientId, DataBodySymkeyResp data) { + if (!isValidStat(clientId)) + synchronized (SymmetricKey.class) { + if (!isValidStat(clientId)) + instance = new SymmetricKey(clientId, data); + } + + return instance; + } + + + public static boolean isValidStat(String clientId) { + if (instance == null) + return false; + if (data == null) + return false; + if (data.getOrDefault(clientId, null) == null) + return false; + + if (Long.parseLong(data.get(clientId).getSymkeyStatInfo().getCurValidDtim()) < Long.parseLong(LocalDateTime.now().plusDays(1).format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")))) + return false; + + return true; + } + + + public DataBodySymkeyResp getData(String clientId) { + return data.get(clientId); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/utils/Token.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/utils/Token.java new file mode 100644 index 0000000..82a038a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/rest/utils/Token.java @@ -0,0 +1,67 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils; + +import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyGenerateTokenResp; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; + +public class Token { + + + private volatile static Token instance; + private static Map data = new HashMap<>(); + +// private PubkeyInfo() { +// +// } +// +// public static PubkeyInfo getInstance() { +// if (instance == null) +// synchronized (PubkeyInfo.class) { +// if (instance == null) +// instance = new PubkeyInfo(); +// } +// +// return instance; +// } + + private Token(String clientId, DataBodyGenerateTokenResp data) { + this.data.put(clientId, data); + } + + public static Token getInstance() { + return instance; + } + + public static Token getInstance(String clientId, DataBodyGenerateTokenResp data) { + if (!isValidStat(clientId)) + synchronized (Token.class) { + if (!isValidStat(clientId)) + instance = new Token(clientId, data); + } + + return instance; + } + + + public static boolean isValidStat(String clientId) { + if (instance == null) + return false; + if (data == null) + return false; + if (data.getOrDefault(clientId, null) == null) + return false; + if (Long.parseLong(data.get(clientId).getExpiredDt()) < Long.parseLong(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")))) + return false; + + return true; + } + + + public DataBodyGenerateTokenResp getData(String clientId) { + return data.get(clientId); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/socket/Interop.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/socket/Interop.java new file mode 100644 index 0000000..98b7e5d --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/nicedici/support/socket/Interop.java @@ -0,0 +1,348 @@ +package cokr.xit.ens.modules.common.ctgy.nicedici.support.socket; + + +import KISINFO.VNO.VNOInterop; +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.MapDeserailizer; +import cokr.xit.ens.modules.common.ctgy.nicedici.model.NiceDiCiRespDTO; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.*; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import java.net.URI; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +public class Interop +{ + public Interop() + { + + } + + public static EnsResponseVO getCI(String siteCode, String sitePw, String jumin) { + + final String sSiteCode = siteCode; // NICE평가정보에서 발급한 서비스 사이트코드 + final String sSitePw = sitePw; + final String sJumin = jumin.replaceAll("[^0-9]", ""); + final String sFlag = "JID"; + + + + int iRtnCI = -1; + EnsErrCd errCode = EnsErrCd.ERR999; + String errMsg = "API 호출 오류. 방화벽을 확인해 보시기 바랍니다."; + String ci = null; + try { + // 모듈 객체 생성 + VNOInterop vnoInterop = new VNOInterop(); + + /* ──── CI 값을 추출하기 위한 부분 Start */ + // 인증요청처리 + iRtnCI = vnoInterop.fnRequestConnInfo(sSiteCode, sSitePw, sJumin, sFlag); + log.info("======================================================================="); + log.info("JID=" + sJumin); + log.info("iRtnCI=" + iRtnCI); + + // 인증결과코드에 따른 처리 + if (iRtnCI == 1) { + // CI 값 추출 (연계정보 확인값, 88Byte) + String sConnInfo = vnoInterop.getConnInfo(); + log.info("CONNINFO=[" + sConnInfo + "]"); + + // 결과설정 + errCode = EnsErrCd.OK; + errMsg = String.format("[%s] (응답코드 %s)", EnsErrCd.OK.getCodeNm(), iRtnCI); + ci = sConnInfo; + } else if (iRtnCI == 3) { + log.info("[사용자 정보와 서비스 구분값 매핑 오류]"); + log.info("사용자 정보와 서비스 구분값이 서로 일치하도록 매핑하여 주시기 바랍니다."); + + // 결과설정 + errCode = EnsErrCd.ERR405; + errMsg = String.format("[사용자 정보와 서비스 구분값 매핑 오류] 사용자 정보와 서비스 구분값이 서로 일치하도록 매핑하여 주시기 바랍니다. (응답코드 %s)", iRtnCI); + } else if (iRtnCI == -9) { + log.info("[입력값 오류]"); + log.info("fnRequestConnInfo 함수 처리시, 필요한 4개의 파라미터값의 정보를 정확하게 입력해 주시기 바랍니다."); + + // 결과설정 + errCode = EnsErrCd.ERR403; + errMsg = String.format("[입력값 오류] fnRequestConnInfo 함수 처리시, 필요한 4개의 파라미터값의 정보를 정확하게 입력해 주시기 바랍니다.(응답코드 %s)", iRtnCI); + } else if (iRtnCI == -21 || iRtnCI == -31 || iRtnCI == -34) { + log.info("[통신오류]"); + log.info("방화벽 이용 시 아래 IP와 Port(총 5개)를 등록해주셔야 합니다."); + log.info("IP : 203.234.219.72 / Port : 81, 82, 83, 84, 85"); + + // 결과설정 + errCode = EnsErrCd.ERR521; + errMsg = String.format("[통신오류] 방화벽 이용 시 아래 IP와 Port(총 5개)를 등록해주셔야 합니다. IP : 203.234.219.72 / Port : 81, 82, 83, 84, 85.(응답코드 %s)", iRtnCI); + } else { + log.info("[기타오류]"); + log.info("iRtnCI 값 확인 후 NICE평가정보 전산 담당자에게 문의"); + + // 결과설정 + errCode = EnsErrCd.ERR999; + errMsg = String.format("[기타오류] iRtnCI 값 확인 후 NICE평가정보 전산 담당자에게 문의. (응답코드 %s)", iRtnCI); + } + /* ──── CI 값을 추출하기 위한 부분 End */ + + } catch (Exception e) { + // 결과설정 + errCode = EnsErrCd.ERR602; + errMsg = String.format("[나이스API 오류] %s (응답코드 %s)", e.getMessage(), iRtnCI); + } finally { + if(iRtnCI == 1) + return EnsResponseVO.okBuilder() + .resultInfo(ci) + .build(); + else + return EnsResponseVO.errBuilder() + .errCode(errCode) + .errMsg(errMsg) + .build(); + } + } + + + + + + public static EnsResponseVO getCIProxy(String origin, String pathname, String siteCode, String sitePw, String jumin) { + + final String sSiteCode = siteCode; // NICE평가정보에서 발급한 서비스 사이트코드 + final String sSitePw = sitePw; + final String sJumin = jumin.replaceAll("[^0-9]", ""); + + + + int iRtnCI = -1; + EnsErrCd errCode = EnsErrCd.ERR999; + String errMsg = "API 호출 오류. 방화벽을 확인해 보시기 바랍니다."; + String ci = null; + try { + + //header 설정 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); + + //url 설정 + StringBuilder url = new StringBuilder(); + url.append(origin) + .append(pathname); + + //body 설정 + Map mParam = new HashMap<>(); + mParam.put("site_code", sSiteCode); + mParam.put("site_pw", sSitePw); + mParam.put("jid", sJumin); + ObjectMapper mapper = new ObjectMapper(); + String jsonStr = mapper.writeValueAsString(mParam); + + + //api 호출 + ResponseEntity resp = callApi(HttpMethod.POST, url.toString(), jsonStr, headers); + + try { + Gson gson = new GsonBuilder().disableHtmlEscaping().registerTypeAdapter(Map.class, new MapDeserailizer()).serializeNulls().create(); + Map mResponse = gson.fromJson(resp.getBody(), Map.class); + + if(!"OK".equals(mResponse.get("errCode"))){ + throw new EnsException(EnsErrCd.valueOfEnum((String) mResponse.get("errCode")), (String) mResponse.get("errMsg")); + } + + // 결과설정 + errCode = EnsErrCd.OK; + errMsg = String.format("[%s] (응답코드 %s)", EnsErrCd.OK.getCodeNm(), iRtnCI); + ci = (String) mResponse.get("resultInfo"); + } catch (Exception e) { + throw new EnsException(EnsErrCd.ERR505, String.format("CI변환 응답데이터 파싱 실패. %s", resp.getBody())); + } + + } catch (EnsException e){ + errCode = e.getErrCd(); + errMsg = e.getMessage(); + } catch (Exception e) { + // 결과설정 + errCode = EnsErrCd.ERR602; + errMsg = String.format("[나이스API 오류] %s (응답코드 %s)", e.getMessage(), iRtnCI); + } finally { + if(EnsErrCd.OK.equals(errCode)) + return EnsResponseVO.okBuilder() + .resultInfo(ci) + .build(); + else + return EnsResponseVO.errBuilder() + .errCode(errCode) + .errMsg(errMsg) + .build(); + } + } + + + + + + public static NiceDiCiRespDTO getDI(String siteCode, String sitePw, String jumin) { + + String sSiteCode = siteCode; // NICE평가정보에서 발급한 서비스 사이트코드 + String sSitePw = sitePw; // NICE평가정보에서 발급한 서비스 사이트패스워드 + + String sJumin = jumin; // 주민등록번호 13자리 + String sFlag = "JID"; // 서비스 구분값 (JID:주민번호 이용) + + + // 모듈 객체 생성 + VNOInterop vnoInterop = new VNOInterop(); + + + NiceDiCiRespDTO diCiRespDTO = new NiceDiCiRespDTO(); + try { + /* ──── DI 값을 추출하기 위한 부분 Start */ + // 인증요청처리 + int iRtnDI = vnoInterop.fnRequestDupInfo(sSiteCode, sSitePw, sJumin, sFlag); + System.out.println("iRtnDI=" + iRtnDI); + + // 인증결과코드에 따른 처리 + if (iRtnDI == 1) { + // DI 값 추출 (중복가입 확인값, 64Byte) + String sDupInfo = vnoInterop.getDupInfo(); + System.out.println("DUPINFO=[" + sDupInfo + "]"); + + // DI 설정 + diCiRespDTO.setDici(sDupInfo); + } else if (iRtnDI == 3) { + System.out.println("[사용자 정보와 서비스 구분값 매핑 오류]"); + System.out.println("사용자 정보와 서비스 구분값이 서로 일치하도록 매핑하여 주시기 바랍니다."); + + // Error 설정 + diCiRespDTO.setError_code(iRtnDI+""); + diCiRespDTO.setError_message("[사용자 정보와 서비스 구분값 매핑 오류] 사용자 정보와 서비스 구분값이 서로 일치하도록 매핑하여 주시기 바랍니다."); + } else if (iRtnDI == -9) { + System.out.println("[입력값 오류]"); + System.out.println("fnRequestDupInfo 함수 처리 시 필요한 4개의 파라미터값의 정보를 정확하게 입력해 주시기 바랍니다."); + + // Error 설정 + diCiRespDTO.setError_code(iRtnDI+""); + diCiRespDTO.setError_message("[입력값 오류] fnRequestDupInfo 함수 처리 시 필요한 4개의 파라미터값의 정보를 정확하게 입력해 주시기 바랍니다."); + } else if (iRtnDI == -21 || iRtnDI == -31 || iRtnDI == -34) { + System.out.println("[통신오류]"); + System.out.println("방화벽 이용 시 아래 IP와 Port(총 5개)를 등록해주셔야 합니다."); + System.out.println("IP : 203.234.219.72 / Port : 81, 82, 83, 84, 85"); + + // Error 설정 + diCiRespDTO.setError_code(iRtnDI+""); + diCiRespDTO.setError_message("[통신오류 오류] 방화벽 이용 시 아래 IP와 Port(총 5개)를 등록해주셔야 합니다. IP : 203.234.219.72 / Port : 81, 82, 83, 84, 85"); + } else { + System.out.println("[기타오류]"); + System.out.println("iRtnDI 값 확인 후 NICE평가정보 전산 담당자에게 문의"); + + // Error 설정 + diCiRespDTO.setError_code(iRtnDI+""); + diCiRespDTO.setError_message("[기타오류] iRtnDI 값 확인 후 NICE평가정보 전산 담당자에게 문의"); + } + /* ──── DI 값을 추출하기 위한 부분 End */ + } catch (Exception e) { + diCiRespDTO.setError_code(String.format("%s %s", HttpStatus.INTERNAL_SERVER_ERROR.value(), HttpStatus.INTERNAL_SERVER_ERROR.name())); + diCiRespDTO.setError_message(e.getMessage()); + } + + return diCiRespDTO; + } + + + + /** + *

메소드 설명: API 호출
+	 * 
+ * @param method + * @param url + * @param body + * @param headers + * @return ResponseEntity 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 4. + * @apiNote: 사이트 참조 https://e2e2e2.tistory.com/15 + */ + private static ResponseEntity callApi(HttpMethod method, String url, String body, HttpHeaders headers) { + log.debug("param ======================="); + log.debug(body); + + + ResponseEntity responseEntity = null; + try { + //uri 및 entity(param) 설정 + HttpEntity entity = null; + UriComponents uri = null; + switch (method) { + case GET: + entity = new HttpEntity<>(headers); + uri = UriComponentsBuilder + .fromHttpUrl(String.format("%s?%s", url, body==null?"":body)) +// .encode(StandardCharsets.UTF_8) //"%"기호가 "%25"로 인코딩 발생하여 주석처리 함. + .build(false); + break; + case POST: + entity = new HttpEntity<>(body, headers); + uri = UriComponentsBuilder + .fromHttpUrl(url) + .encode(StandardCharsets.UTF_8) + .build(); + break; + + default: + break; + } + + + //api 호출 + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + factory.setConnectTimeout(3000); +// factory.setReadTimeout(3000); + factory.setReadTimeout(10000); + RestTemplate restTemplate = new RestTemplate(factory); + System.out.println(" url => " + uri.toString()); + System.out.println(" method => " + method); + System.out.println(" headers => "+ entity.getHeaders().toString()); + System.out.println(" body => "+ entity.getBody()); + responseEntity = restTemplate.exchange(URI.create(uri.toString()), method, entity, String.class); + + /* + * HttpStatus 정보 확인 방법 + * -.코드: responseEntity.getStatusCodeValue() + * -.메시지: responseEntity.getStatusCode() + */ + + } catch (HttpServerErrorException e) { + responseEntity = new ResponseEntity(e.getResponseBodyAsString(), e.getStatusCode()); + log.error(String.format("call API 서버오류[url =>%s param => %s error => %s]", url, body, e.getMessage())); + } catch (HttpClientErrorException e) { + responseEntity = new ResponseEntity(e.getResponseBodyAsString(), e.getStatusCode()); + log.error(String.format("call API 클라이언트오류[url =>%s param => %s error => %s]", url, body, e.getMessage())); + } catch (RestClientException e) { //timeout 발생 또는 기타 오류... + responseEntity = new ResponseEntity(e.getMessage(), HttpStatus.REQUEST_TIMEOUT); + log.error(String.format("RestAPI 호출 오류[url =>%s param => %s error => %s]", url, body, e.getMessage())); + } catch (Exception e) { + responseEntity = new ResponseEntity(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + log.error(String.format("call API 기타오류[url =>%s param => %s error => %s]", url, body, e.getMessage())); + } + + + return responseEntity; + } + + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/OrgMng.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/OrgMng.java new file mode 100644 index 0000000..6a2931f --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/OrgMng.java @@ -0,0 +1,190 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.domain; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.time.LocalDateTime; + +//@Data +@Entity +@Getter +@ToString +@SuperBuilder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_org_mng", schema = "", catalog = "") +//@SuperBuilder +//@Inheritance(strategy = InheritanceType.JOINED) +//@DiscriminatorColumn(name = "DTYPE") +public class OrgMng { + + @Id + @Column(name = "org_cd", nullable = false, length = 20) + private String orgCd; + + + @Column(name = "org_nm", nullable = false, length = 30) + @Setter + private String orgNm; + + + @Column(name = "regist_dt", nullable = true) + @CreationTimestamp + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + private LocalDateTime registDt; + + + @Column(name = "last_updt_dt", nullable = true) + @UpdateTimestamp + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + private LocalDateTime lastUpdtDt; + + + + @Column(name = "kko_md_access_token", nullable = true, length = 50) + @Setter + private String kkoMdAccessToken; + + @Column(name = "kko_md_contract_uuid", nullable = true, length = 50) + @Setter + private String kkoMdContractUuid; + + + @Column(name = "kko_bp_biller_code", nullable = true, length = 30) + @Setter + private String kkoBpBillerCode; + + @Column(name = "kko_bp_authorization", nullable = true, length = 64) + @Setter + private String kkoBpAuthorization; + + @Column(name = "kko_bp_csign_yn", nullable = true, length = 1) + @Setter + private String kkoBpCsignYn; + + @Column(name = "kko_bp_url_api", nullable = true, length = 100) + @Setter + private String kkoBpUrlApi; + + @Column(name = "kko_bp_notice_api", nullable = true, length = 100) + @Setter + private String kkoBpNoticeApi; + + @Column(name = "kko_bp_prepay_api", nullable = true, length = 100) + @Setter + private String kkoBpPrepayApi; + + @Column(name = "kko_bp_payresult_api", nullable = true, length = 100) + @Setter + private String kkoBpPayresultApi; + + + @Column(name = "kko_at_bsid", nullable = true, length = 30) + @Setter + private String kkoAtBsid; + + @Column(name = "kko_at_passwd", nullable = true, length = 50) + @Setter + private String kkoAtPasswd; + + @Column(name = "kko_at_sender_key", nullable = true, length = 50) + @Setter + private String kkoAtSenderKey; + + + @Column(name = "nice_cd_site_code", nullable = true, length = 30) + @Setter + private String niceCdSiteCode; + + @Column(name = "nice_cd_site_pw", nullable = true, length = 30) + @Setter + private String niceCdSitePw; + + @Column(name = "nice_cd_client_id", nullable = true, length = 50) + @Setter + private String niceCdClientId; + + @Column(name = "nice_cd_client_sercet", nullable = true, length = 50) + @Setter + private String niceCdClientSercet; + + + @Column(name = "nv_st_x_naver_client_id", nullable = true, length = 30) + @Setter + private String nvStXNaverClientId; + + @Column(name = "nv_st_x_naver_client_secret", nullable = true, length = 30) + @Setter + private String nvStXNaverClientSecret; + + @Column(name = "nv_st_org_id", nullable = true, length = 50) + @Setter + private String nvStOrgId; + + + @Column(name = "nv_bp_partner_id", nullable = true, length = 30) + @Setter + private String nvBpPartnerId; + + @Column(name = "nv_bp_client_id", nullable = true, length = 30) + @Setter + private String nvBpClientId; + + @Column(name = "nv_bp_client_secret", nullable = true, length = 30) + @Setter + private String nvBpClientSecret; + + @Column(name = "nv_bp_notice_api", nullable = true, length = 100) + @Setter + private String nvBpNoticeApi; + + @Column(name = "nv_bp_prepay_api", nullable = true, length = 100) + @Setter + private String nvBpPrepayApi; + + @Column(name = "nv_bp_payresult_api", nullable = true, length = 100) + @Setter + private String nvBpPayresultApi; + + @Column(name = "nv_bp_paycancel_api", nullable = true, length = 100) + @Setter + private String nvBpPaycancelApi; + + + @Column(name = "kt_st_access_token", nullable = true, length = 1000) + @Setter + private String ktStAccessToken; + + @Column(name = "kt_st_service_cd", nullable = true, length = 5) + @Setter + private String ktStServiceCd; + + + @Column(name = "kt_st_service_key", nullable = true, length = 100) + @Setter + private String ktStServiceKey; + + @Column(name = "kt_st_clientId", nullable = true, length = 50) + @Setter + private String ktStClientId; + + @Column(name = "kt_st_client_secret", nullable = true, length = 50) + @Setter + private String ktStClientSecret; + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/TmpltMng.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/TmpltMng.java new file mode 100644 index 0000000..316c8c2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/TmpltMng.java @@ -0,0 +1,159 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.domain; + +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.ids.TmpltMngIds; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +//@Data +@Getter +@ToString +//@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_tmplt_mng", schema = "", catalog = "") +@IdClass(TmpltMngIds.class) +@SuperBuilder +@Inheritance(strategy = InheritanceType.JOINED) +@DiscriminatorColumn(name = "dtype") +@DiscriminatorValue("basic") +public class TmpltMng { + +// @Id +// @Column(name = "org_cd", nullable = false, length = 20) +// private String orgCd; + + @Column(length = 10, insertable = false, updatable = false) + private String dtype; + @Id + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "org_cd") + @Setter + private OrgMng orgMng; + + @Id + @Column(name = "tmplt_cd", nullable = false, length = 30) + private String tmpltCd; + + + @Column(name = "title", nullable = false, length = 40) + @Setter + private String title; + + + @Column(name = "message", nullable = false, length = 2000) + @Setter + private String message; + + +// @Column(name = "cs_number", nullable = true, length = 20) +// @Setter +// private String csNumber; +// + +// @Column(name = "cs_name", nullable = true, length = 10) +// @Setter +// private String csName; + + + @Column(name = "use_yn", nullable = false, length = 1) + @Setter + private String useYn; + + + @Column(name = "regist_id", nullable = true) + @Setter + private String registId; + + + @Column(name = "regist_dt", nullable = true) + @CreationTimestamp + private LocalDateTime registDt; + + + @Column(name = "upd_id", nullable = true) + @Setter + private String updId; + + + @Column(name = "last_updt_dt", nullable = true) + @UpdateTimestamp + private LocalDateTime lastUpdtDt; + + + + + + +// @Column(name = "ci_send_yn", nullable = true) +// private String ciSendYn; + +// @Column(name = "div_send_cnt", nullable = true) +// private Long divSendCnt; + +// @Column(name = "div_send_min", nullable = true) +// private Long divSendMin; + +// @Column(name = "send_thread_cnt", nullable = true) +// private Long sendThreadCnt; + +// @Column(name = "fail_resend_cnt", nullable = true) +// private Long failResendCnt; + +// @Column(name = "fail_resend_min", nullable = true) +// private Long failResendMin; + +// @Column(name = "tmot_api_use_yn", nullable = true) +// private String tmotApiUseYn; + +// @Column(name = "pce_doc_reg_yn", nullable = true) +// private String pceDocRegYn; + +// @Column(name = "access_token_use_yn", nullable = true) +// private String accessTokenUseYn; + +// @Column(name = "access_token", nullable = true) +// private String accessToken; + +// @Column(name = "service_cd", nullable = true) +// private String serviceCd; + +// @Column(name = "service_key", nullable = true) +// private String serviceKey; + +// @Column(name = "tx_prefix", nullable = true) +// private String txPrefix; + +// @Column(name = "verify_auth_name", nullable = true) +// private String verifyAuthName; + +// @Column(name = "allow_simple_reg_yn", nullable = true) +// private String allowSimpleRegYn; + +// @Column(name = "msg_cd", nullable = true) +// private String msgCd; + +// @Column(name = "nv_client_id", nullable = true) +// private String nvClientId; + +// @Column(name = "nv_client_secret", nullable = true) +// private String nvClientSecret; + +// @Column(name = "h_local_gov", nullable = true) +// private String hLocalGov; + +// @Column(name = "h_dept", nullable = true) +// private String hDept; + +// @Column(name = "h_info_name", nullable = true) +// private String hInfoName; + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/ids/TmpltMngIds.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/ids/TmpltMngIds.java new file mode 100644 index 0000000..3bbd6c3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/ids/TmpltMngIds.java @@ -0,0 +1,19 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.domain.ids; + +import lombok.*; + +import java.io.Serializable; + +@Getter +@Setter +@EqualsAndHashCode +@NoArgsConstructor +@Builder +@AllArgsConstructor +public class TmpltMngIds implements Serializable { + +// private String orgCd; + private String orgMng; + + private String tmpltCd; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/OrgMngRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/OrgMngRepository.java new file mode 100644 index 0000000..a295dc4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/OrgMngRepository.java @@ -0,0 +1,7 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository; + +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface OrgMngRepository extends JpaRepository, OrgMngRepositoryCustom { +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/OrgMngRepositoryCustom.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/OrgMngRepositoryCustom.java new file mode 100644 index 0000000..fc1678a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/OrgMngRepositoryCustom.java @@ -0,0 +1,10 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository; + +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.OrgMngSearchDTO; + +import java.util.List; + +public interface OrgMngRepositoryCustom { + List findAllFetchBySearchDTO(OrgMngSearchDTO searchDTO); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/OrgMngRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/OrgMngRepositoryImpl.java new file mode 100644 index 0000000..0a13797 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/OrgMngRepositoryImpl.java @@ -0,0 +1,71 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.OrgMngSearchDTO; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.util.List; + +import static cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng.orgMng; + +@RequiredArgsConstructor +public class OrgMngRepositoryImpl implements OrgMngRepositoryCustom { + + private final JPAQueryFactory query; + + @Override + public List findAllFetchBySearchDTO(OrgMngSearchDTO searchDTO) { + return query.selectFrom(orgMng) + .where(eqSearchDTO(searchDTO)) + .fetch(); + } + + private BooleanBuilder eqSearchDTO(OrgMngSearchDTO searchDTO) { + BooleanBuilder builder = new BooleanBuilder(); + + if (!CmmnUtil.isEmpty(searchDTO.getSchOrgCd())) + builder.and(orgMng.orgCd.eq(searchDTO.getSchOrgCd())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchOrgNm())) + builder.and(orgMng.orgNm.like(searchDTO.getSchOrgNm() + "%")); + + if (!CmmnUtil.isEmpty(searchDTO.getSchKkoMdAccessToken())) + builder.and(orgMng.kkoMdAccessToken.eq(searchDTO.getSchKkoMdAccessToken())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchKkoMdContractUuid())) + builder.and(orgMng.kkoMdContractUuid.eq(searchDTO.getSchKkoMdContractUuid())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchKkoBpBillerCode())) + builder.and(orgMng.kkoBpBillerCode.eq(searchDTO.getSchKkoBpBillerCode())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchKkoBpAuthorization())) + builder.and(orgMng.kkoBpAuthorization.eq(searchDTO.getSchKkoBpAuthorization())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchKkoAtBsid())) + builder.and(orgMng.kkoAtBsid.eq(searchDTO.getSchKkoAtBsid())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchKkoAtPasswd())) + builder.and(orgMng.kkoAtPasswd.eq(searchDTO.getSchKkoAtPasswd())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchKkoAtSenderKey())) + builder.and(orgMng.kkoAtSenderKey.eq(searchDTO.getSchKkoAtSenderKey())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchNiceCdSiteCode())) + builder.and(orgMng.niceCdSiteCode.eq(searchDTO.getSchNiceCdSiteCode())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchNiceCdSitePw())) + builder.and(orgMng.niceCdSitePw.eq(searchDTO.getSchNiceCdSitePw())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchNvStXNaverClientId())) + builder.and(orgMng.nvStXNaverClientId.eq(searchDTO.getSchNvStXNaverClientId())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchNvStXNaverClientSecret())) + builder.and(orgMng.nvStXNaverClientSecret.eq(searchDTO.getSchNvStXNaverClientSecret())); + + + return builder; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/TmpltMngRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/TmpltMngRepository.java new file mode 100644 index 0000000..fce8f31 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/TmpltMngRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository; + +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.TmpltMng; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TmpltMngRepository extends JpaRepository, TmpltMngRepositoryCustom { + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/TmpltMngRepositoryCustom.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/TmpltMngRepositoryCustom.java new file mode 100644 index 0000000..7593bd8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/TmpltMngRepositoryCustom.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository; + +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.TmpltMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngSearchDTO; + +public interface TmpltMngRepositoryCustom extends TmpltMngRepositorySupport { + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/TmpltMngRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/TmpltMngRepositoryImpl.java new file mode 100644 index 0000000..2854d0f --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/TmpltMngRepositoryImpl.java @@ -0,0 +1,102 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.TmpltMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngSearchDTO; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.QBean; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.util.List; +import java.util.Optional; + +import static cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng.orgMng; +import static cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QTmpltMng.tmpltMng; + +@RequiredArgsConstructor +public class TmpltMngRepositoryImpl implements TmpltMngRepositoryCustom { + + private final JPAQueryFactory query; + + @Override + public List findAllFetchBySearchDTO(TmpltMngSearchDTO searchDTO) { + return query.selectFrom(tmpltMng) + .innerJoin(tmpltMng.orgMng, orgMng) + .fetchJoin() + .where(eqSearchDTO(searchDTO)) + .fetch(); + } + + @Override + public Optional findFetchByOrgCdAndTmpltCd(String orgCd, String tmpltCd) { + return Optional.ofNullable(query.selectFrom(tmpltMng) + .innerJoin(tmpltMng.orgMng, orgMng) + .fetchJoin() + .where(tmpltMng.orgMng.orgCd.eq(orgCd) + .and(tmpltMng.tmpltCd.eq(tmpltCd))) + .fetchOne()); + } + + @Override + public Optional findDtoByOrgCdAndTmpltCd(String orgCd, String tmpltCd) { + return Optional.ofNullable(query.select(mappedDto()) + .from(tmpltMng) + .where(tmpltMng.orgMng.orgCd.eq(orgCd) + .and(tmpltMng.tmpltCd.eq(tmpltCd))) + .fetchOne()); + } + + @Override + public List findAllDtoBySearchDTO(TmpltMngSearchDTO searchDTO) { + return query.select(mappedDto()) + .from(tmpltMng) + .innerJoin(tmpltMng.orgMng, orgMng) + .where(eqSearchDTO(searchDTO)) + .fetch(); + } + + private QBean mappedDto() { + return Projections.fields(TmpltMngDTO.class + , tmpltMng.dtype + , tmpltMng.orgMng.orgCd + , tmpltMng.orgMng.orgNm + , tmpltMng.tmpltCd + , tmpltMng.title + , tmpltMng.message + , tmpltMng.useYn + ); + } + + private BooleanBuilder eqSearchDTO(TmpltMngSearchDTO searchDTO) { + BooleanBuilder builder = new BooleanBuilder(); + + if (!CmmnUtil.isEmpty(searchDTO.getSchOrgCd())) + builder.and(tmpltMng.orgMng.orgCd.eq(searchDTO.getSchOrgCd())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchTmpltCd())) + builder.and(tmpltMng.tmpltCd.eq(searchDTO.getSchTmpltCd())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchTitle())) + builder.and(tmpltMng.title.like(searchDTO.getSchTitle() + "%")); + + + return builder; + } + + @Override + public Optional findFetchByOrgCdAndTmpltCdAndUseYn(String orgCd, String tmpltCd, String useYn) { + return Optional.ofNullable( + query.selectFrom(tmpltMng) + .innerJoin(tmpltMng.orgMng, orgMng) + .fetchJoin() + .where( + tmpltMng.orgMng.orgCd.eq(orgCd) + .and(tmpltMng.tmpltCd.eq(tmpltCd)) + .and(tmpltMng.useYn.eq(useYn)) + ) + .fetchOne()); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/TmpltMngRepositorySupport.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/TmpltMngRepositorySupport.java new file mode 100644 index 0000000..bf97d7e --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/repository/TmpltMngRepositorySupport.java @@ -0,0 +1,17 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository; + +import java.util.List; +import java.util.Optional; + +public interface TmpltMngRepositorySupport { + + Optional findFetchByOrgCdAndTmpltCd(String orgCd, String tmpltCd); + + List findAllFetchBySearchDTO(P searchDTO); + + Optional findDtoByOrgCdAndTmpltCd(String orgCd, String tmpltCd); + + List findAllDtoBySearchDTO(P searchDTO); + + Optional findFetchByOrgCdAndTmpltCdAndUseYn(String orgCd, String tmpltCd, String useYn); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/OrgMngDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/OrgMngDTO.java new file mode 100644 index 0000000..6b14800 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/OrgMngDTO.java @@ -0,0 +1,128 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; + +@Data +@Builder +@Schema(name = "OrgMngDTO") +public class OrgMngDTO { + + + @NotEmpty(message = "기관코드는 필수 입력값 입니다.") + @Length(max = 20, message = "기관코드의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "기관코드", example = "EX_ORG001") + private String orgCd; + + @NotEmpty(message = "기관명은 필수 입력값 입니다.") + @Length(max = 30, message = "기관명의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "기관명", example = "테스트 기관") + private String orgNm; + + + @Length(max = 50, message = "(계약정보)엑세스토큰의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)엑세스토큰", example = " ") + private String kkoMdAccessToken; + @Length(max = 50, message = "(계약정보)계약Uuid의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)계약Uuid", example = " ") + private String kkoMdContractUuid; + + @Length(max = 30, message = "(계약정보)빌러코드의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)빌러코드", example = " ") + private String kkoBpBillerCode; + @Length(max = 64, message = "(계약정보)허가코드의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)허가코드", example = " ") + private String kkoBpAuthorization; + @Pattern(regexp = "(Y|N)", message = "납부요청 위탁여부는 Y 또는 N 만 입력 할 수 있습니다.") + @Schema(required = false, title = "납부요청 위탁여부", example = " ") + private String kkoBpCsignYn; + @Length(max = 100, message = "청구서링크생성정보API의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "이용시스템의 청구서링크생성정보API URL", example = " ") + private String kkoBpUrlApi; + @Length(max = 100, message = "납부정보조회API의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "이용시스템의 납부정보조회API URL", example = " ") + private String kkoBpNoticeApi; + @Length(max = 100, message = "납부가능조회API의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "이용시스템의 납부가능조회API URL", example = " ") + private String kkoBpPrepayApi; + @Length(max = 100, message = "납부결과API의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "이용시스템의 납부결과API URL", example = " ") + private String kkoBpPayResultApi; + + @Length(max = 30, message = "(계약정보)bs아이디의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)bs아이디", example = " ") + private String kkoAtBsid; + @Length(max = 50, message = "(계약정보)패스워드의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)패스워드", example = " ") + private String kkoAtPasswd; + @Length(max = 50, message = "(계약정보)발송자키의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)발송자키", example = " ") + private String kkoAtSenderKey; + + @Length(max = 30, message = "(계약정보)사이트코드(socket)의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)사이트코드(socket)", example = " ") + private String niceCdSiteCode; + @Length(max = 30, message = "(계약정보)사이트패스워드(socket)의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)사이트패스워드(socket)", example = " ") + private String niceCdSitePw; + @Length(max = 50, message = "(계약정보)클라이언트ID(rest)의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)클라이언트ID(rest)", example = " ") + private String niceCdClientId; + @Length(max = 50, message = "(계약정보)클라이언트패스워드(rest)의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)클라이언트패스워드(rest)", example = " ") + private String niceCdClientSercet; + + @Length(max = 30, message = "(계약정보)클라이언트 아이디의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)클라이언트 아이디", example = " ") + private String nvStXNaverClientId; + @Length(max = 30, message = "(계약정보)클라이언트 패스워드의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)클라이언트 패스워드", example = " ") + private String nvStXNaverClientSecret; + @Length(max = 50, message = "(계약정보)하위기관명의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)하위기관명", example = " ") + private String nvStOrgId; + + @Length(max = 30, message = "(계약정보)파트너ID의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)파트너ID", example = " ") + private String nvBpPartnerId; + @Length(max = 30, message = "(계약정보)클라이언트ID의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)클라이언트ID", example = " ") + private String nvBpClientId; + @Length(max = 30, message = "(계약정보)클라이언트Pwd의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)클라이언트Pwd", example = " ") + private String nvBpClientSecret; + @Length(max = 100, message = "납부정보조회API의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "이용시스템의 납부정보조회API URL", example = " ") + private String nvBpNoticeApi; + @Length(max = 100, message = "납부가능조회API의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "이용시스템의 납부가능조회API URL", example = " ") + private String nvBpPrepayApi; + @Length(max = 100, message = "납부결과API의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "이용시스템의 납부결과API URL", example = " ") + private String nvBpPayresultApi; + @Length(max = 100, message = "결제취소API의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "이용시스템의 결제취소API URL", example = " ") + private String nvBpPaycancelApi; + + @Length(max = 1000, message = "(계약정보)엑세스토큰의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)엑세스토큰", example = " ") + private String ktStAccessToken; + @Length(max = 5, message = "(계약정보)서비스코드의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)서비스코드", example = " ") + private String ktStServiceCd; + @Length(max = 100, message = "(계약정보)서비스키의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)서비스키", example = " ") + private String ktStServiceKey; + @Length(max = 50, message = "(계약정보)고객ID의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)고객ID", example = " ") + private String ktStClientId; + @Length(max = 50, message = "(계약정보)고객비밀번호의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "(계약정보)고객비밀번호", example = " ") + private String ktStClientSecret; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/OrgMngSearchDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/OrgMngSearchDTO.java new file mode 100644 index 0000000..e4f44dd --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/OrgMngSearchDTO.java @@ -0,0 +1,54 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "OrgMngSearchDTO") +public class OrgMngSearchDTO { + + + @Schema(required = true, title = "기관코드", example = "EX_ORG001") + private String schOrgCd; + + @Schema(required = true, title = "기관명", example = " ") + private String schOrgNm; + + + + + @Schema(required = false, title = "(계약정보)엑세스토큰", example = " ") + private String schKkoMdAccessToken; + @Schema(required = false, title = "(계약정보)계약Uuid", example = " ") + private String schKkoMdContractUuid; + + @Schema(required = false, title = "(계약정보)빌러코드", example = " ") + private String schKkoBpBillerCode; + @Schema(required = false, title = "(계약정보)허가코드", example = " ") + private String schKkoBpAuthorization; + + @Schema(required = false, title = "(계약정보)bs아이디", example = " ") + private String schKkoAtBsid; + @Schema(required = false, title = "(계약정보)패스워드", example = " ") + private String schKkoAtPasswd; + @Schema(required = false, title = "(계약정보)발송자키", example = " ") + private String schKkoAtSenderKey; + + @Schema(required = false, title = "(계약정보)사이트코드", example = " ") + private String schNiceCdSiteCode; + @Schema(required = false, title = "(계약정보)사이트패스워드", example = " ") + private String schNiceCdSitePw; + + @Schema(required = false, title = "(계약정보)클라이언트 아이디", example = " ") + private String schNvStXNaverClientId; + @Schema(required = false, title = "(계약정보)클라이언트 패스워드", example = " ") + private String schNvStXNaverClientSecret; + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/TmpltMngByTypeDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/TmpltMngByTypeDTO.java new file mode 100644 index 0000000..43be23b --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/TmpltMngByTypeDTO.java @@ -0,0 +1,25 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; +import java.io.Serializable; + + +@Data +@SuperBuilder +@NoArgsConstructor +@Schema(name = "TmpltMngByTypeDTO") +public class TmpltMngByTypeDTO extends TmpltMngDTO { + + @Length(max = 2000, message = "우선순위 메시지의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "우선순위 메시지", example = "우선순위 메시지 입니다.") + private String pryMessage; + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/TmpltMngDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/TmpltMngDTO.java new file mode 100644 index 0000000..702819a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/TmpltMngDTO.java @@ -0,0 +1,51 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; +import java.io.Serializable; + +@Data +//@Builder +@SuperBuilder +@NoArgsConstructor +@Schema(name = "TmpltMngDTO") +public class TmpltMngDTO implements Serializable { + + private String dtype; + + @NotEmpty(message = "기관코드는 필수 입력값 입니다.") + @Length(max = 20, message = "기관코드의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "기관코드", example = "EX_ORG001") + private String orgCd; + + @Schema(required = false, title = "기관명", example = "테스트 기관", hidden = true) + private String orgNm; + @NotEmpty(message = "템플릿코드는 필수 입력값 입니다.") + @Length(max = 30, message = "템플릿코드의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "템플릿코드", example = "EX_TMPLT001") + private String tmpltCd; + + @NotEmpty(message = "템플릿명칭은 필수 입력값 입니다.") + @Length(max = 40, message = "템플릿명칭의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "메시지명칭", example = "테스트 템플릿") + private String title; + + @NotEmpty(message = "템플릿메시지는 필수 입력값 입니다.") + @Length(max = 1000, message = "템플릿메시지의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "메시지", example = "해당 안내문은 다음과 같습니다.") + private String message; + + @NotEmpty(message = "사용여부는 필수 입력값 입니다.") + @Length(max = 1, message = "사용여부의 최대 길이를 초과 했습니다.") + @Pattern(regexp = "(Y|N)", message = "사용여부는 Y 또는 N 만 입력 할 수 있습니다.") + @Schema(required = true, title = "사용여부", example = "Y") + private String useYn; + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/TmpltMngSearchDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/TmpltMngSearchDTO.java new file mode 100644 index 0000000..7086c1c --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/TmpltMngSearchDTO.java @@ -0,0 +1,25 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Data +@Builder +//@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "TmpltMngSearchDTO") +public class TmpltMngSearchDTO { + + @Schema(required = true, title = "기관코드", example = "EX_ORG001") + private String schOrgCd; + + @Schema(required = true, title = "템플릿코드", example = "EX_TMPLT001") + private String schTmpltCd; + @Schema(required = true, title = "템플릿 명칭", example = " ") + private String schTitle; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/struct/OrgMngMapper.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/struct/OrgMngMapper.java new file mode 100644 index 0000000..24333c1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/struct/OrgMngMapper.java @@ -0,0 +1,13 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.model.struct; + +import cokr.xit.ens.core.mapstruct.GenericMapper; +import cokr.xit.ens.core.mapstruct.StructMapperConfig; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.TmpltMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.OrgMngDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngDTO; +import org.mapstruct.Mapper; + +@Mapper(config = StructMapperConfig.class) +public interface OrgMngMapper extends GenericMapper { +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/struct/TmpltMngMapper.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/struct/TmpltMngMapper.java new file mode 100644 index 0000000..ad9630f --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/struct/TmpltMngMapper.java @@ -0,0 +1,11 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.model.struct; + +import cokr.xit.ens.core.mapstruct.GenericMapper; +import cokr.xit.ens.core.mapstruct.StructMapperConfig; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.TmpltMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngDTO; +import org.mapstruct.Mapper; + +@Mapper(config = StructMapperConfig.class) +public interface TmpltMngMapper extends GenericMapper { +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/presentation/OrgMngController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/presentation/OrgMngController.java new file mode 100644 index 0000000..b659cf2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/presentation/OrgMngController.java @@ -0,0 +1,82 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.presentation; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.OrgMngDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.OrgMngSearchDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.service.OrgMngService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Tag(name = "OrgMngController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class OrgMngController { + + private final OrgMngService orgMngService; + + + + + @Operation(summary = "기관 목록 조회") + @GetMapping(value = "/sys/mng/org", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity>> findAll(OrgMngSearchDTO searchDTO){ + EnsResponseVO> responseVO = orgMngService.findAllBySearchDTO(searchDTO); + + return new ResponseEntity>>(responseVO, HttpStatus.OK); + } + + + + + @Operation(summary = "기관정보 조회") + @GetMapping(value = "/sys/mng/org/{orgCd}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity find(@PathVariable String orgCd){ + EnsResponseVO responseVO = orgMngService.find(orgCd); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + + + + @Operation(summary = "기관정보 신규 등록") + @PostMapping(value = "/sys/mng/org", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity add(@RequestBody OrgMngDTO reqDTO){ + EnsResponseVO responseVO = orgMngService.add(reqDTO); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + + + + @Operation(summary = "기관정보 수정") + @PutMapping(value = "/sys/mng/org", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity modify(@RequestBody OrgMngDTO reqDTO){ + EnsResponseVO responseVO = orgMngService.modify(reqDTO); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + + + + @Operation(summary = "기관정보 삭제") + @DeleteMapping(value = "/sys/mng/org/{orgCd}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity delete(@PathVariable String orgCd){ + EnsResponseVO responseVO = orgMngService.delete(orgCd); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/presentation/TmpltMngController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/presentation/TmpltMngController.java new file mode 100644 index 0000000..255e081 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/presentation/TmpltMngController.java @@ -0,0 +1,144 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.presentation; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngSearchDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.service.TmpltMngService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@Tag(name = "TmpltMngController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class TmpltMngController { + + private final TmpltMngService tmpltMngService; + + @Operation(summary = "템플릿(타입별) 목록 조회") + @Parameters({ + @Parameter(in = ParameterIn.PATH, name = "dType"), + }) + @GetMapping(value = "/sys/mng/tmplt/{dType}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity>> findAll(@PathVariable String dType, TmpltMngSearchDTO searchDTO) { + EnsResponseVO> responseVO = tmpltMngService.findAllBySearchDTO(searchDTO, dType); + + return new ResponseEntity>>(responseVO, HttpStatus.OK); + } + + + @Operation(summary = "템플릿(타입별) 조회") + @Parameters({ + @Parameter(in = ParameterIn.PATH, name = "dType"), + @Parameter(in = ParameterIn.PATH, name = "orgCd"), + @Parameter(in = ParameterIn.PATH, name = "tmpltCd"), + }) + @GetMapping(value = "/sys/mng/tmplt/{dType}/{orgCd}/{tmpltCd}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> find(@PathVariable String dType, @PathVariable String orgCd, @PathVariable String tmpltCd) { + TmpltMngSearchDTO searchDTO = TmpltMngSearchDTO.builder() + .schOrgCd(orgCd) + .schTmpltCd(tmpltCd) + .build(); + EnsResponseVO responseVO = tmpltMngService.find(orgCd, tmpltCd, dType); + + return new ResponseEntity>(responseVO, HttpStatus.OK); + } + + + @Operation(summary = "템플릿 신규 등록") + @Parameters({ + @Parameter(in = ParameterIn.PATH, name = "dType"), + }) + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Example_01" + , summary = "기본(basic)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT001\",\"title\":\"테스트 템플릿\",\"message\":\"해당 안내문은 다음과 같습니다.\"}"), + @ExampleObject(name = "Example_02" + , summary = "카카오 알림톡(kkoat)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT002\",\"title\":\"테스트 템플릿\",\"message\":\"해당 안내문은 다음과 같습니다.\",\"biztalkOrgCd\":\"\",\"biztalkTmpltCode\":\"CEPHIS_001\"}"), + @ExampleObject(name = "Example_03" + , summary = "카카오 내문서함(kkomd)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT003\",\"title\":\"테스트 템플릿\",\"message\":\"해당 안내문은 다음과 같습니다.\",\"csNumber\":\"02-123-1234\",\"csName\":\"고객센터\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"N\"}"), + @ExampleObject(name = "Example_04" + , summary = "네이버 고지서(nvst)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT004\",\"title\":\"테스트 템플릿\",\"message\":\"null...\",\"callCenterNo\":\"02-1234-1234\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"N\",\"messageDataFmt\":{\"data\":[{\"수신인\":\"#{RECV_NAME}\"},{\"주소\":\"#{ADDRESS}\"},{\"과태료\":\"#{AMOUNT}\"},{\"전화번호\":\"#{CALL_CENTER_NO}\"}]}}"), + @ExampleObject(name = "Example_05" + , summary = "통합고지(intgrn)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT005\",\"title\":\"테스트 템플릿\",\"message\":\"해당 안내문은 다음과 같습니다.\",\"try1\":\"kkoMydoc\",\"try2\":\"nvSigntalk\",\"try3\":\"kkoAlimtalk\",\"kkoAlimtalk\":{\"biztalkOrgCd\":\"\",\"biztalkTmpltCode\":\"CEPHIS_001\"},\"kkoMydoc\":{\"csNumber\":\"02-123-4567\",\"csName\":\"고객센터\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"N\"},\"nvSigntalk\":{\"callCenterNo\":\"02-123-1234\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"N\",\"messageDataFmt\":{\"data\":[{\"수신인\":\"#{RECV_NAME}\"},{\"주소\":\"#{ADDRESS}\"},{\"과태료\":\"#{AMOUNT}\"},{\"전화번호\":\"#{CALL_CENTER_NO}\"}]}},\"ktSigntalk\":{\"sndTelNo\":\"0212345678\",\"sendTel\":\"0256781234\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"N\"},\"ktGibis\":{\"msgCd\":\"MC001\",\"mtype\":\"mms\",\"optType\":1,\"sndTelNo\":\"044-211-3377\",\"sendTel\":\"044-211-3377\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"Y\"}}"), + @ExampleObject(name = "Example_06" + , summary = "KT 인증톡(ktst)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT006\",\"title\":\"테스트 템플릿\",\"message\":\"해당 안내문은 다음과 같습니다.\",\"sndTelNo\":\"0212345678\",\"sendTel\":\"0256781234\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"N\"}"), + @ExampleObject(name = "Example_07" + , summary = "KT 인증톡(ktgbs)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT007\",\"title\":\"테스트 템플릿\",\"message\":\"해당 안내문은 다음과 같습니다.\",\"msgCd\":\"MC001\",\"mtype\":\"mms\",\"optType\":1,\"sndTelNo\":\"044-211-3377\",\"sendTel\":\"044-211-3377\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"Y\"}") + }) + }) + @PostMapping(value = "/sys/mng/tmplt/{dType}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity add(@PathVariable String dType, @RequestBody Map mParam) { + EnsResponseVO responseVO = tmpltMngService.add(mParam, dType); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + + @Operation(summary = "템플릿 수정") + @Parameters({ + @Parameter(in = ParameterIn.PATH, name = "dType"), + }) + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Example_01" + , summary = "기본(basic)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT001\",\"title\":\"테스트 템플릿\",\"message\":\"해당 안내문은 다음과 같습니다.\"}"), + @ExampleObject(name = "Example_02" + , summary = "카카오 알림톡(kkoat)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT002\",\"title\":\"테스트 템플릿\",\"message\":\"해당 안내문은 다음과 같습니다.\",\"biztalkOrgCd\":\"\",\"biztalkTmpltCode\":\"CEPHIS_001\"}"), + @ExampleObject(name = "Example_03" + , summary = "카카오 내문서함(kkomd)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT003\",\"title\":\"테스트 템플릿\",\"message\":\"해당 안내문은 다음과 같습니다.\",\"csNumber\":\"02-123-1234\",\"csName\":\"고객센터\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"N\"}"), + @ExampleObject(name = "Example_04" + , summary = "네이버 고지서(nvst)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT004\",\"title\":\"테스트 템플릿\",\"message\":\"null...\",\"callCenterNo\":\"02-1234-1234\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"N\",\"messageDataFmt\":{\"data\":[{\"수신인\":\"#{RECV_NAME}\"},{\"주소\":\"#{ADDRESS}\"},{\"과태료\":\"#{AMOUNT}\"},{\"전화번호\":\"#{CALL_CENTER_NO}\"}]}}"), + @ExampleObject(name = "Example_05" + , summary = "통합고지(intgrn)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT005\",\"title\":\"테스트 템플릿\",\"message\":\"해당 안내문은 다음과 같습니다.\",\"try1\":\"kkoMydoc\",\"try2\":\"nvSigntalk\",\"try3\":\"kkoAlimtalk\",\"kkoAlimtalk\":{\"biztalkOrgCd\":\"\",\"biztalkTmpltCode\":\"CEPHIS_001\"},\"kkoMydoc\":{\"csNumber\":\"02-123-4567\",\"csName\":\"고객센터\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"N\"},\"nvSigntalk\":{\"callCenterNo\":\"02-123-1234\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"N\",\"messageDataFmt\":{\"data\":[{\"수신인\":\"#{RECV_NAME}\"},{\"주소\":\"#{ADDRESS}\"},{\"과태료\":\"#{AMOUNT}\"},{\"전화번호\":\"#{CALL_CENTER_NO}\"}]}},\"ktSigntalk\":{\"sndTelNo\":\"0212345678\",\"sendTel\":\"0256781234\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"N\"},\"ktGibis\":{\"msgCd\":\"MC001\",\"mtype\":\"mms\",\"optType\":1,\"sndTelNo\":\"044-211-3377\",\"sendTel\":\"044-211-3377\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"Y\"}}"), + @ExampleObject(name = "Example_06" + , summary = "KT 인증톡(ktst)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT006\",\"title\":\"테스트 템플릿\",\"message\":\"해당 안내문은 다음과 같습니다.\",\"sndTelNo\":\"0212345678\",\"sendTel\":\"0256781234\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"N\"}"), + @ExampleObject(name = "Example_07" + , summary = "KT 인증톡(ktgbs)" + , value = "{\"orgCd\":\"EX_ORG001\",\"tmpltCd\":\"EX_TMPLT007\",\"title\":\"테스트 템플릿\",\"message\":\"해당 안내문은 다음과 같습니다.\",\"msgCd\":\"MC001\",\"mtype\":\"mms\",\"optType\":1,\"sndTelNo\":\"044-211-3377\",\"sendTel\":\"044-211-3377\",\"ciTransUseYn\":\"Y\",\"tmpltMsgUseYn\":\"Y\",\"tmpltCsInfoUseYn\":\"Y\"}") + }) + }) + @PutMapping(value = "/sys/mng/tmplt/{dType}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity modify(@PathVariable String dType, @RequestBody Map mParam) { + EnsResponseVO responseVO = tmpltMngService.modify(mParam, dType); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + + @Operation(summary = "템플릿 삭제") + @DeleteMapping(value = "/sys/mng/tmplt/{orgCd}/{tmpltCd}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity delete(@PathVariable String orgCd, @PathVariable String tmpltCd) { + EnsResponseVO responseVO = tmpltMngService.delete(orgCd, tmpltCd); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/OrgMngService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/OrgMngService.java new file mode 100644 index 0000000..617d6c2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/OrgMngService.java @@ -0,0 +1,216 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.service; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.config.redis.CacheKey; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.OrgMngRepository; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.OrgMngDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.OrgMngSearchDTO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional +public class OrgMngService { + + private final OrgMngRepository orgMngRepository; + + public EnsResponseVO> findAllBySearchDTO(OrgMngSearchDTO searchDTO) { + return EnsResponseVO.>okBuilder() + .resultInfo(orgMngRepository.findAllFetchBySearchDTO(searchDTO)) + .build(); + + } + +// @Cacheable(value = CacheKey.ORGMNG, key = "#orgCd") + public EnsResponseVO find(String orgCd) { + try { + return EnsResponseVO.okBuilder() + .resultInfo(orgMngRepository.findById(orgCd).orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("기관코드(%s)와 일치하는 자료가 없습니다.", orgCd)))) + .build(); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + } + + + public EnsResponseVO add(OrgMngDTO dto) { + try { + final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + Set> list = validator.validate(dto); + if (list.size() > 0) { + return EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ERR410) + .errMsg("유효하지 않은 요청값 입니다.") + .resultInfo(list.stream() + .map(row -> String.format("%s [ %s ]", row.getMessageTemplate(), row.getPropertyPath())) + .collect(Collectors.toList())) + .build(); + } + if ("Y".equals(dto.getKkoBpCsignYn())) { + if (CmmnUtil.isEmpty(dto.getKkoBpPrepayApi()) || CmmnUtil.isEmpty(dto.getKkoBpPayResultApi())) + return EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ERR410) + .errMsg("납부요청 위탁여부(kkoBpCsignYn)가 Y 일 경우 \"납부가능조회API\"와 \"납부결과API\"의 URL은 필수 입니다.") + .build(); + } + orgMngRepository.findById(dto.getOrgCd()).ifPresent(orgmng -> { + throw new EnsException(EnsErrCd.ERR540, String.format("이미 등록된 기관코드(%s) 입니다.", dto.getOrgCd())); + }); + + + orgMngRepository.save(OrgMng.builder() + .orgCd(dto.getOrgCd()) + .orgNm(dto.getOrgNm()) +// .subOrgId(null) + .kkoMdAccessToken(dto.getKkoMdAccessToken()) + .kkoMdContractUuid(dto.getKkoMdContractUuid()) + .kkoBpBillerCode(dto.getKkoBpBillerCode()) + .kkoBpAuthorization(dto.getKkoBpAuthorization()) + .kkoBpCsignYn(dto.getKkoBpCsignYn()) + .kkoBpUrlApi(dto.getKkoBpUrlApi()) + .kkoBpNoticeApi(dto.getKkoBpNoticeApi()) + .kkoBpPrepayApi(dto.getKkoBpPrepayApi()) + .kkoBpPayresultApi(dto.getKkoBpPayResultApi()) + .kkoAtBsid(dto.getKkoAtBsid()) + .kkoAtPasswd(dto.getKkoAtPasswd()) + .kkoAtSenderKey(dto.getKkoAtSenderKey()) + .niceCdSiteCode(dto.getNiceCdSiteCode()) + .niceCdSitePw(dto.getNiceCdSitePw()) + .niceCdClientId(dto.getNiceCdClientId()) + .niceCdClientSercet(dto.getNiceCdClientSercet()) + .nvStXNaverClientId(dto.getNvStXNaverClientId()) + .nvStXNaverClientSecret(dto.getNvStXNaverClientSecret()) + .nvStOrgId(dto.getNvStOrgId()) + .nvBpPartnerId(dto.getNvBpPartnerId()) + .nvBpClientId(dto.getNvBpClientId()) + .nvBpClientSecret(dto.getNvBpClientSecret()) + .nvBpNoticeApi(dto.getNvBpNoticeApi()) + .nvBpPrepayApi(dto.getNvBpPrepayApi()) + .nvBpPayresultApi(dto.getNvBpPayresultApi()) + .nvBpPaycancelApi(dto.getNvBpPaycancelApi()) + .ktStAccessToken(dto.getKtStAccessToken()) + .ktStServiceCd(dto.getKtStServiceCd()) + .ktStServiceKey(dto.getKtStServiceKey()) + .ktStClientId(dto.getKtStClientId()) + .ktStClientSecret(dto.getKtStClientId()) + .build() + ); + + return EnsResponseVO.okBuilder().build(); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } catch (Exception e) { + return EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ERR999) + .errMsg(e.getMessage()) + .build(); + } + + } + +// @CachePut(value = CacheKey.ORGMNG, key = "#dto.orgCd") + public EnsResponseVO modify(OrgMngDTO dto) { + try { + final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + Set> list = validator.validate(dto); + if (list.size() > 0) { + return EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ERR410) + .errMsg("유효하지 않은 요청값 입니다.") + .resultInfo(list.stream() + .map(row -> String.format("%s [ %s ]", row.getMessageTemplate(), row.getPropertyPath())) + .collect(Collectors.toList())) + .build(); + } + if ("Y".equals(dto.getKkoBpCsignYn())) { + if (CmmnUtil.isEmpty(dto.getKkoBpPrepayApi()) || CmmnUtil.isEmpty(dto.getKkoBpPayResultApi())) + return EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.ERR410) + .errMsg("납부요청 위탁여부(kkoBpCsignYn)가 Y 일 경우 \"납부가능조회API\"와 \"납부결과API\"의 URL은 필수 입니다.") + .build(); + } + OrgMng orgMng = orgMngRepository.findById(dto.getOrgCd()).orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("기관코드(%s)와 일치하는 자료가 없습니다.", dto.getOrgCd()))); + + + orgMng.setOrgNm(dto.getOrgNm()); +// orgMng.setSubOrgId(null); + orgMng.setKkoMdAccessToken(dto.getKkoMdAccessToken()); + orgMng.setKkoMdContractUuid(dto.getKkoMdContractUuid()); + orgMng.setKkoBpBillerCode(dto.getKkoBpBillerCode()); + + orgMng.setKkoBpAuthorization(dto.getKkoBpAuthorization()); + orgMng.setKkoBpCsignYn(dto.getKkoBpCsignYn()); + orgMng.setKkoBpUrlApi(dto.getKkoBpUrlApi()); + orgMng.setKkoBpNoticeApi(dto.getKkoBpNoticeApi()); + orgMng.setKkoBpPrepayApi(dto.getKkoBpPrepayApi()); + orgMng.setKkoBpPayresultApi(dto.getKkoBpPayResultApi()); + + orgMng.setKkoAtBsid(dto.getKkoAtBsid()); + orgMng.setKkoAtPasswd(dto.getKkoAtPasswd()); + orgMng.setKkoAtSenderKey(dto.getKkoAtSenderKey()); + + orgMng.setNiceCdSiteCode(dto.getNiceCdSiteCode()); + orgMng.setNiceCdSitePw(dto.getNiceCdSitePw()); + orgMng.setNiceCdClientId(dto.getNiceCdClientId()); + orgMng.setNiceCdClientSercet(dto.getNiceCdClientSercet()); + + orgMng.setNvStXNaverClientId(dto.getNvStXNaverClientId()); + orgMng.setNvStXNaverClientSecret(dto.getNvStXNaverClientSecret()); + orgMng.setNvStOrgId(dto.getNvStOrgId()); + + orgMng.setKtStAccessToken(dto.getKtStAccessToken()); + orgMng.setKtStServiceCd(dto.getKtStServiceCd()); + orgMng.setKtStServiceKey(dto.getKtStServiceKey()); + orgMng.setKtStClientId(dto.getKtStClientId()); + orgMng.setKtStClientSecret(dto.getKtStClientSecret()); + + return EnsResponseVO.okBuilder().resultInfo(orgMng).build(); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + } + +// @CacheEvict(value = CacheKey.ORGMNG, key = "#orgCd") + public EnsResponseVO delete(String orgCd) { + try { + OrgMng orgMng = orgMngRepository.findById(orgCd).orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("기관코드(%s)와 일치하는 자료가 없습니다.", orgCd))); + + orgMngRepository.delete(orgMng); + + return EnsResponseVO.okBuilder().build(); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/TmpltMngService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/TmpltMngService.java new file mode 100644 index 0000000..052402a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/TmpltMngService.java @@ -0,0 +1,134 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.service; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.TmpltMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.TmpltMngRepository; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngSearchDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.service.strategy.TmpltMngCacheSupport; +import cokr.xit.ens.modules.common.ctgy.sys.mng.service.strategy.TmpltMngStrategy; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.List; +import java.util.Map; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional +public class TmpltMngService extends TmpltMngCacheSupport { + + private final OrgMngService orgMngService; + private final TmpltMngRepository tmpltMngRepository; + + private final Map mTmpltMngStrategy; +// private final RedisTemplate redisTemplate; + + public EnsResponseVO> findAllBySearchDTO(TmpltMngSearchDTO searchDTO, String dType) { + TmpltMngStrategy tmpltMngStrategy = mTmpltMngStrategy.get("tmpltMngStrategy_" + dType); + if (tmpltMngStrategy == null) + throw new EnsException(EnsErrCd.ERR405, "유효하지 않은 타입 또는 이용이 불가한 템플릿 타입 입니다."); + return EnsResponseVO.>okBuilder() + .resultInfo(tmpltMngStrategy.findAll(searchDTO)) + .build(); + + } + + public EnsResponseVO find(String orgCd, String tmpltCd, String dType) { + try { + if (CmmnUtil.isEmpty(orgCd)) + throw new EnsException(EnsErrCd.ERR410, "기관코드는 필수 입력값 입니다."); + if (CmmnUtil.isEmpty(tmpltCd)) + throw new EnsException(EnsErrCd.ERR410, "템플릿코드는 필수 입력값 입니다."); + EnsResponseVO orgMng = orgMngService.find(orgCd); + if(!EnsErrCd.OK.equals(orgMng.getErrCode())) + throw new EnsException(EnsErrCd.ERR404, String.format("기관코드(%s)가 일치하는 자료가 없습니다.", orgCd)); + TmpltMngStrategy tmpltMngStrategy = mTmpltMngStrategy.get("tmpltMngStrategy_" + dType); + if (tmpltMngStrategy == null) + throw new EnsException(EnsErrCd.ERR405, "유효하지 않은 타입 또는 이용이 불가한 템플릿 타입 입니다."); + return EnsResponseVO.okBuilder() + .resultInfo(tmpltMngStrategy.find(orgCd, tmpltCd) + .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("기관코드(%s) 및 템플릿코드(%s)가 일치하는 자료가 없습니다.", orgCd, tmpltCd))) + ) + .build(); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } catch (Throwable e) { + return EnsResponseVO.errBuilder() + .errCode(EnsErrCd.ERR999) + .errMsg(e.getMessage()) + .build(); + } + } + + + public EnsResponseVO add(Map mParam, String dType) { + try { + + mParam.put("useYn", "Y"); + TmpltMngStrategy tmpltMngStrategy = mTmpltMngStrategy.get("tmpltMngStrategy_" + dType); + if (tmpltMngStrategy == null) + throw new EnsException(EnsErrCd.ERR405, "유효하지 않은 타입 또는 이용이 불가한 템플릿 타입 입니다."); + tmpltMngStrategy.add(mParam); + + + return EnsResponseVO.okBuilder().build(); + } catch (EnsException e) { + return EnsResponseVO.errRsltBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .resultInfo(e.getData()) + .build(); + } + + } + + public EnsResponseVO modify(Map mParam, String dType) { + try { + + mParam.put("useYn", "Y"); + TmpltMngStrategy tmpltMngStrategy = mTmpltMngStrategy.get("tmpltMngStrategy_" + dType); + if (tmpltMngStrategy == null) + throw new EnsException(EnsErrCd.ERR405, "유효하지 않은 타입 또는 이용이 불가한 템플릿 타입 입니다."); + tmpltMngStrategy.modify(mParam); + + + return EnsResponseVO.okBuilder().build(); + } catch (EnsException e) { + return EnsResponseVO.errRsltBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .resultInfo(e.getData()) + .build(); + } + } + + public EnsResponseVO delete(String orgCd, String tmpltCd) { + try { + TmpltMng tmpltMng = tmpltMngRepository.findFetchByOrgCdAndTmpltCd(orgCd, tmpltCd).orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("기관코드(%s) 및 템플릿코드(%s)가 일치하는 자료가 없습니다.", orgCd, tmpltCd))); + + tmpltMng.setUseYn("N"); + + return EnsResponseVO.okBuilder().build(); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } finally { +// +// super.deleteCache(redisTemplate, orgCd, tmpltCd); + } + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/strategy/TmpltMngCacheSupport.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/strategy/TmpltMngCacheSupport.java new file mode 100644 index 0000000..18bf618 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/strategy/TmpltMngCacheSupport.java @@ -0,0 +1,72 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.service.strategy; + +import cokr.xit.ens.core.config.redis.CacheKey; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.TmpltMngRepositorySupport; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.RedisTemplate; + +import java.time.Duration; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +public abstract class TmpltMngCacheSupport { + + protected final String KEY = CacheKey.TMPLTMNG; + protected final Long KEY_EXPIRE = CacheKey.TMPLTMNG_EXP_SEC; + + + /** + * 템플릿 캐시 저장 + * + * @param redisTemplate + * @param orgCd + * @param tmpltCd + * @param tmpltMngRepositorySupport + * @return + */ + protected String pushCache(RedisTemplate redisTemplate, String orgCd, String tmpltCd, TmpltMngRepositorySupport tmpltMngRepositorySupport) { + final String hk = orgCd + ":" + tmpltCd + ":" + this.getClass().getSimpleName(); + HashOperations hashOperations = redisTemplate.opsForHash(); + if (redisTemplate.hasKey(KEY)) { + if (!hashOperations.entries(KEY).containsKey(hk)) { + Optional tmpltMngDTOByStrategy = tmpltMngRepositorySupport.findDtoByOrgCdAndTmpltCd(orgCd, tmpltCd); + if (tmpltMngDTOByStrategy.isPresent()) { + hashOperations.put(KEY, hk, tmpltMngDTOByStrategy.get()); + } + } + } else { + Optional tmpltMngDTO = tmpltMngRepositorySupport.findDtoByOrgCdAndTmpltCd(orgCd, tmpltCd); + if (tmpltMngDTO.isPresent()) { + hashOperations.put(KEY, hk, tmpltMngDTO.get()); + hashOperations.getOperations().expire(KEY, Duration.ofSeconds(KEY_EXPIRE)); + } + } + + return hk; + } + + + /** + * ID(orgCd, tmpltCd)가 일치하는 모든 템플릿 캐시 삭제 + * + * @param redisTemplate + * @param orgCd + * @param tmpltCd + */ + protected void deleteCache(RedisTemplate redisTemplate, String orgCd, String tmpltCd) { + HashOperations hashOperations = redisTemplate.opsForHash(); + if (redisTemplate.hasKey(KEY)) { + Map m = hashOperations.entries(KEY); + m.keySet().stream() + .filter(key -> key.startsWith(orgCd + ":" + tmpltCd + ":")) + .collect(Collectors.toList()) + .forEach(hk -> m.remove(hk)); + hashOperations.putAll(KEY, m); + } + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/strategy/TmpltMngStrategy.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/strategy/TmpltMngStrategy.java new file mode 100644 index 0000000..5a49b56 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/strategy/TmpltMngStrategy.java @@ -0,0 +1,15 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.service.strategy; + +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngSearchDTO; + +import java.util.List; +import java.util.Optional; + +public interface TmpltMngStrategy

{ + + List findAll(TmpltMngSearchDTO tmpltMngSearchDTO); + Optional find(String orgCd, String tmpltCd); + void add(P params); + void modify(P params); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/strategy/TmpltMngStrategyBasic.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/strategy/TmpltMngStrategyBasic.java new file mode 100644 index 0000000..7236ec7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/strategy/TmpltMngStrategyBasic.java @@ -0,0 +1,85 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.service.strategy; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.TmpltMng; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.OrgMngRepository; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.TmpltMngRepository; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngSearchDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.struct.TmpltMngMapper; +import lombok.RequiredArgsConstructor; +import org.mapstruct.factory.Mappers; +import org.springframework.stereotype.Component; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.*; +import java.util.stream.Collectors; + +@Component("tmpltMngStrategy_basic") +@RequiredArgsConstructor +public class TmpltMngStrategyBasic extends TmpltMngStrategyTemplate, TmpltMngDTO> { + private final OrgMngRepository orgMngRepository; + private final TmpltMngRepository tmpltMngRepository; + private TmpltMngMapper kkoMydocMapper = Mappers.getMapper(TmpltMngMapper.class); +// private final RedisTemplate redisTemplate; + + public List findAll(TmpltMngSearchDTO tmpltMngSearchDTO) { + return tmpltMngRepository.findAllDtoBySearchDTO(tmpltMngSearchDTO); + } + + @Override + public Optional find(String orgCd, String tmpltCd) { + return tmpltMngRepository.findDtoByOrgCdAndTmpltCd(orgCd, tmpltCd); + +// String key = super.pushCache(redisTemplate, orgCd, tmpltCd, tmpltMngRepository); +// HashOperations hashOperations = redisTemplate.opsForHash(); +// return Optional.ofNullable(hashOperations.entries(KEY).get(key)); + } + + @Override + protected TmpltMngDTO validate(Map params) { + try { + TmpltMngDTO dto = mapper.convertValue(params, TmpltMngDTO.class); + + final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + Set> list = validator.validate(dto); + if (list.size() > 0) { + throw new EnsException(EnsErrCd.ERR410, "유효하지 않은 요청 값 입니다.", list.stream() + .map(row -> String.format("%s [ %s ]", row.getMessageTemplate(), row.getPropertyPath())) + .collect(Collectors.toList()) + ); + } + return dto; + } catch (IllegalArgumentException e) { + throw new EnsException(EnsErrCd.ERR403, "유효하지 않은 파라미터 입니다. 사용가능한 파라미터는 resultInfo 를 참고하시기 바랍니다.", Arrays.stream(TmpltMngDTO.class.getDeclaredFields()).map(row -> row.getName()).collect(Collectors.toList())); + } + } + + @Override + protected void addProc(TmpltMngDTO dto) { + OrgMng orgMng = orgMngRepository.findById(dto.getOrgCd()).orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("기관코드(%s)가 일치하는 자료가 없습니다.", dto.getOrgCd()))); + tmpltMngRepository.findFetchByOrgCdAndTmpltCd(dto.getOrgCd(), dto.getTmpltCd()) + .ifPresent(tmpltMng -> { + throw new EnsException(EnsErrCd.ERR540, String.format("이미 등록된 템플릿코드[기관코드 %s 템플릿코드 %s] 입니다.", tmpltMng.getOrgMng().getOrgCd(), tmpltMng.getTmpltCd())); + }); + + TmpltMng tmpltMng = kkoMydocMapper.toEntity(dto); + tmpltMng.setOrgMng(orgMng); + tmpltMng.setRegistId("ENS_SYS"); + tmpltMngRepository.save(tmpltMng); + } + + @Override + protected void modifyProc(TmpltMngDTO tmpltMngDTO) { + TmpltMng tmpltMng = tmpltMngRepository.findFetchByOrgCdAndTmpltCd((tmpltMngDTO).getOrgCd(), (tmpltMngDTO).getTmpltCd()) + .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("기관코드(%s) 및 템플릿코드(%s)가 일치하는 자료가 없습니다.", tmpltMngDTO.getOrgCd(), tmpltMngDTO.getTmpltCd()))); + kkoMydocMapper.updateFromDto(tmpltMngDTO, tmpltMng); + tmpltMng.setUpdId("ENS_SYS"); + +// super.deleteCache(redisTemplate, tmpltMngDTO.getOrgCd(), tmpltMngDTO.getTmpltCd()); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/strategy/TmpltMngStrategyTemplate.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/strategy/TmpltMngStrategyTemplate.java new file mode 100644 index 0000000..fe08205 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/strategy/TmpltMngStrategyTemplate.java @@ -0,0 +1,28 @@ +package cokr.xit.ens.modules.common.ctgy.sys.mng.service.strategy; + +import cokr.xit.ens.core.exception.EnsException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public abstract class TmpltMngStrategyTemplate extends TmpltMngCacheSupport implements TmpltMngStrategy

{ + + protected ObjectMapper mapper = new ObjectMapper(); + + @Override + final public void add(P params) throws EnsException { + addProc(validate(params)); + } + + @Override + final public void modify(P params) throws EnsException { + modifyProc(validate(params)); + } + + protected abstract D validate(P params); + + protected abstract void addProc(D dto); + + protected abstract void modifyProc(D dto); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/util/presentation/CryptoController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/util/presentation/CryptoController.java new file mode 100644 index 0000000..ac7c8c7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/util/presentation/CryptoController.java @@ -0,0 +1,103 @@ +package cokr.xit.ens.modules.common.ctgy.sys.util.presentation; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.crypto.AES256; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Tag(name = "CryptoController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class CryptoController { + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "AES256 암호화" + , value = "{\"key\":\"0e1n2s3e4n5c6r7y8p9t256secretkey\",\"raws\":[\"8611281234567\",\"abcdefg\"]}") + }) + }) + @Operation(summary = "AES256 암호화(일괄)") + @PostMapping(value = "/sys/util/crypto/aes/enc/bulk", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity aesEncBulk(@RequestBody Map mParam) { + EnsResponseVO responseVO = null; + try { + AES256 aes256 = new AES256((String) mParam.get("key")); + List raws = (List) mParam.get("raws"); + List> resultInfo = raws.stream() + .map(s -> { + HashMap m = new HashMap<>(); + m.put(s, aes256.encrypt(s)); + return m; + }) + .collect(Collectors.toList()); + responseVO = EnsResponseVO.okBuilder() + .resultInfo(resultInfo) + .build(); + + } catch (StringIndexOutOfBoundsException e) { + responseVO = EnsResponseVO.errBuilder() + .errCode(EnsErrCd.ERR403) + .errMsg("key 값이 유효하지 않습니다.:::" + e.getMessage()) + .build(); + } + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "AES256 복호화" + , value = "{\"key\":\"0e1n2s3e4n5c6r7y8p9t256secretkey\",\"raws\":[\"BtdvjQMMvHC0Qz8gQhZm7Q==\",\"KhzYssTY2yWJhOhg801nFQ==\"]}") + }) + }) + @Operation(summary = "AES256 복호화(일괄)") + @PostMapping(value = "/sys/util/crypto/aes/dec/bulk", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity aesDecBulk(@RequestBody Map mParam) { + EnsResponseVO responseVO = null; + try { + + AES256 aes256 = new AES256((String) mParam.get("key")); + List raws = (List) mParam.get("raws"); + List> resultInfo = raws.stream() + .map(s -> { + HashMap m = new HashMap<>(); + m.put(s, aes256.decrypt(s)); + return m; + }) + .collect(Collectors.toList()); + responseVO = EnsResponseVO.okBuilder() + .resultInfo(resultInfo) + .build(); + + } catch (StringIndexOutOfBoundsException e) { + responseVO = EnsResponseVO.errBuilder() + .errCode(EnsErrCd.ERR403) + .errMsg("key 값이 유효하지 않습니다.:::" + e.getMessage()) + .build(); + } + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/util/presentation/LinkImgController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/util/presentation/LinkImgController.java new file mode 100644 index 0000000..7f5f97a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/util/presentation/LinkImgController.java @@ -0,0 +1,61 @@ +package cokr.xit.ens.modules.common.ctgy.sys.util.presentation; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +@Tag(name = "LinkImgController") +@Slf4j +@Controller +public class LinkImgController { + @Operation(summary = "링크이미지 출력") + @GetMapping(value = "/sys/util/lnk/img") + public void printImg(HttpServletRequest request, HttpServletResponse response, @RequestParam String link, @RequestParam String type) throws IOException { + + String mime = null; + if ("jpg".equals(type) || "jpeg".equals(type)) + mime = "image/jpeg"; + else if ("png".equals(type)) + mime = "image/png"; + else if ("gif".equals(type)) + mime = "image/gif"; + else + mime = "image/jpeg"; + + + try (InputStream inputStream = new URL(link).openStream(); + ServletOutputStream outputStream = response.getOutputStream();) { + + response.setHeader("Cache-Control", "no-store"); + response.setHeader("Pragma", "no-cache"); + response.setDateHeader("Expires", 0); + response.setContentType(mime); + + + int length; + byte[] buffer = new byte[1024]; + while ((length = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, length); + } + + + outputStream.flush(); + + } catch (FileNotFoundException e) { + response.getWriter().println("File is Not Found." + e.getMessage()); + } catch (IOException e) { + response.getWriter().println("I/O Error Occurred!!. " + e.getMessage()); + } + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/util/presentation/SlackController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/util/presentation/SlackController.java new file mode 100644 index 0000000..3d83ac4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/util/presentation/SlackController.java @@ -0,0 +1,135 @@ +package cokr.xit.ens.modules.common.ctgy.sys.util.presentation; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.monitor.slack.support.ChannelGetter; +import cokr.xit.ens.core.monitor.slack.support.ImageSender; +import cokr.xit.ens.core.monitor.slack.support.MessageSender; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +@Tag(name = "SlackController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class SlackController { + + @Value("${slack.token}") + private String TOKEN; + @Value("${slack.api.users}") + private String API_USERS; + @Value("${slack.api.chat}") + private String API_CHAT; + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "이미지 전송하기" + , value = "{\"email\":\"xxxxxx@gmail.com\",\"message\":\"안녕하세요. xxxx 입니다.\",\"img_url\":\"https://is5-ssl.mzstatic.com/image/thumb/Purple3/v4/d3/72/5c/d3725c8f-c642-5d69-1904-aa36e4297885/source/256x256bb.jpg\",\"pretext\":\"샘플이미지\"}" + ) + }) + }) + @Operation(summary = "Slack 이미지 전송") + @PostMapping(value = "/sys/util/slack/send/photo", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity slackSendPhoto(@RequestBody Map mParam) { + try { + ImageSender.builder() + .API_URL(API_CHAT) + .message(mParam.get("message")) + .imgUrl(mParam.get("img_url")) + .pretext(mParam.get("pretext")) + .build() + .execute(TOKEN, ChannelGetter.builder() + .TOKEN(TOKEN) + .API_URL(API_USERS) + .email(mParam.get("email")) + .build() + .execute()); + + return new ResponseEntity(EnsResponseVO.okBuilder().build(), HttpStatus.OK); + } catch (EnsException e) { + return new ResponseEntity(EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(), HttpStatus.INTERNAL_SERVER_ERROR); + } + + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "메시지 전송하기" + , value = "{\"email\":\"xxxxxx@gmail.com\",\"message\":\"안녕하세요. xxxx 입니다.\"}" + ) + }) + }) + @Operation(summary = "Slack 메시지 전송") + @PostMapping(value = "/sys/util/slack/send/msg", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity slackSendMsg(@RequestBody Map mParam) { + try { + MessageSender.builder() + .API_URL(API_CHAT) + .message(mParam.get("message")) + .build() + .execute(TOKEN, ChannelGetter.builder() + .TOKEN(TOKEN) + .API_URL(API_USERS) + .email(mParam.get("email")) + .build() + .execute()); + + + return new ResponseEntity(EnsResponseVO.okBuilder().build(), HttpStatus.OK); + } catch (EnsException e) { + return new ResponseEntity(EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(), HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + + @Parameters({ + @Parameter(in = ParameterIn.PATH, name = "email"), + }) + @Operation(summary = "Slack ID 조회") + @GetMapping(value = "/sys/util/slack/ids/{email}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> slackId(@PathVariable String email) { + try { + String slackInternalId = ChannelGetter.builder() + .TOKEN(TOKEN) + .API_URL(API_USERS) + .email(email) + .build() + .execute(); + + return new ResponseEntity>(EnsResponseVO.okBuilder().resultInfo(slackInternalId).build(), HttpStatus.OK); + } catch (EnsException e) { + return new ResponseEntity>(EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(), HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = false, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "Unchecked Exception 오류 전송 테스트" + , value = "{}") + }) + }) + @Operation(summary = "Unchecked Exception 오류 전송 테스트") + @PostMapping(value = "/sys/util/slack/error", produces = MediaType.APPLICATION_JSON_VALUE) + public void slackError() { + throw new RuntimeException("실행 오류 테스트!!!"); + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/modules/common/domain/BaseEntity.java b/src/main/java/cokr/xit/ens/modules/common/domain/BaseEntity.java new file mode 100644 index 0000000..e2457f6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/domain/BaseEntity.java @@ -0,0 +1,31 @@ +package cokr.xit.ens.modules.common.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import javax.persistence.Column; +import javax.persistence.MappedSuperclass; +import java.time.LocalDateTime; + +@Getter +@Setter +@MappedSuperclass +@SuperBuilder +@NoArgsConstructor +public abstract class BaseEntity { + + + @CreationTimestamp + @Column(name = "regist_dt", nullable = true) + private LocalDateTime registDt; + + + @UpdateTimestamp + @Column(name = "last_updt_dt", nullable = true) + private LocalDateTime lastUpdtDt; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/domain/SendMast.java b/src/main/java/cokr/xit/ens/modules/common/domain/SendMast.java new file mode 100644 index 0000000..be8dfe8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/domain/SendMast.java @@ -0,0 +1,91 @@ +package cokr.xit.ens.modules.common.domain; + +import cokr.xit.ens.modules.common.code.PostSeCd; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.persistence.*; + +@Entity +//@Data +@Getter @ToString +@SuperBuilder +@EqualsAndHashCode(callSuper = false) +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_snd_mast", schema = "", catalog = "") +public class SendMast extends SendMastBaseEntity { + + @Id +// @GeneratedValue(strategy=GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.TABLE, generator = "SendMast_Generator") + @TableGenerator(table = "ens_seq_generator", name = "SendMast_Generator" + ,pkColumnName = "seq_name", pkColumnValue = "SendMast_id" + ,initialValue = 0, allocationSize = 50) + private Long sendMastId; + + @Enumerated(EnumType.STRING) + private PostSeCd postSe; + + + +// @Column(name = "last_updt_dt", nullable = true) +// @UpdateTimestamp +// private LocalDateTime lastUpdtDt; + +// @Embedded +// @Setter +// private FieldError error; + + + +// @Column(nullable = false, length = 30) +// @Enumerated(EnumType.STRING) +// private VenderCd vender; +// + +// @Column(name = "org_cd", nullable = true, length = 20) +// private String orgCd; +// + +// @Column(nullable = true) +// private String tmpltCd; +// + +// @Column(nullable = true) +// private String postBundleTitle; +// + +// @CreationTimestamp +// private LocalDateTime acceptDt; +// + +// @Enumerated(EnumType.STRING) +// @Setter +// private StatCd statCd; +// + +// @Column(name = "send_dt", nullable = false) +// private LocalDateTime sendDt; +// + +// @Column(name = "send_cnt", columnDefinition = "integer") +// @ColumnDefault("0") +// private Integer sendCnt; +// + +// @Column(name = "read_cnt", columnDefinition = "integer") +// @ColumnDefault("0") +// @Setter +// private Integer readCnt; +// + +// @Column(name = "close_dt", nullable = false) +// private LocalDateTime closeDt; +// +// @Embedded +// @Setter +// private FieldError error; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/domain/SendMastBaseEntity.java b/src/main/java/cokr/xit/ens/modules/common/domain/SendMastBaseEntity.java new file mode 100644 index 0000000..ac376d0 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/domain/SendMastBaseEntity.java @@ -0,0 +1,72 @@ +package cokr.xit.ens.modules.common.domain; + +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.code.VenderCd; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; +import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.CreationTimestamp; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Getter +@Setter +@MappedSuperclass +@SuperBuilder +@NoArgsConstructor +public abstract class SendMastBaseEntity extends BaseEntity { + + + @Column(nullable = false, length = 30) + @Enumerated(EnumType.STRING) + private VenderCd vender; + + + @Column(name = "org_cd", nullable = true, length = 20) + private String orgCd; + + + @Column(nullable = true) + private String tmpltCd; + + + @Column(nullable = true) + private String postBundleTitle; + + + @CreationTimestamp + private LocalDateTime acceptDt; + + + @Enumerated(EnumType.STRING) + @Setter + private StatCd statCd; + + + @Column(name = "send_dt", nullable = false) + private LocalDateTime sendDt; + + + @Column(name = "send_cnt", columnDefinition = "integer") + @ColumnDefault("0") + private Integer sendCnt; + + + @Column(name = "read_cnt", columnDefinition = "integer") + @ColumnDefault("0") + @Setter + private Integer readCnt; + + + @Column(name = "close_dt", nullable = false) + private LocalDateTime closeDt; + + @Embedded + @Setter + private FieldError error; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/domain/repository/SendMastRepository.java b/src/main/java/cokr/xit/ens/modules/common/domain/repository/SendMastRepository.java new file mode 100644 index 0000000..f9588df --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/domain/repository/SendMastRepository.java @@ -0,0 +1,22 @@ +package cokr.xit.ens.modules.common.domain.repository; + +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.domain.SendMast; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.time.LocalDateTime; +import java.util.List; + +public interface SendMastRepository extends JpaRepository, SendMastRepositoryCustom{ + + List findAllBySendMastIdIn(List sendMastIds); + + List findAllByPostSeAndStatCdIn(PostSeCd postSeCd, List statCds); + + List findAllByPostSeAndStatCdInAndSendDtBefore(PostSeCd postSeCd, List statCds, LocalDateTime sendDt); + + List findAllByStatCdInAndCloseDtBefore(List statCds, LocalDateTime closeDt); + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/domain/repository/SendMastRepositoryCustom.java b/src/main/java/cokr/xit/ens/modules/common/domain/repository/SendMastRepositoryCustom.java new file mode 100644 index 0000000..f4a9b1e --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/domain/repository/SendMastRepositoryCustom.java @@ -0,0 +1,6 @@ +package cokr.xit.ens.modules.common.domain.repository; + +public interface SendMastRepositoryCustom { + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/domain/repository/SendMastRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/common/domain/repository/SendMastRepositoryImpl.java new file mode 100644 index 0000000..ab9bf2f --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/domain/repository/SendMastRepositoryImpl.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.modules.common.domain.repository; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class SendMastRepositoryImpl implements SendMastRepositoryCustom{ + + private final JPAQueryFactory query; + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/domain/support/Error.java b/src/main/java/cokr/xit/ens/modules/common/domain/support/Error.java new file mode 100644 index 0000000..1dc590f --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/domain/support/Error.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.modules.common.domain.support; + +import lombok.Data; + +@Data +public class Error { + protected String error_code; + protected String error_message; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/domain/support/FieldError.java b/src/main/java/cokr/xit/ens/modules/common/domain/support/FieldError.java new file mode 100644 index 0000000..b41e173 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/domain/support/FieldError.java @@ -0,0 +1,29 @@ +package cokr.xit.ens.modules.common.domain.support; + +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.Lob; + +@Embeddable +@Getter +@RequiredArgsConstructor +public class FieldError { + + @Column(name = "error_code", length = 30) + private String errorCode; + + @Column(name = "error_message") + @Lob + private String errorMessage; + + + @Builder(builderMethodName = "initBuilder") + public FieldError(String errorCode, String errorMessage) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/event/SendMastStatUpdateEvent.java b/src/main/java/cokr/xit/ens/modules/common/event/SendMastStatUpdateEvent.java new file mode 100644 index 0000000..d46b2fc --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/event/SendMastStatUpdateEvent.java @@ -0,0 +1,13 @@ +package cokr.xit.ens.modules.common.event; + +import lombok.Builder; +import lombok.Getter; + +/** + * 발송마스터 상태갱신 Event + */ +@Builder +@Getter +public class SendMastStatUpdateEvent { + private Long sendMastId; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/monitor/MessageByBill.java b/src/main/java/cokr/xit/ens/modules/common/monitor/MessageByBill.java new file mode 100644 index 0000000..674dbb6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/monitor/MessageByBill.java @@ -0,0 +1,49 @@ +package cokr.xit.ens.modules.common.monitor; + +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.monitor.Message; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd; +import lombok.Builder; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@Builder +public class MessageByBill implements Message { + private final String oClass; + private final BillSeCd billSeCd; + private EnsErrCd errCd; + private String message; + + + @Override + public String create() { + StringBuffer sb = new StringBuffer(); + sb.append("###############################################################") + .append(System.getProperty("line.separator")) + .append(String.format("####### ENS proccess error Info... [ -Dspring.profiles.active=%s ] #######", System.getProperty("ens.active.profile"))) + .append(System.getProperty("line.separator")) + .append("###############################################################") + .append(System.getProperty("line.separator")) + .append(String.format("%s(%s)", billSeCd.getCodeNm(), billSeCd.getCode())) + .append(System.getProperty("line.separator")) + .append("-------------------------------------------------------------------------------") + .append(System.getProperty("line.separator")) + .append("[Occurrence class]: " + oClass) + .append(System.getProperty("line.separator")) + .append("[Occurrence time]: ") + .append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))) + .append(System.getProperty("line.separator")) + .append("[ErrorCode]: ") + .append(errCd.getCode()) + .append(System.getProperty("line.separator")) + .append("[ErrorMessage]: ") + .append(errCd.getCodeNm()) + .append(System.getProperty("line.separator")) + .append("[Details]: ") + .append(System.getProperty("line.separator")) + .append(message); + + return sb.toString(); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/monitor/MessageByPhase.java b/src/main/java/cokr/xit/ens/modules/common/monitor/MessageByPhase.java new file mode 100644 index 0000000..3245a27 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/monitor/MessageByPhase.java @@ -0,0 +1,51 @@ +package cokr.xit.ens.modules.common.monitor; + +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.monitor.Message; +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.code.StatCd; +import lombok.Builder; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@Builder +public class MessageByPhase implements Message { + private final String oClass; + private final PostSeCd postSeCd; + private final StatCd statCd; + private EnsErrCd errCd; + private String message; + + + @Override + public String create() { + StringBuffer sb = new StringBuffer(); + sb.append("###############################################################") + .append(System.getProperty("line.separator")) + .append(String.format("####### ENS proccess error Info... [ -Dspring.profiles.active=%s ] #######", System.getProperty("ens.active.profile"))) + .append(System.getProperty("line.separator")) + .append("###############################################################") + .append(System.getProperty("line.separator")) + .append(String.format("%s - %s(%s)", postSeCd.getCodeNm(), statCd.getCodeNm(), statCd.getCode())) + .append(System.getProperty("line.separator")) + .append("-------------------------------------------------------------------------------") + .append(System.getProperty("line.separator")) + .append("[Occurrence class]: " + oClass) + .append(System.getProperty("line.separator")) + .append("[Occurrence time]: ") + .append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))) + .append(System.getProperty("line.separator")) + .append("[ErrorCode]: ") + .append(errCd.getCode()) + .append(System.getProperty("line.separator")) + .append("[ErrorMessage]: ") + .append(errCd.getCodeNm()) + .append(System.getProperty("line.separator")) + .append("[Details]: ") + .append(System.getProperty("line.separator")) + .append(message); + + return sb.toString(); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/example/api/ClientController.java b/src/main/java/cokr/xit/ens/modules/example/api/ClientController.java new file mode 100644 index 0000000..b09bc84 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/example/api/ClientController.java @@ -0,0 +1,110 @@ +package cokr.xit.ens.modules.example.api; + +import cokr.xit.ens.core.exception.EnsException; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.core.utils.CmmnUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@RestController +public class ClientController { + + @Value("${contract.kakao.pay.mydoc.access-token}") + private String ACCESS_TOKEN; + private String HOST = "http://localhost:18090" ; + + @PostMapping("/example/client/ok") + private ResponseEntity ok(@RequestBody Map reqDTO ) throws Exception { + if(reqDTO ==null) + reqDTO = createParam(); + + log.info(String.format("called %s.%s", getClass().getName(), new Object() {}.getClass().getEnclosingMethod().getName())); + log.info(String.format("request parameters... %s", CmmnUtil.toJsonString(reqDTO))); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON_UTF8); + ResponseEntity resp = this.sendData(HttpMethod.POST, "/example/server/ok", CmmnUtil.toJsonString(reqDTO), headers); + + String body = resp.getBody(); + log.info(String.format("body:::%s", body)); + return resp; + } + @PostMapping("/example/client/err400") + private ResponseEntity err400(@RequestBody Map reqDTO ) throws Exception { + + log.info(String.format("called %s.%s", getClass().getName(), new Object() {}.getClass().getEnclosingMethod().getName())); + log.info(String.format("request parameters... \n%s", CmmnUtil.toJsonString(reqDTO))); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON_UTF8); + ResponseEntity resp = this.sendData(HttpMethod.POST, "/example/server/err400", CmmnUtil.toJsonString(reqDTO), headers); + + return resp; + + } + @PostMapping("/example/client/err500") + private ResponseEntity err500(@RequestBody Map reqDTO ) throws Exception { + + log.info(String.format("called %s.%s", getClass().getName(), new Object() {}.getClass().getEnclosingMethod().getName())); + log.info(String.format("request parameters... %s", CmmnUtil.toJsonString(reqDTO))); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON_UTF8); + ResponseEntity resp = this.sendData(HttpMethod.POST, "/example/server/err500", CmmnUtil.toJsonString(reqDTO), headers); + + return resp; + + } + + private Map createParam() { + + Map data = new HashMap<>(); + data.put("param1", 123); + data.put("param2", "abc"); + data.put("param3", 10L); + + return data; + } + + /** + * 데이터 전송 + * @param method + * @param uri + * @param param + * @param headers + * @return + * @throws Exception + */ + @SuppressWarnings({ "unchecked" }) + protected ResponseEntity sendData(HttpMethod method, String uri, String param, HttpHeaders headers) throws Exception{ + if((this.ACCESS_TOKEN == null || this.ACCESS_TOKEN.length() < 5) && !uri.endsWith("ping")) //ping 확인 서비스를 제외한 서비스에 대해 엑세스토큰이 없을 경우.. + throw new IOException("AccessToken is null!"); + + + if(headers==null) + headers = new HttpHeaders(); + headers.set("Authorization", String.format("Bearer %s", this.ACCESS_TOKEN)); //access token 설정 + + + Map resp = CmmnUtil.callApi(method, this.HOST+uri, param, headers); + + + + if(!"OK".equals(resp.get("resCd"))) + throw new EnsException(EnsErrCd.valueOf((String) resp.get("resCd")), String.format("API 호출 실패. %s", resp.get("resMsg"))); + + return (ResponseEntity) resp.get("responseEntity"); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/example/api/ServerController.java b/src/main/java/cokr/xit/ens/modules/example/api/ServerController.java new file mode 100644 index 0000000..6775e63 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/example/api/ServerController.java @@ -0,0 +1,63 @@ +package cokr.xit.ens.modules.example.api; + +import cokr.xit.ens.core.utils.CmmnUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@RestController +public class ServerController { + + + @PostMapping("/example/server/ok") + private ResponseEntity> ok(@RequestBody Map reqDTO ) { + + log.info(String.format("called %s.%s", getClass().getName(), new Object() {}.getClass().getEnclosingMethod().getName())); + log.info(String.format("request parameters... %s", CmmnUtil.toJsonString(reqDTO))); + + ResponseEntity> resp = new ResponseEntity>(this.createBody(), HttpStatus.OK); + + return resp; + } + @PostMapping("/example/server/err400") + private ResponseEntity> err400(@RequestBody Map reqDTO ) { + + log.info(String.format("called %s.%s", getClass().getName(), new Object() {}.getClass().getEnclosingMethod().getName())); + log.info(String.format("request parameters... \n%s", CmmnUtil.toJsonString(reqDTO))); + + ResponseEntity> resp = new ResponseEntity>(this.createBody(), HttpStatus.BAD_REQUEST); + + return resp; + + } + @PostMapping("/example/server/err500") + private ResponseEntity> err500(@RequestBody Map reqDTO ) { + + log.info(String.format("called %s.%s", getClass().getName(), new Object() {}.getClass().getEnclosingMethod().getName())); + log.info(String.format("request parameters... %s", CmmnUtil.toJsonString(reqDTO))); + + ResponseEntity> resp = new ResponseEntity>(this.createBody(), HttpStatus.INTERNAL_SERVER_ERROR); + + return resp; + + } + + private Map createBody() { + Map data = new HashMap<>(); + data.put("param1", 123); + data.put("param2", "abc"); + data.put("param3", 10L); + + + Map resultMap = new HashMap(); + resultMap.put("data", data); + return resultMap; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/example/thread/Calculator.java b/src/main/java/cokr/xit/ens/modules/example/thread/Calculator.java new file mode 100644 index 0000000..f68bf28 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/example/thread/Calculator.java @@ -0,0 +1,14 @@ +package cokr.xit.ens.modules.example.thread; + + +public class Calculator{ + private int index; + + public Calculator(int index) { + this.index = index; + } + + public synchronized int getNextIndex() { + return ++index; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/example/thread/MultiThreadSample.java b/src/main/java/cokr/xit/ens/modules/example/thread/MultiThreadSample.java new file mode 100644 index 0000000..457271c --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/example/thread/MultiThreadSample.java @@ -0,0 +1,288 @@ +package cokr.xit.ens.modules.example.thread; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletionService; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorCompletionService; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MultiThreadSample { + + /** + *

메소드 설명: Multi Thread 예제
+ * @throws InterruptedException + * @throws ExecutionException void 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 30. + */ + public static void example() throws InterruptedException, ExecutionException { + + long startTme = System.currentTimeMillis(); + + Calculator calculrator = new Calculator(0); + HashSet set1 = new HashSet(); + HashSet set2 = new HashSet(); + + Callable callable1 = () -> { + for(int i=0; i<50; i++) { + set1.add(calculrator.getNextIndex()); + log.info(String.format("callable1 => %05d", i)); +// Thread.sleep(500); + } + return null; + }; + Callable callable2 = () -> { + for(int i=0; i<100; i++) { + set2.add(calculrator.getNextIndex()); + log.info(String.format("callable2 => %05d", i)); + Thread.sleep(300); + } + return null; + }; + + + ExecutorService executorService = Executors.newFixedThreadPool(3); + Future future1 = executorService.submit(callable1); + Future future2 = executorService.submit(callable2); + future1.get(); + future2.get(); + + + if(future1.isDone() && future2.isDone()) { + System.out.println(set1.size()); + System.out.println(set2.size()); + } + + executorService.shutdown(); //executor 종료 + log.info(String.format("Executor Shutdown => %s", executorService.isShutdown())); + + long endTme = System.currentTimeMillis(); + log.info(String.format("수행시간::: %s seconds...", (endTme-startTme)/1000) ); + } + + + + + + + + + /** + *
메소드 설명: Multi Thread 결과 리턴 예제
+	 * 	-.runable로 작성한 Task를 호출하여 공유객체에 결과를 return 받는다.
+	 * 
+ * @throws InterruptedException + * @throws ExecutionException void 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 30. + */ + @SuppressWarnings("unchecked") + public static void runnableExample() throws InterruptedException, ExecutionException { + + long startTme = System.currentTimeMillis(); + + + List result = new ArrayList(); + for(int i=0; i<102; i++) { + TaskDtoSample dto = new TaskDtoSample(); + dto.setId(i); + result.add(dto); + } + + //thread 갯수 설정 + int unitSize = Runtime.getRuntime().availableProcessors(); + int cntDiv = result.size()/unitSize; + int cntMod = result.size()%unitSize; + int cntThread = cntDiv+(cntMod>0?1:0); + ExecutorService executorService = Executors.newFixedThreadPool(cntThread); + + //Task 단위별 실행 + List listFuture = new ArrayList<>(); //future 목록 + for(int i=0; i taskList = null; + if(i==cntThread-1) + taskList = result.subList(i*unitSize, cntMod>0?result.size():(i+1)*unitSize); + else + taskList = result.subList(i*unitSize, (i+1)*unitSize); + + Runnable task = new TaskRunnableReturnSample(taskList, "task"+i); + listFuture.add(executorService.submit(task, result)); //task 작업 실행 + } + + //task block 처리 + Iterator it = listFuture.iterator(); + while(it.hasNext()) { + Future> future = it.next(); + List list = future.get(); + + System.out.println(String.format("결과건수=%s", list.size())); + System.out.println(String.format("결과=%s", list.toString())); + +// long endTme = System.currentTimeMillis(); +// log.info(String.format("수행시간::: %s seconds...", (endTme-startTme)/1000) ); + } + + +// for(TaskReturnDtoSample row : result) +// log.info(String.format("수행결과::: %s ", row.getResult())); + + + +// boolean isShutdown = executorService.isShutdown(); +// List listRunnable = executorService.shutdownNow() ; +// executorService.shutdown(); +// isShutdown = executorService.isShutdown(); +// boolean isTerminated = executorService.isTerminated(); +// boolean isIdle = executorService.awaitTermination(30, TimeUnit.SECONDS); + + executorService.shutdown(); //executor 종료 + log.info(String.format("Executor Shutdown => %s", executorService.isShutdown())); + + long endTme = System.currentTimeMillis(); + log.info(String.format("수행시간::: %s seconds...", (endTme-startTme)/1000) ); + } + + + + /** + *
메소드 설명: Multi Thread 예제
+	 * 	-.callable로 작성한 Task를 호출하여 Task 처리단위별 결과를 return 받는다.
+	 * 
+ * @throws InterruptedException + * @throws ExecutionException void 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 30. + */ + public static void callableExample() throws InterruptedException, ExecutionException { + + long startTme = System.currentTimeMillis(); + + + List result = new ArrayList(); + for(int i=0; i<102; i++) { + TaskDtoSample dto = new TaskDtoSample(); + dto.setId(i); + result.add(dto); + } + + //thread 갯수 설정 +// int unitSize = Runtime.getRuntime().availableProcessors(); + int unitSize = 10; + int cntDiv = result.size()/unitSize; + int cntMod = result.size()%unitSize; + int cntThread = cntDiv+(cntMod>0?1:0); + ExecutorService executorService = Executors.newFixedThreadPool(cntThread); + List listFuture = new ArrayList<>(); //future 목록 + + //Task 단위별 실행 + for(int i=0; i taskList = null; + if(i==cntThread-1) + taskList = result.subList(i*unitSize, cntMod>0?result.size():(i+1)*unitSize); + else + taskList = result.subList(i*unitSize, (i+1)*unitSize); + + Callable> task = new TaskCallableExample(taskList); + listFuture.add(executorService.submit(task)); //task 작업 실행 + } + + //task block 처리 + Iterator it = listFuture.iterator(); + while(it.hasNext()) { + Future> future = it.next(); + List list = future.get(); + System.out.println(String.format("결과건수=%s", list.size())); + System.out.println(String.format("결과=%s", list.toString())); + } + + executorService.shutdown(); //executor 종료 + log.info(String.format("Executor Shutdown => %s", executorService.isShutdown())); + + long endTme = System.currentTimeMillis(); + log.info(String.format("수행시간::: %s seconds...", (endTme-startTme)/1000) ); + } + + /** + *
메소드 설명: Multi Thread 예제
+	 * 	-.CompletionService로 Task를 호출 한다.
+	 * 
+ * @throws InterruptedException + * @throws ExecutionException void 요청처리 후 응답객체 + * @author: 박민규 + * @date: 2021. 8. 30. + */ + public static void completionServiceExample() throws InterruptedException, ExecutionException { + + long startTme = System.currentTimeMillis(); + + + List result = new ArrayList(); + for(int i=0; i<102; i++) { + TaskDtoSample dto = new TaskDtoSample(); + dto.setId(i); + result.add(dto); + } + + //thread 갯수 설정 +// int unitSize = Runtime.getRuntime().availableProcessors(); + int unitSize = 10; + int cntDiv = result.size()/unitSize; + int cntMod = result.size()%unitSize; + int cntThread = cntDiv+(cntMod>0?1:0); + ExecutorService executorService = Executors.newFixedThreadPool(cntThread); + CompletionService completionService = new ExecutorCompletionService(executorService); + List listFuture = new ArrayList<>(); //future 목록 + + //Task 단위별 실행 + for(int i=0; i taskList = null; + if(i==cntThread-1) + taskList = result.subList(i*unitSize, cntMod>0?result.size():(i+1)*unitSize); + else + taskList = result.subList(i*unitSize, (i+1)*unitSize); + + Callable> task = new TaskCallableExample(taskList); + listFuture.add(completionService.submit(task)); //task 작업 실행 + } + + //task block 처리-Case1. 순차 처리 +// Iterator it = listFuture.iterator(); +// while(it.hasNext()) { +// Future> future = it.next(); +// List list = future.get(); +// System.out.println(String.format("결과건수=%s", list.size())); +// System.out.println(String.format("결과=%s", list.toString())); +// } + //task block 처리-Case2. 비순차 처리 + int complete = 0; + while (true) { + if(complete == cntThread) + break; +// Future future = completionService.poll(); +// Future future = completionService.poll(30, TimeUnit.SECONDS); + Future future = completionService.take(); + if(future.isDone()) + complete++; + List list = (List) future.get(); + System.out.println(String.format("결과건수=%s", list.size())); + System.out.println(String.format("결과=%s", list.toString())); + } + + executorService.shutdown(); //executor 종료 + log.info(String.format("Executor Shutdown => %s", executorService.isShutdown())); + + + long endTme = System.currentTimeMillis(); + log.info(String.format("수행시간::: %s seconds...", (endTme-startTme)/1000) ); + } +} + diff --git a/src/main/java/cokr/xit/ens/modules/example/thread/ResultByRunnableExample.java b/src/main/java/cokr/xit/ens/modules/example/thread/ResultByRunnableExample.java new file mode 100644 index 0000000..9367a9d --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/example/thread/ResultByRunnableExample.java @@ -0,0 +1,73 @@ +package cokr.xit.ens.modules.example.thread; + +import java.util.concurrent.ExecutorService; + +import java.util.concurrent.Executors; + +import java.util.concurrent.Future; + + + +public class ResultByRunnableExample { + + public static void main(String[] args) { + + ExecutorService executorService = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() ); + System.out.println("[작업 처리 요청]"); + + class Task implements Runnable { + Result result; + Task(Result result) { + this.result = result; + } + @Override + public void run() { + int sum = 0; + for(int i=1; i<=10; i++) { + sum += i; + } + result.addValue(sum); + } + + } + + + Result result = new Result(); + Runnable task1 = new Task(result); + Runnable task2 = new Task(result); + Future future1 = executorService.submit(task1, result); + Future future2 = executorService.submit(task2, result); + + + try { + result = future1.get(); + result = future2.get(); + System.out.println("[처리 결과] " + result.accumValue); + System.out.println("[작업 처리 완료]"); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("[실행 예외 발생함] " + e.getMessage()); + } + + + executorService.shutdown(); + + } + +} + + + +class Result { + + int accumValue; + + synchronized void addValue(int value) { + + accumValue += value; + +} + + + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/modules/example/thread/TaskCallableExample.java b/src/main/java/cokr/xit/ens/modules/example/thread/TaskCallableExample.java new file mode 100644 index 0000000..c7845cb --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/example/thread/TaskCallableExample.java @@ -0,0 +1,35 @@ +package cokr.xit.ens.modules.example.thread; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TaskCallableExample implements Callable> { + + private List trgetList; + + TaskCallableExample(List trgetList){ + this.trgetList = trgetList; + } + + @Override + public List call() throws Exception { + List rsList = new ArrayList(); + for(TaskDtoSample row : trgetList) { +// if(row.getId()>99&&row.getId()<102) +// throw new RuntimeException("Exception"); + row.setResult(String.format("getId => %05d. current thread name is\"%s\". ", row.getId(), Thread.currentThread().getName())); + rsList.add(row); + log.info(String.format("getId => %05d. current thread name is \"%s\". ", row.getId(), Thread.currentThread().getName())); + Thread.sleep(500); + } + + log.info(String.format("%s ID is \"%s\"", Thread.currentThread().getName(), Thread.currentThread().getId())); + + return rsList; + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/example/thread/TaskDtoSample.java b/src/main/java/cokr/xit/ens/modules/example/thread/TaskDtoSample.java new file mode 100644 index 0000000..f33f11f --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/example/thread/TaskDtoSample.java @@ -0,0 +1,11 @@ +package cokr.xit.ens.modules.example.thread; + +import lombok.Data; + +@Data +public class TaskDtoSample { + + private int id; + + private String result; +} diff --git a/src/main/java/cokr/xit/ens/modules/example/thread/TaskRunnableReturnSample.java b/src/main/java/cokr/xit/ens/modules/example/thread/TaskRunnableReturnSample.java new file mode 100644 index 0000000..002856a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/example/thread/TaskRunnableReturnSample.java @@ -0,0 +1,43 @@ +package cokr.xit.ens.modules.example.thread; + +import java.util.List; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TaskRunnableReturnSample implements Runnable{ + + List trgetList; + List result; + String taskNm; + + TaskRunnableReturnSample(List result, String taskNm){ + this.result = result; + this.taskNm = taskNm; + } + @Override + public void run() { + int scnd = 1000; +// int scnd = 500; +// if(taskNm.endsWith("2")) +// scnd = 100; + for(TaskDtoSample row : result) { + try { +// if(row.getId()>99&&row.getId()<102) +// throw new RuntimeException("Exception"); + row.setResult(String.format("%s => %05d", taskNm, row.getId())); + log.info(String.format("%s => %05d", taskNm, row.getId())); + } catch (Exception e) { + log.error(String.format("task id is %s trget Id \"%s\". error 발생:::%s", taskNm, row.getId(), e.getMessage())); + } + + try { + Thread.sleep(scnd); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + + }; +} diff --git a/src/main/java/cokr/xit/ens/modules/example/thread/TaskRunnableSample.java b/src/main/java/cokr/xit/ens/modules/example/thread/TaskRunnableSample.java new file mode 100644 index 0000000..3d69c8a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/example/thread/TaskRunnableSample.java @@ -0,0 +1,33 @@ +package cokr.xit.ens.modules.example.thread; + +import java.util.List; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TaskRunnableSample implements Runnable{ + + List result; + String taskNm; + + TaskRunnableSample(List result, String taskNm){ + this.result = result; + this.taskNm = taskNm; + } + @Override + public void run() { + int scnd = 500; + if(taskNm.endsWith("2")) + scnd = 100; + for(int i=0; i<50; i++) { + result.add(String.format("%s => %05d", taskNm, i)); + log.info(String.format("%s => %05d", taskNm, i)); + try { + Thread.sleep(scnd); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }; + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/code/AlimTalkSendTypeCd.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/code/AlimTalkSendTypeCd.java new file mode 100644 index 0000000..776c47a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/code/AlimTalkSendTypeCd.java @@ -0,0 +1,44 @@ +package cokr.xit.ens.modules.kkoalimtalk.code; + +import cokr.xit.ens.core.code.CodeMapperType; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * 발송 메시지 타입 구분 + */ +@RequiredArgsConstructor +public enum AlimTalkSendTypeCd implements CodeMapperType { + + + UNKNOWN("알수없음") + ,K("카카오") + ,S("SMS") + ,M("MMS") + ,U("MMS URL") + ,E("문자를 발송 하엿으나 결과를 수신하지 못함") + ; + + @Getter + private final String codeNm; + + @Override + public String getCode() { + return this.name(); + } + + + public static AlimTalkSendTypeCd valueOfEnum(String statCd){ + if(statCd == null) + return AlimTalkSendTypeCd.UNKNOWN; + + AlimTalkSendTypeCd BizTalkSendTypeCd = null; + try { + BizTalkSendTypeCd = BizTalkSendTypeCd.valueOf(statCd); + } catch (IllegalArgumentException e){ + BizTalkSendTypeCd = BizTalkSendTypeCd.UNKNOWN; + } + return BizTalkSendTypeCd; + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/code/AlimtalkResultCd.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/code/AlimtalkResultCd.java new file mode 100644 index 0000000..c63fb4c --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/code/AlimtalkResultCd.java @@ -0,0 +1,114 @@ +package cokr.xit.ens.modules.kkoalimtalk.code; + +import cokr.xit.ens.modules.common.code.IntgrnDtlStatCd; +import cokr.xit.ens.modules.common.code.IntgrnDtlStatMapperType; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum AlimtalkResultCd implements IntgrnDtlStatMapperType { + UNKNOWN("알수없음", IntgrnDtlStatCd.UNKNOWN) + , NULL("입력값 없음", IntgrnDtlStatCd.ACPT_CMPLT) + , SENT_FAIL("송신실패", IntgrnDtlStatCd.FAIL) + + + + ,RQ_1000("비즈톡 G/W 접수 성공", IntgrnDtlStatCd.ACPT_OK) + ,RQ_1001("문자 재처리 포함 카카오 메시지 발송 시 문자 제한건수 초과로 인해 카카오 메시지만 접수 성공", IntgrnDtlStatCd.FAIL) + ,RQ_B199("인증 실패(Token 정보 인증 실패", IntgrnDtlStatCd.FAIL) + ,RQ_B201("알 수 없는 벤더 코드 오류", IntgrnDtlStatCd.FAIL) + ,RQ_B202("알 수 없는 메시지 코드 오류", IntgrnDtlStatCd.FAIL) + ,RQ_B203("메시지 문법 오류(JSON형식 오류)", IntgrnDtlStatCd.FAIL) + ,RQ_B206("빈 메시지 리스트 오류", IntgrnDtlStatCd.FAIL) + ,RQ_B207("메시지 리스트 최대 요청 개수 초과", IntgrnDtlStatCd.FAIL) + ,RQ_B208("내부 오류", IntgrnDtlStatCd.FAIL) + ,RQ_B209("등록되지 않은 테스트 번호로 테스트 발송 요청", IntgrnDtlStatCd.FAIL) + ,RQ_B210("bsid, passwd 불일치", IntgrnDtlStatCd.FAIL) + ,RQ_B211("등록되지 않은 bsid", IntgrnDtlStatCd.FAIL) + ,RQ_B212("등록되지 않은 회신번호", IntgrnDtlStatCd.FAIL) + ,RQ_B213("비활성화 상태의 BSID", IntgrnDtlStatCd.FAIL) + ,RQ_B214("파일 업로드 오류", IntgrnDtlStatCd.FAIL) + ,RQ_B300("내부 오류", IntgrnDtlStatCd.FAIL) + ,RQ_B301("메시지 여신건수 초과", IntgrnDtlStatCd.FAIL) + ,RQ_B400("수신 번호 차단 리스트에 추가된 사용자", IntgrnDtlStatCd.FAIL) + ,RQ_B401("이미 등록되어있는 차단 번호", IntgrnDtlStatCd.FAIL) + ,RQ_B402("등록되어있지 않은 차단 번호", IntgrnDtlStatCd.FAIL) + ,RQ_B403("등록된 차단 번호가 존재하지 않음", IntgrnDtlStatCd.FAIL) + + + ,RS_B800("Http 요청 오류, JSON Parameter 오류 등 벤더사로 발송 요청 시 발생 한 오류", IntgrnDtlStatCd.FAIL) + ,RS_B801("벤더사 오류", IntgrnDtlStatCd.FAIL) + ,RS_1000("전송 성공", IntgrnDtlStatCd.SENT) + ,RS_1001("Request Body가 Json형식이 아님", IntgrnDtlStatCd.FAIL) + ,RS_1002("허브 파트너 키가 유효하지 않음", IntgrnDtlStatCd.FAIL) + ,RS_1003("발신 프로필 키가 유효하지 않음", IntgrnDtlStatCd.FAIL) + ,RS_1004("Request Body(Json)에서 name을 찾을 수 없음", IntgrnDtlStatCd.FAIL) + ,RS_1006("삭제된 발신프로필.(메시지 사업 담당자에게 문의)", IntgrnDtlStatCd.FAIL) + ,RS_1007("차단 상태의 발신프로필.(메시지 사업 담당자에게 문의)", IntgrnDtlStatCd.FAIL) + ,RS_1011("계약정보를 찾을 수 없음.(메시지 사업 담당자에게 문의)", IntgrnDtlStatCd.FAIL) + ,RS_1012("잘못된 형식의 유저키 요청", IntgrnDtlStatCd.FAIL) + ,RS_1013("유효하지 않은 app연결", IntgrnDtlStatCd.FAIL) + ,RS_1014("유효하지 않은 사업자번호", IntgrnDtlStatCd.FAIL) + ,RS_1015("유효하지 않은 app user id 요청", IntgrnDtlStatCd.FAIL) + ,RS_1020("전화번호 또는 유효하지 않은 app user id", IntgrnDtlStatCd.FAIL) + ,RS_1021("차단 상태의 카카오톡 채널(카카오톡 채널 운영툴에서 확인)", IntgrnDtlStatCd.FAIL) + ,RS_1022("닫힘 상태의 카카오톡 채널(카카오톡 채널 운영툴에서 확인)", IntgrnDtlStatCd.FAIL) + ,RS_1023("삭제된 카카오톡 채널(카카오톡 채널 운영툴에서 확인)", IntgrnDtlStatCd.FAIL) + ,RS_1024("삭제대기 상태의 카카오톡 채널(카카오톡 채널 운영툴에서 확인", IntgrnDtlStatCd.FAIL) + ,RS_1025("메시지차단 상태의 카카오톡 채널(카카오톡 채널 운영툴에서 확인)", IntgrnDtlStatCd.FAIL) + ,RS_1030("잘못된 파라메터 요청", IntgrnDtlStatCd.FAIL) + ,RS_2003("메시지 전송 실패(테스트 서버에서 친구관계가 아닌 경우)", IntgrnDtlStatCd.FAIL) + ,RS_2004("템플릿 일치 확인시 오류 발생(내부 오류 발생)", IntgrnDtlStatCd.FAIL) + ,RS_2006("시리얼 넘버 형식 불일치", IntgrnDtlStatCd.FAIL) + ,RS_3000("예기치 않은 오류 발생", IntgrnDtlStatCd.FAIL) + ,RS_3005("메시지를 발송했으나 수신확인 안됨(성공불확실)-서버에는 암호화 되어 보관되며 3일 이내 수신 가능", IntgrnDtlStatCd.FAIL) + ,RS_3006("내부 시스템 오류로 메시지 전송 실패", IntgrnDtlStatCd.FAIL) + ,RS_3008("전화번호 오류", IntgrnDtlStatCd.FAIL) + ,RS_3010("Json파싱 오류", IntgrnDtlStatCd.FAIL) + ,RS_3011("메시지가 존재하지 않음", IntgrnDtlStatCd.FAIL) + ,RS_3012("메시지 일련번호가 중복됨-메시지 일련번호는 CS처리를 위해 고유한 값이 부여되어야 함.", IntgrnDtlStatCd.FAIL) + ,RS_3013("메시지가 비어 있음", IntgrnDtlStatCd.FAIL) + ,RS_3014("메시지 길이 제한 오류(템플릿별 제한 길이 또는 1000자 초과)", IntgrnDtlStatCd.FAIL) + ,RS_3015("템플릿을 찾을 수 없음", IntgrnDtlStatCd.FAIL) + ,RS_3016("메시지 내용이 템플릿과 일치하지 않음/버튼 템플릿 사용시 버튼명 또는 버튼 내용이 템플릿 등록시 사용한 값과 다를 경우", IntgrnDtlStatCd.FAIL) + ,RS_3018("메시지를 전송할 수 없음(카카오톡을 사용하지 않는 사용자/168시간 내에 카카오톡 사용이력이 없는 사용자/알림톡 차단을 선택한 사용자/친구톡의 경우 친구가 아닌경우/카카오톡 하위버전 사용자(android 6.0.0 미만/ios 6.0.0 미만)", IntgrnDtlStatCd.FAIL) + ,RS_3022("메시지 발송 가능한 시간이 아님(친구톡/마케팅 메시지는 20시50분 부터 익일 08시까지 발송 제한)", IntgrnDtlStatCd.FAIL) + ,RS_3024("메시지에 포함된 이미지를 전송할 수 없음", IntgrnDtlStatCd.FAIL) + ,RS_3025("변수 글자수 제한 초과", IntgrnDtlStatCd.FAIL) + ,RS_3026("상담/봇 전환버튼 extra, event 글자수 제한 초과", IntgrnDtlStatCd.FAIL) + ,RS_3027("버튼내용 또는 바로연결 버튼이 등록한 템플릿과 일치 하지 않음", IntgrnDtlStatCd.FAIL) + ,RS_3028("메시지 강조 표기 타이틀이 템플릿과 일치하지 않음", IntgrnDtlStatCd.FAIL) + ,RS_3029("메시지 강조 표기 타이틀 길이 제한 초과(50자)", IntgrnDtlStatCd.FAIL) + ,RS_3030("등록된 템플릿과 일치하지 않는 메시지 타입", IntgrnDtlStatCd.FAIL) + ,RS_4000("메시지 전송 결과를 찾을 수 없음", IntgrnDtlStatCd.FAIL) + ,RS_4001("알 수 없는 메시지 상태", IntgrnDtlStatCd.FAIL) + ,RS_ME09("사용자에게 메시지를 발송했으나 수신여부 불투명", IntgrnDtlStatCd.FAIL) + ,RS_9999("알 수 없는 오류", IntgrnDtlStatCd.FAIL); + + + @Getter + private final String codeNm; + @Getter + private final IntgrnDtlStatCd intgrnDtlStatCd; + + @Override + public String getCode() { + return this.name(); + } + + + public static AlimtalkResultCd valueOfEnum(String statCd){ + if(statCd == null) + return AlimtalkResultCd.UNKNOWN; + + AlimtalkResultCd KkoAlimtalkRsltCd = null; + try { + KkoAlimtalkRsltCd = KkoAlimtalkRsltCd.valueOf(statCd); + } catch (IllegalArgumentException e){ + KkoAlimtalkRsltCd = KkoAlimtalkRsltCd.UNKNOWN; + } + return KkoAlimtalkRsltCd; + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/SendDetailKkoAlimtalk.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/SendDetailKkoAlimtalk.java new file mode 100644 index 0000000..acf87c7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/SendDetailKkoAlimtalk.java @@ -0,0 +1,185 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.Bill; +import cokr.xit.ens.modules.common.domain.BaseEntity; +import cokr.xit.ens.modules.common.domain.SendMast; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import cokr.xit.ens.modules.kkoalimtalk.code.AlimTalkSendTypeCd; +import cokr.xit.ens.modules.kkoalimtalk.code.AlimtalkResultCd; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; +import org.hibernate.annotations.ColumnDefault; + +import javax.persistence.*; + +@Entity +@Getter +@ToString +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_snd_dtl_kko_at", schema = "", catalog = "", indexes = { + @Index(name = "idx_kkoat_api_doc_uk", columnList = "msg_idx"), +// @Index(name = "idx_kkoat_bill_uid", columnList = "mk_bill_uid"), +}) +public class SendDetailKkoAlimtalk extends BaseEntity { + @Id +// @GeneratedValue(strategy=GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.TABLE, generator = "SendDetailKkoAlimtalk_Generator") + @TableGenerator(table = "ens_seq_generator", name = "SendDetailKkoAlimtalk_Generator" + , pkColumnName = "seq_name", pkColumnValue = "SendDetailKkoAlimtalk_id" + , initialValue = 0, allocationSize = 200) + + private Long sendDetailId; + + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "send_mast_id") + + private SendMast sendMast; + + + + @Column(name = "msg_idx", nullable = true) + private String msgIdx; + + + @Column(name = "country_code", nullable = false) + @ColumnDefault("'82'") + private String countryCode; + + + @Column(name = "recipient", nullable = true) + @Setter + private String recipient; + + + @Column(name = "sender_key", nullable = true) + private String senderKey; + + + @Column(name = "app_user_id", nullable = true) + private String appUserId; + + + @Column(name = "org_code", nullable = true) + private String orgCode; + + + @Column(name = "message", nullable = true) + @ColumnDefault("'Waiting for Make Stage'") + @Lob + @Setter + private String message; + + + @Column(name = "tmplt_code", nullable = false) + private String tmpltCode; + + + @Column(name = "title", nullable = true) + private String title; + + + @Column(name = "res_method", nullable = false) + @ColumnDefault("'PUSH'") + private String resMethod; + + +// @Column(name = "price", nullable = true) +// private int price; +// + +// @Column(name = "currency_type", nullable = true, length = 3) +// private String currencyType; + + + @Column(name = "attach", nullable = true, length = 1000) + @Setter + private String attach; + + + @Column(name = "supplement", nullable = true) + private String supplement; + + + @Column(name = "message_type", nullable = true) + private String messageType; + + + @Column(name = "use_failback", nullable = true) + private String useFailback; + + + @Column(name = "mmsAttach", nullable = true) + private String mmsAttach; + + + + @Column(name = "mk_bill_use_yn", nullable = true, length = 1) + private String mkBillUseYn; + +// @Column(name = "mk_bill_uid", nullable = true, length = 45) +// private String mkBillUid; + + @JoinColumn(name = "bill_uid", referencedColumnName = "bill_uid") + @OneToOne(fetch = FetchType.LAZY) + private Bill bill; + + @Column(name = "req_msg_idx", nullable = true) + @Setter + private String reqMsgIdx; + + @Column(name = "mk_tmplt_msg_json_data", nullable = true, length = 3000) + private String mkTmpltMsgJsonData; + + @Column(name = "mk_name", nullable = true) + private String mkName; + + @Column(name = "mk_birthday", nullable = true) + private String mkBirthday; + + @Column(name = "mk_sid", nullable = true) + private String mkSid; + + @Column(name = "mk_gender", nullable = true) + private String mkGender; + + @Column(name = "mk_mbl_json_data", nullable = true) + @Lob + private String mkMblJsonData; + + @Column(name = "mk_pay_bill_json_data", nullable = true) + @Lob + private String mkPayBillJsonData; + + + + @Column(name = "kko_doc_sent_dt", nullable = true, length = 14) + @Setter + private String kkoDocSentDt; + + @Column(name = "kko_send_type", nullable = true) + @Setter + @Enumerated(EnumType.STRING) + private AlimTalkSendTypeCd kkoSendType; + + @Column(name = "kko_result_cd", nullable = false) + @Setter + @Enumerated(EnumType.STRING) + private AlimtalkResultCd kkoResultCd; + + @Column(name = "kko_request_dt", nullable = true) + @Setter + private String kkoRequestDt; + + @Column(name = "kko_received_dt", nullable = true) + @Setter + private String kkoReceivedDt; + + + @Embedded + @Setter + private FieldError error; +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/SendDetailKkoAlimtalkReqHist.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/SendDetailKkoAlimtalkReqHist.java new file mode 100644 index 0000000..88543fa --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/SendDetailKkoAlimtalkReqHist.java @@ -0,0 +1,73 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain; + +import cokr.xit.ens.modules.common.domain.support.FieldError; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.annotations.CreationTimestamp; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_snd_dtl_kko_at_req_his", schema = "", catalog = "", indexes = { + @Index(name = "idx_snd_dtl_kko_at_req_his_01", columnList = "regist_dt") +}) +public class SendDetailKkoAlimtalkReqHist { + + @Id +// @GeneratedValue(strategy=GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.TABLE, generator = "SendDetailKkoAlimtalkReqHist_Generator") + @TableGenerator(table = "ens_seq_generator", name = "SendDetailKkoAlimtalkReqHist_Generator" + , pkColumnName = "seq_name", pkColumnValue = "SendDetailKkoAlimtalkReqHist_id" + , initialValue = 0, allocationSize = 200) + + private Long id; + +// @ManyToOne(fetch = FetchType.LAZY) +// @JoinColumn(name = "send_mast_id") + +// private SendMast sendMast; + + + @Column(name = "send_detail_id", nullable = true) + private Long sendDetailId; + + + @Column(nullable = false) + @Lob + private String sendRawMsg; + + + @Column(nullable = false) + private String btToken; + + + @Column(nullable = true) + private String responseCode; + + + @Column(nullable = true, length = 1000) + private String msg; + + + @Column(nullable = true) + private String reqMsgIdx; + + + @Column(nullable = true) + private String msgResponseCode; + + @CreationTimestamp + @Column(name = "regist_dt", nullable = true) + private LocalDateTime registDt; + + @Embedded + @Setter + private FieldError error; + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/SendDetailKkoAlimtalkRsltHist.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/SendDetailKkoAlimtalkRsltHist.java new file mode 100644 index 0000000..31cce2f --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/SendDetailKkoAlimtalkRsltHist.java @@ -0,0 +1,90 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain; + +import cokr.xit.ens.modules.common.domain.support.FieldError; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.hibernate.annotations.CreationTimestamp; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "ens_snd_dtl_kko_at_rslt_his", schema = "", catalog = "", indexes = { + @Index(name = "idx_snd_dtl_kko_at_rslt_his_01", columnList = "regist_dt") +}) +public class SendDetailKkoAlimtalkRsltHist { + + @Id +// @GeneratedValue(strategy=GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.TABLE, generator = "SendDetailKkoAlimtalkRsltHist_Generator") + @TableGenerator(table = "ens_seq_generator", name = "SendDetailKkoAlimtalkRsltHist_Generator" + , pkColumnName = "seq_name", pkColumnValue = "SendDetailKkoAlimtalkRsltHist_id" + , initialValue = 0, allocationSize = 200) + + private Long id; + +// @ManyToOne(fetch = FetchType.LAZY) +// @JoinColumn(name = "send_mast_id") + +// private SendMast sendMast; + + + @Column(nullable = true) + private String pk; + + + @Column(nullable = true) + private String responseCode; + + + @Column(nullable = true) + private String msg; + + + @Column(nullable = true) +// private String uid; + private String uuid; + + + @Column(nullable = true) + private String reqMsgIdx; + + + @Column(nullable = true) + private String resultCode; + + + @Column(nullable = true) + private String requestAt; + + + @Column(nullable = true) + private String receivedAt; + + + @Column(nullable = true) + private String bsid; + + + @Column(nullable = true) + private String sendType; + + + @Column(nullable = true) + private String recipientOrder; + + + @CreationTimestamp + @Column(name = "regist_dt", nullable = true) + private LocalDateTime registDt; + + @Embedded + @Setter + private FieldError error; + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/TmpltMngKkoAlimtalk.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/TmpltMngKkoAlimtalk.java new file mode 100644 index 0000000..c73972a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/TmpltMngKkoAlimtalk.java @@ -0,0 +1,39 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain; + +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.TmpltMng; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import javax.persistence.Column; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Getter +@ToString +@SuperBuilder +@EqualsAndHashCode +@NoArgsConstructor +@Table(name = "ens_tmplt_mng_kko_at", schema = "", catalog = "") +@DiscriminatorValue("kkoat") +public class TmpltMngKkoAlimtalk extends TmpltMng { + + + @Column(name = "pryMessage", nullable = true, length = 2000) + @Setter + private String pryMessage; + + @Setter + @Column(name = "biztalk_org_cd", nullable = true, length = 20) + + private String biztalkOrgCd; + + @Setter + @Column(name = "biztalk_tmplt_code", nullable = false, length = 30) + + private String biztalkTmpltCode; + + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRepository.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRepository.java new file mode 100644 index 0000000..98c4417 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRepository.java @@ -0,0 +1,13 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain.repository; + +import cokr.xit.ens.modules.kkoalimtalk.domain.SendDetailKkoAlimtalk; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface SendDetailKkoAlimtalkRepository extends JpaRepository, SendDetailKkoAlimtalkRepositoryCustom { + + Optional findByMsgIdx(String msgIdx); + + Optional findByReqMsgIdx(String reqMsgIdx); +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRepositoryCustom.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRepositoryCustom.java new file mode 100644 index 0000000..af01d22 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRepositoryCustom.java @@ -0,0 +1,16 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain.repository; + +import cokr.xit.ens.modules.common.code.PostSeCd; +import cokr.xit.ens.modules.common.code.StatCd; +import cokr.xit.ens.modules.common.domain.SendMast; +import cokr.xit.ens.modules.common.biztmplt.SendDetailRepositorySupport; +import cokr.xit.ens.modules.kkoalimtalk.domain.SendDetailKkoAlimtalk; + +import java.util.List; + +public interface SendDetailKkoAlimtalkRepositoryCustom extends SendDetailRepositorySupport { + + List findAllFetchBySendMastId(Long sendMastId); +// List findAllSendMastByMsgIdxInPostSeAndStatCdIn(List msgIdxs, PostSeCd postSeCd, List statCds); + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRepositoryImpl.java new file mode 100644 index 0000000..9be0c54 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRepositoryImpl.java @@ -0,0 +1,60 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain.repository; + +import cokr.xit.ens.modules.kkoalimtalk.domain.SendDetailKkoAlimtalk; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.util.List; + +import static cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.QBill.bill; +import static cokr.xit.ens.modules.common.domain.QSendMast.sendMast; +import static cokr.xit.ens.modules.kkoalimtalk.domain.QSendDetailKkoAlimtalk.sendDetailKkoAlimtalk; + +@RequiredArgsConstructor +public class SendDetailKkoAlimtalkRepositoryImpl implements SendDetailKkoAlimtalkRepositoryCustom { + + private final JPAQueryFactory query; + + + @Override + public List findAllFetchBySendMastId(Long sendMastId) { + return query.selectFrom(sendDetailKkoAlimtalk) + .innerJoin(sendDetailKkoAlimtalk.sendMast, sendMast).fetchJoin() +// .leftJoin(sendDetailKkoAlimtalk.kkoBillMast, kkoBillMast) + .leftJoin(sendDetailKkoAlimtalk.bill, bill).fetchJoin() + .where(sendDetailKkoAlimtalk.sendMast.sendMastId.eq(sendMastId)) + .fetch() + ; + } +// +// @Override +// public List findAllFetchBySendMastIdAndMkBillUseYAndUrlIsNull(Long sendMastId, boolean urlIsNull) { +// return query.selectFrom(sendDetailKkoAlimtalk) +// .innerJoin(sendDetailKkoAlimtalk.sendMast, sendMast) +// .fetchJoin() +// .leftJoin(sendDetailKkoAlimtalk.kkoBillMast, kkoBillMast) +// .fetchJoin() +// .where(sendDetailKkoAlimtalk.sendMast.sendMastId.eq(sendMastId) +// .and(sendDetailKkoAlimtalk.mkBillUseYn.eq("Y")) +// .and(urlIsNull ? sendDetailKkoAlimtalk.kkoBillMast.url.isNull() : sendDetailKkoAlimtalk.kkoBillMast.url.isNotNull()) +// ) +// .fetch() +// ; +// } +// +// @Override +// public List findAllSendMastByMsgIdxInPostSeAndStatCdIn(List msgIdxs, PostSeCd postSeCd, List statCds) { +// return query.select(sendMast) +// .from(sendDetailKkoAlimtalk) +// .innerJoin(sendDetailKkoAlimtalk.sendMast, sendMast) +// .where(sendDetailKkoAlimtalk.msgIdx.in(msgIdxs) +// .and(sendMast.postSe.eq(postSeCd)) +// .and(sendMast.statCd.in(statCds)) +// ) +// .groupBy(sendMast) +// .fetch() +// ; +// } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkReqHistRepository.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkReqHistRepository.java new file mode 100644 index 0000000..dfe27a8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkReqHistRepository.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain.repository; + +import cokr.xit.ens.modules.common.biztmplt.CleanRepositorySupport; +import cokr.xit.ens.modules.kkoalimtalk.domain.SendDetailKkoAlimtalkReqHist; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SendDetailKkoAlimtalkReqHistRepository extends JpaRepository, CleanRepositorySupport { + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkReqHistRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkReqHistRepositoryImpl.java new file mode 100644 index 0000000..39d66ea --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkReqHistRepositoryImpl.java @@ -0,0 +1,18 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain.repository; + +import cokr.xit.ens.modules.common.biztmplt.CleanRepositorySupport; +import cokr.xit.ens.modules.common.code.UseNativeQuery; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +public class SendDetailKkoAlimtalkReqHistRepositoryImpl implements CleanRepositorySupport { + @PersistenceContext + private EntityManager em; + + + @Override + public void truncate() { + em.createNativeQuery("truncate table " + UseNativeQuery.SendDetailKkoAlimtalkReqHist.getTblNm()).executeUpdate(); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRsltHistRepository.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRsltHistRepository.java new file mode 100644 index 0000000..67881ff --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRsltHistRepository.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain.repository; + +import cokr.xit.ens.modules.common.biztmplt.CleanRepositorySupport; +import cokr.xit.ens.modules.kkoalimtalk.domain.SendDetailKkoAlimtalkRsltHist; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SendDetailKkoAlimtalkRsltHistRepository extends JpaRepository, CleanRepositorySupport { + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRsltHistRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRsltHistRepositoryImpl.java new file mode 100644 index 0000000..797e9c0 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/SendDetailKkoAlimtalkRsltHistRepositoryImpl.java @@ -0,0 +1,17 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain.repository; + +import cokr.xit.ens.modules.common.biztmplt.CleanRepositorySupport; +import cokr.xit.ens.modules.common.code.UseNativeQuery; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +public class SendDetailKkoAlimtalkRsltHistRepositoryImpl implements CleanRepositorySupport { + @PersistenceContext + private EntityManager em; + + @Override + public void truncate() { + em.createNativeQuery("truncate table " + UseNativeQuery.SendDetailKkoAlimtalkRsltHist.getTblNm()).executeUpdate(); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/TmpltMngKkoAlimtalkRepository.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/TmpltMngKkoAlimtalkRepository.java new file mode 100644 index 0000000..cabe658 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/TmpltMngKkoAlimtalkRepository.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain.repository; + +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.ids.TmpltMngIds; +import cokr.xit.ens.modules.kkoalimtalk.domain.TmpltMngKkoAlimtalk; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TmpltMngKkoAlimtalkRepository extends JpaRepository, TmpltMngKkoAlimtalkRepositoryCustom { +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/TmpltMngKkoAlimtalkRepositoryCustom.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/TmpltMngKkoAlimtalkRepositoryCustom.java new file mode 100644 index 0000000..9e7c7f0 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/TmpltMngKkoAlimtalkRepositoryCustom.java @@ -0,0 +1,10 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain.repository; + +import cokr.xit.ens.modules.kkoalimtalk.domain.TmpltMngKkoAlimtalk; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.TmpltMngRepositorySupport; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngSearchDTO; +import cokr.xit.ens.modules.kkoalimtalk.model.TmpltMngKkoAlimtalkDTO; + +public interface TmpltMngKkoAlimtalkRepositoryCustom extends TmpltMngRepositorySupport { + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/TmpltMngKkoAlimtalkRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/TmpltMngKkoAlimtalkRepositoryImpl.java new file mode 100644 index 0000000..57d1357 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/domain/repository/TmpltMngKkoAlimtalkRepositoryImpl.java @@ -0,0 +1,104 @@ +package cokr.xit.ens.modules.kkoalimtalk.domain.repository; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngSearchDTO; +import cokr.xit.ens.modules.kkoalimtalk.domain.TmpltMngKkoAlimtalk; +import cokr.xit.ens.modules.kkoalimtalk.model.TmpltMngKkoAlimtalkDTO; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.QBean; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.util.List; +import java.util.Optional; + +import static cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng.orgMng; +import static cokr.xit.ens.modules.kkoalimtalk.domain.QTmpltMngKkoAlimtalk.tmpltMngKkoAlimtalk; + +@RequiredArgsConstructor +public class TmpltMngKkoAlimtalkRepositoryImpl implements TmpltMngKkoAlimtalkRepositoryCustom { + + private final JPAQueryFactory query; + + @Override + public Optional findFetchByOrgCdAndTmpltCd(String orgCd, String tmpltCd) { + return Optional.ofNullable(query.selectFrom(tmpltMngKkoAlimtalk) + .where(tmpltMngKkoAlimtalk.orgMng.orgCd.eq(orgCd) + .and(tmpltMngKkoAlimtalk.tmpltCd.eq(tmpltCd))) + .fetchOne()); + } + + @Override + public List findAllFetchBySearchDTO(TmpltMngSearchDTO searchDTO) { + return query.selectFrom(tmpltMngKkoAlimtalk) + .innerJoin(tmpltMngKkoAlimtalk.orgMng, orgMng) + .fetchJoin() + .where(eqSearchDTO(searchDTO)) + .fetch(); + } + + @Override + public Optional findDtoByOrgCdAndTmpltCd(String orgCd, String tmpltCd) { + return Optional.ofNullable(query.select(mappedDto()) + .from(tmpltMngKkoAlimtalk) + .where(tmpltMngKkoAlimtalk.orgMng.orgCd.eq(orgCd) + .and(tmpltMngKkoAlimtalk.tmpltCd.eq(tmpltCd))) + .fetchOne()); + } + + @Override + public List findAllDtoBySearchDTO(TmpltMngSearchDTO searchDTO) { + return query.select(mappedDto()) + .from(tmpltMngKkoAlimtalk) + .innerJoin(tmpltMngKkoAlimtalk.orgMng, orgMng) + .where(eqSearchDTO(searchDTO)) + .fetch(); + } + + private QBean mappedDto() { + return Projections.fields(TmpltMngKkoAlimtalkDTO.class + , tmpltMngKkoAlimtalk.dtype + , tmpltMngKkoAlimtalk.orgMng.orgCd + , tmpltMngKkoAlimtalk.orgMng.orgNm + , tmpltMngKkoAlimtalk.tmpltCd + , tmpltMngKkoAlimtalk.title + , tmpltMngKkoAlimtalk.message + , tmpltMngKkoAlimtalk.useYn + + , tmpltMngKkoAlimtalk.biztalkOrgCd + , tmpltMngKkoAlimtalk.biztalkTmpltCode + , tmpltMngKkoAlimtalk.pryMessage + ); + } + + @Override + public Optional findFetchByOrgCdAndTmpltCdAndUseYn(String orgCd, String tmpltCd, String useYn) { + return Optional.ofNullable( + query.selectFrom(tmpltMngKkoAlimtalk) + .innerJoin(tmpltMngKkoAlimtalk.orgMng, orgMng) + .fetchJoin() + .where( + tmpltMngKkoAlimtalk.orgMng.orgCd.eq(orgCd) + .and(tmpltMngKkoAlimtalk.tmpltCd.eq(tmpltCd)) + .and(tmpltMngKkoAlimtalk.useYn.eq(useYn)) + ) + .fetchOne()); + } + + private BooleanBuilder eqSearchDTO(TmpltMngSearchDTO searchDTO) { + BooleanBuilder builder = new BooleanBuilder(); + + if (!CmmnUtil.isEmpty(searchDTO.getSchOrgCd())) + builder.and(tmpltMngKkoAlimtalk.orgMng.orgCd.eq(searchDTO.getSchOrgCd())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchTmpltCd())) + builder.and(tmpltMngKkoAlimtalk.tmpltCd.eq(searchDTO.getSchTmpltCd())); + + if (!CmmnUtil.isEmpty(searchDTO.getSchTitle())) + builder.and(tmpltMngKkoAlimtalk.title.like(searchDTO.getSchTitle() + "%")); + + + return builder; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/KkoAlimtalkAcceptReqDTO.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/KkoAlimtalkAcceptReqDTO.java new file mode 100644 index 0000000..0e85f65 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/KkoAlimtalkAcceptReqDTO.java @@ -0,0 +1,24 @@ +package cokr.xit.ens.modules.kkoalimtalk.model; + +import cokr.xit.ens.core.model.EnsAcceptReqDTO; +import cokr.xit.ens.modules.kkoalimtalk.model.config.Document; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import java.util.List; + +@SuperBuilder +@Data +@Schema(name = "KkoAlimtalkAcceptReqDTO") +@NoArgsConstructor +public class KkoAlimtalkAcceptReqDTO extends EnsAcceptReqDTO { + + @Valid + @NotEmpty(message = "문서목록은 필수 입력값 입니다") + private List documents; + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/KkoAlimtalkApiRespVO.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/KkoAlimtalkApiRespVO.java new file mode 100644 index 0000000..ce1c776 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/KkoAlimtalkApiRespVO.java @@ -0,0 +1,27 @@ +package cokr.xit.ens.modules.kkoalimtalk.model; + +import cokr.xit.ens.modules.kkoalimtalk.model.config.MsgInfo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +import java.util.List; + +@Getter +@ToString +@Builder +@EqualsAndHashCode +@Schema(name = "KkoAlimtalkApiRespVO") +public class KkoAlimtalkApiRespVO { + + @Schema(title = "비즈톡 G/W 접수결과 코드", example = " ") + private String responseCode; + + @Schema(title = "접수 결과 메시지(접수 실패일 경우에만 표시)", example = " ") + private String msg; + + @Schema(title = "응답데이터", example = " ") + private List msgList; +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/KkoAlimtalkRsltRespDTO.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/KkoAlimtalkRsltRespDTO.java new file mode 100644 index 0000000..0241cf7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/KkoAlimtalkRsltRespDTO.java @@ -0,0 +1,20 @@ +package cokr.xit.ens.modules.kkoalimtalk.model; + +import cokr.xit.ens.core.model.EnsRsltRespDTO; +import cokr.xit.ens.modules.kkoalimtalk.model.config.KkoAlimtalkStat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@SuperBuilder +@Data +@Schema(name = "KkoAlimtalkRsltRespDTO") +public class KkoAlimtalkRsltRespDTO extends EnsRsltRespDTO { + @Schema(required = true, title = "발송마스터ID", example = " ") + private Long sendMastId; + @Schema(required = false, title = "발송요청문서", example = " ") + private List documents; + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/TmpltMngKkoAlimtalkDTO.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/TmpltMngKkoAlimtalkDTO.java new file mode 100644 index 0000000..a0a9fae --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/TmpltMngKkoAlimtalkDTO.java @@ -0,0 +1,28 @@ +package cokr.xit.ens.modules.kkoalimtalk.model; + +import cokr.xit.ens.modules.common.ctgy.sys.mng.model.TmpltMngByTypeDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +@Data +@SuperBuilder +@NoArgsConstructor +@Schema(name = "TmpltMngKkoAlimtalkDTO") +public class TmpltMngKkoAlimtalkDTO extends TmpltMngByTypeDTO implements Serializable { + + @Length(max = 20, message = "비즈톡 기관코드의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "비즈톡 기관코드", example = " ") + private String biztalkOrgCd; + + @Length(max = 30, message = "비즈톡 템플릿코드의 최대 길이를 초과 했습니다.") + @NotBlank(message = "비즈톡 템플릿코드는 필수 입력값 입니다.") + @Schema(required = true, title = "비즈톡 템플릿코드", example = "CEPHIS_001") + private String biztalkTmpltCode; + +} diff --git a/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/config/Attachment.java b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/config/Attachment.java new file mode 100644 index 0000000..c9d9148 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkoalimtalk/model/config/Attachment.java @@ -0,0 +1,21 @@ +package cokr.xit.ens.modules.kkoalimtalk.model.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.validation.Valid; +import java.util.List; + +@Getter +@ToString +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "Attachment") +public class Attachment { + +// @Schema(required = false, title = "버튼 목록", example = " ") + @Valid + @Setter + private List