commit 0a4f0941041d48eb59efafa7895e14fa14539681 Author: minkyu1128 Date: Thu Mar 30 11:23:19 2023 +0900 feat: 전자문서/CI변환/모바일페이지 서비스 구축 -.주정차웹: 천안, 춘천 -.민자고속도로 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/pom.xml b/pom.xml new file mode 100644 index 0000000..f58860d --- /dev/null +++ b/pom.xml @@ -0,0 +1,450 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.3 + + + cokr.modules + module-post + 0.0.1-SNAPSHOT + war + module-post + Demo project for Spring Boot + + 1.8 + ${basedir}/libs + ojdbc8 + 1.6.3 + 1.4.2.Final + 1.18.20 + + 3rd-party/**, + resource/**, + WEB-INF/jsp/**, + WEB-INF/META-INF/**, + WEB-INF/classes/application.yml, + WEB-INF/classes/config/*.yml, + WEB-INF/classes/**/ens/*.class, + WEB-INF/classes/**/ens/core/**, + WEB-INF/classes/**/ens/batch/**/EnsScheduler.class, + WEB-INF/classes/**/ens/modules/*.class, + + + WEB-INF/classes/**/ens/modules/example/**, + + + + + local + + true + + + local + + ${package.include.base} + WEB-INF/classes/**/ens/batch/**, + WEB-INF/classes/**/ens/modules/**, + WEB-INF/classes/application-local*.yml, + + + + + + + prod-iup + + prod-iup + + ${package.include.base} + WEB-INF/classes/**/ens/modules/**, + + + + WEB-INF/classes/**/ens/biz/iup/**, + WEB-INF/classes/application-prod-iup.yml, + WEB-INF/classes/mybatis-mapper/**, + + + ${package.exclude.base} + WEB-INF/classes/**/ens/batch/**/EnsScheduler.class, + WEB-INF/classes/**/ens/biz/iup/_legacy/**, + WEB-INF/classes/**/ens/biz/iup/alimtalk/**, + + + + + prod-traffic-cc + + prod-traffic + + ${package.include.base} + WEB-INF/classes/**/ens/batch/**/EnsKkoMydocScheduler.class, + WEB-INF/classes/**/ens/modules/common/**, + WEB-INF/classes/**/ens/modules/kkomydoc/**, + WEB-INF/classes/**/ens/biz/traffic/chuncheon/**, + WEB-INF/classes/application-prod-traffic.yml, + + + ${package.exclude.base} + WEB-INF/classes/**/ens/modules/common/ctgy/intgrnnoti/**, + + + + + + src/main/resources + + mybatis-mapper/** + + + + + + + prod-traffic-cheonan + + prod-traffic-cheonan + + ${package.include.base} + WEB-INF/classes/**/ens/batch/**/EnsIntgrnScheduler.class, + WEB-INF/classes/**/ens/batch/**/EnsKkoMydocScheduler.class, + WEB-INF/classes/**/ens/batch/**/EnsKtGibisScheduler.class, + WEB-INF/classes/**/ens/modules/**, + + + + + WEB-INF/classes/**/ens/biz/traffic/cheonan/**, + WEB-INF/classes/application-prod-traffic-cheonan.yml, + WEB-INF/classes/mybatis-mapper/**, + + + ${package.exclude.base} + + ojdbc6 + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-validation + + + + + + + + + org.springframework.kafka + spring-kafka + + + + + com.h2database + h2 + 1.4.199 + runtime + + + org.mariadb.jdbc + mariadb-java-client + runtime + + + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + org.projectlombok + lombok + ${lombok.version} + true + + + + + org.apache.tomcat.embed + tomcat-embed-jasper + + + + + javax.servlet + jstl + + + + + org.springframework.boot + spring-boot-devtools + + + + + com.querydsl + + querydsl-jpa + + 4.4.0 + + + com.querydsl + + querydsl-apt + + 4.2.1 + provided + + + org.eclipse.jdt.core.compiler + ecj + + + + + + + + org.apache.httpcomponents + httpcore + 4.4.6 + + + org.apache.httpcomponents + httpclient + 4.5.11 + + + commons-io + commons-io + 1.3.2 + + + + + com.auth0 + java-jwt + 3.10.3 + + + + + com.github.gavlyukovskiy + p6spy-spring-boot-starter + 1.8.0 + + + + + + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + it.ozimov + embedded-redis + 0.7.2 + + + + + external + nicedici + 1.0 + system + ${webapp.lib}/VNOInterop.jar + + + external + ${webapp.lib.jdbc.oracle} + 1.0 + system + ${webapp.lib}/${webapp.lib.jdbc.oracle}.jar + + + + + org.springdoc + springdoc-openapi-ui + ${springdoc.swagger} + + + + + + + + + + + + + + + + + + + + + + + + + com.google.code.gson + gson + 2.9.0 + + + + + com.slack.api + bolt + 1.21.2 + + + com.slack.api + bolt-servlet + 1.21.2 + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.2.2 + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + true + + + + + com.mysema.maven + apt-maven-plugin + 1.1.3 + + + generate-sources + + process + + + target/generated-sources/java + + com.querydsl.apt.jpa.JPAAnnotationProcessor + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + + + org.projectlombok + lombok + ${lombok.version} + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.3.1 + + ${packageIncludesByProfile} + ${packageExcludesByProfile} + + + + + + + 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/alimtalk/model/IupAlimtalkReqVO.java b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/model/IupAlimtalkReqVO.java new file mode 100644 index 0000000..4c5af40 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/model/IupAlimtalkReqVO.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.biz.iup.alimtalk.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +@Getter +@Schema(name = "IupAlimtalkReqVO") +public class IupAlimtalkReqVO { + + @Schema(required = true, title = "연계입수 아이디", example = " ") + private Long lnkInputId; +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/alimtalk/mq/IupAlimtalkConsumer.java b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/mq/IupAlimtalkConsumer.java new file mode 100644 index 0000000..77497ed --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/mq/IupAlimtalkConsumer.java @@ -0,0 +1,38 @@ +package cokr.xit.ens.biz.iup.alimtalk.mq; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.kafka.annotation.KafkaListener; + +import javax.annotation.Resource; +import java.io.IOException; + +@Slf4j +//@Component +@Profile("prod-iup") +public class IupAlimtalkConsumer { + + @Resource(name = "iupAlimtalkMakerLegacy") +// @Autowired +// private IupAlimtalkMakerLegacy iupAlimtalkMaker; + + /** + * 알림톡 제작요청 + * @param message + * @throws IOException + */ + @SuppressWarnings("unchecked") + @KafkaListener(topics = "iup-kkoalimtalk-makereq", groupId = "group-id-ens") + public void subMakeReq(String message) throws IOException { + log.info("[iup-kkoalimtalk-makereq] sub message : " + message); + try { + Long sendMastId = Long.parseLong(message); + +// iupAlimtalkMaker.make(sendMastId); + } catch (Exception e) { + e.printStackTrace(); + } + } + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/alimtalk/mq/IupAlimtalkProducer.java b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/mq/IupAlimtalkProducer.java new file mode 100644 index 0000000..a4445b5 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/mq/IupAlimtalkProducer.java @@ -0,0 +1,28 @@ +package cokr.xit.ens.biz.iup.alimtalk.mq; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class IupAlimtalkProducer { + + @Autowired + private KafkaTemplate kafkaTemplate; + + /** + * 알림톡 제작요청 + * @param message + */ + public void pubMakeReq(String message) { + final String topicName = "iup-kkoalimtalk-makereq"; + + 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/iup/alimtalk/presentation/IupAlimtalkController.java b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/presentation/IupAlimtalkController.java new file mode 100644 index 0000000..82d2cc7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/presentation/IupAlimtalkController.java @@ -0,0 +1,54 @@ +package cokr.xit.ens.biz.iup.alimtalk.presentation; + +import cokr.xit.ens.biz.iup.alimtalk.model.IupAlimtalkReqVO; +import cokr.xit.ens.biz.iup.alimtalk.service.IupAlimtalkService; +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 = "IupAlimtalkController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class IupAlimtalkController { + + private final IupAlimtalkService iupAlimtalkService; + + @Operation(summary = "접수") + @PostMapping(value = "/iup/alimtalk/accept", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity accept(@RequestBody IupAlimtalkReqVO reqDTO){ + EnsResponseVO responseVO = iupAlimtalkService.accept(reqDTO.getLnkInputId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "제작") +// @PutMapping(value = "/iup/alimtalk/re/make", produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/iup/alimtalk/re/make", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity reMake(@RequestBody IupAlimtalkReqVO reqDTO){ + EnsResponseVO responseVO = iupAlimtalkService.reMake(reqDTO.getLnkInputId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "전송") +// @PutMapping(value = "/iup/alimtalk/re/send", produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/iup/alimtalk/re/send", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity reSend(@RequestBody IupAlimtalkReqVO reqDTO){ + EnsResponseVO responseVO = iupAlimtalkService.reSend(reqDTO.getLnkInputId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "전송결과가져오기") + @PostMapping(value = "/iup/alimtalk/fetch", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity fetch(@RequestBody IupAlimtalkReqVO reqDTO){ + EnsResponseVO responseVO = iupAlimtalkService.fetch(reqDTO.getLnkInputId()); + return new ResponseEntity(responseVO, HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/alimtalk/sched/IupAlimtalkScheduler.java b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/sched/IupAlimtalkScheduler.java new file mode 100644 index 0000000..cd35f06 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/sched/IupAlimtalkScheduler.java @@ -0,0 +1,45 @@ +package cokr.xit.ens.biz.iup.alimtalk.sched; + +import cokr.xit.ens.biz.iup.alimtalk.service.IupAlimtalkService; +import cokr.xit.ens.core.aop.EnsResponseVO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; + +@Slf4j +//@Component +//@Profile("prod-iup") +@RequiredArgsConstructor +public class IupAlimtalkScheduler { + + private final IupAlimtalkService iupAlimtalkService; + + /** + * 알림톡 접수 + * -. 알림톡 전송을 위해 IUP에 등록된 기초데이터를 ENS에 이관 등록 한다. + */ + @Scheduled(cron = "0 */5 7-22 * * *") + public void accepted() { + EnsResponseVO responseVO = iupAlimtalkService.acceptAll(); + + log.info("======================================================="); + log.info("[IUP] 알림톡 접수처리 결과"); + log.info(responseVO.toString()); + log.info("======================================================="); + } + + + /** + * 알림톡 결과 가져오기 + * -. 전송이 완료된 알림톡 전송결과(성공/실패)를 ENS -> IUP 로 가져온다. + */ + @Scheduled(cron = "0 */15 7-22 * * *") + public void fetched() { + EnsResponseVO responseVO = iupAlimtalkService.fetchAll(); + + log.info("======================================================="); + log.info("[IUP] 알림톡 전송결과 Fetch"); + log.info(responseVO.toString()); + log.info("======================================================="); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/IupAlimtalkService.java b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/IupAlimtalkService.java new file mode 100644 index 0000000..560547a --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/IupAlimtalkService.java @@ -0,0 +1,164 @@ +package cokr.xit.ens.biz.iup.alimtalk.service; + +import cokr.xit.ens.biz.iup.alimtalk.service.support.IupAlimtalkAcceptor; +import cokr.xit.ens.biz.iup.alimtalk.service.support.IupAlimtalkFetcher; +import cokr.xit.ens.biz.iup.alimtalk.service.support.IupAlimtalkMaker; +import cokr.xit.ens.biz.iup.alimtalk.service.support.IupAlimtalkSender; +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.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.kkoalimtalk.service.event.KkoAlimtalkSendReserveEvent; +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 IupAlimtalkService { + + + + private final TbInputXitRepository tbInputXitRepository; + + private final IupAlimtalkAcceptor iupAlimtalkAcceptor; + private final IupAlimtalkMaker iupAlimtalkMaker; + private final IupAlimtalkSender iupAlimtalkSender; + private final IupAlimtalkFetcher iupAlimtalkFetcher; + + private final ApplicationEventPublisher applicationEventPublisher; + + + /** + * 인증톡 접수(IUP -> ENS) + */ + public EnsResponseVO accept(Long lnkInputId){ + + try { + + TbInputXit tbInputXit = tbInputXitRepository.findByPrcsCdAndSendTypeAndId(IupPrcsCd.TGRG, IupSendTypeCd.NI, 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) + */ + public EnsResponseVO> acceptAll(){ + try { + + List tbInputXits = tbInputXitRepository.findAllByPrcsCdInAndSendType(Arrays.asList(IupPrcsCd.TGRG), IupSendTypeCd.NI); + 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){ + iupAlimtalkAcceptor.statReady(tbInputXits.stream().map(row -> row.getLnkInputId()).collect(Collectors.toList())); + + List resultInfo = tbInputXits.stream() + .map(row -> iupAlimtalkAcceptor.execute(row.getLnkInputId())) + .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()); + KkoAlimtalkSendReserveEvent event = KkoAlimtalkSendReserveEvent.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 iupAlimtalkMaker.execute(lnkInputId); + } + + + /** + * 인증톡 전송 재요청 + * @param lnkInputId + * @return + */ + public EnsResponseVO reSend(Long lnkInputId){ + return iupAlimtalkSender.execute(lnkInputId); + } + + + /** + * 인증톡 전송(성공/실패) 결과 가져오기 + */ + 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.NI.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), IupSendTypeCd.NI); + + return this.fetch(tbInputXits); + } + + private EnsResponseVO fetch(List tbInputXits){ + iupAlimtalkFetcher.statReady(tbInputXits.stream().map(row -> row.getLnkInputId()).collect(Collectors.toList())); + + return EnsResponseVO.okBuilder() + .resultInfo( + tbInputXits.stream() + .map(row -> iupAlimtalkFetcher.execute(row.getLnkInputId())) + .collect(Collectors.toList() + ) + ) + .build(); + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/IupBillPayApiAlimtalkService.java b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/IupBillPayApiAlimtalkService.java new file mode 100644 index 0000000..296e64d --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/IupBillPayApiAlimtalkService.java @@ -0,0 +1,430 @@ +package cokr.xit.ens.biz.iup.alimtalk.service; + +import cokr.xit.ens.biz.iup.billpay.service.IupBillPayApiServiceSupport; +import cokr.xit.ens.biz.iup.domain.TbEnfrcLevRciv; +import cokr.xit.ens.biz.iup.domain.TbInputDataXit; +import cokr.xit.ens.biz.iup.domain.VKakaoNoticeInfo; +import cokr.xit.ens.biz.iup.domain.VKakaoNoticeInfoSn; +import cokr.xit.ens.biz.iup.domain.repository.TbEnfrcLevRcivRepository; +import cokr.xit.ens.biz.iup.domain.repository.TbInputDataXitRepository; +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.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.api.BillKkoClientApiSpec; +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.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.kkoalimtalk.domain.SendDetailKkoAlimtalk; +import cokr.xit.ens.modules.kkoalimtalk.domain.repository.SendDetailKkoAlimtalkRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.text.SimpleDateFormat; +import java.util.*; + +@Slf4j +@Service("iupBillPayApiService_NI") +@RequiredArgsConstructor +public class IupBillPayApiAlimtalkService extends IupBillPayApiServiceSupport { + + + private final SendDetailKkoAlimtalkRepository sendDetailKkoAlimtalkRepository; + 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 BillKkoClientApiSpec billKkoClientApi; + + + /** + * 청구서 조회 + * + * @param mParam + * @return + */ + @Transactional + 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.E402; + throw new EnsException(EnsErrCd.ERR401, "사용자식별키가 없습니다."); + } + if (CmmnUtil.isEmpty(orgCd)) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR401, "기관코드가 없습니다."); + } + if (CmmnUtil.isEmpty(userBirth)) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR401, "생년월일이 없습니다."); + } + + + Optional orgMng = orgMngRepository.findById(orgCd); + if (!orgMng.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR404, "일치하는 기관정보가 없습니다."); + } + Optional sendDetailKkoAlimtalk = sendDetailKkoAlimtalkRepository.findByMsgIdx(billerUserKey); + if (!sendDetailKkoAlimtalk.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR404, "일치하는 발송상세 자료가 없습니다."); + } + Optional sendTmpltMng = sendTmpltMngRepository.findFetchByOrgCdAndTmpltCdAndUseYn(orgCd, sendDetailKkoAlimtalk.get().getSendMast().getTmpltCd(), "Y"); + if (!sendTmpltMng.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E402; + 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(); + + 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, "생년월일이 일치하지 않습니다."); + } + + 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, "생년월일이 일치하지 않습니다."); + } + + 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 + 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); + if (!tbInputDataXit.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR404, "일치하는 발송상세정보가 없습니다."); + } + final String dataId = tbInputDataXit.get().getDataId(); + Optional vKakaoNoticeInfo = Optional.ofNullable(null); + List tbEnfrcLevRcivs = new ArrayList<>(); + if ("Y".equals(orgMng.get().getKkoBpCsignYn())) { + if (dataId.length() < 20) { + kkoBillErrCd = BillKkoErrCd.E601; + throw new EnsException(EnsErrCd.ERR403, "빌러코드가 20자리 미만 입니다."); + } + Optional vKakaoNoticeInfoSn = vKakaoNoticeInfoSnRepository.findById(dataId); + if (!vKakaoNoticeInfoSn.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E502; + throw new EnsException(EnsErrCd.ERR404, "일치하는 단순미납 자료가 없습니다."); + } + + respVO = billKkoClientApi.callApiByOrg(orgMng.get().getKkoBpCsignPrepayApi(), 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(orgMng.get().getKkoBpCsignYn())) { + 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"); + + } 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 + public BillKkoApiRespDTO addPayReultIfno(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("pay_by"); +// data.get("pay_type"); +// data.get("pay_detail1"); +// data.get("pay_detail2"); +// data.get("pay_detail3"); +// data.get("amount"); +// data.get("pay_amount"); +// data.get("pay_fee_type"); +// data.get("pay_fee"); +// data.get("pay_fee_tax"); +// data.get("adjust_date"); +// data.get("paid_at"); +// data.get("pay_id"); + + + 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 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.PAYRSLT, 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, "일치하는 기관정보가 없습니다."); + } + if ("Y".equals(orgMng.get().getKkoBpCsignYn())) { + return billKkoClientApi.callApiByOrg(orgMng.get().getKkoBpCsignPayresultApi(), mParam); + + } else if ("N".equals(orgMng.get().getKkoBpCsignYn())) { + + } else { + kkoBillErrCd = BillKkoErrCd.E601; + throw new EnsException(EnsErrCd.ERR999, "위탁업체여부 구분값이 등록되지 않았습니다."); + } + + + 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; + } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/support/IupAlimtalkAcceptor.java b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/support/IupAlimtalkAcceptor.java new file mode 100644 index 0000000..d1c4da1 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/support/IupAlimtalkAcceptor.java @@ -0,0 +1,294 @@ +package cokr.xit.ens.biz.iup.alimtalk.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.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.MapDeserailizer; +import cokr.xit.ens.modules.common.biztmplt.EnsPhaseProcSupport; +import cokr.xit.ens.modules.common.code.VenderCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.BillAcptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoAcptReqVO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.config.CustomUrl; +import cokr.xit.ens.modules.kkoalimtalk.model.KkoAlimtalkAcceptReqDTO; +import cokr.xit.ens.modules.kkoalimtalk.model.config.*; +import cokr.xit.ens.modules.kkoalimtalk.service.KkoAlimtalkService; +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 IupAlimtalkAcceptor implements EnsPhaseProcSupport { + + private final TbInputXitRepository tbInputXitRepository; + private final TbInputDataXitRepository tbInputDataXitRepository; + + private final KkoAlimtalkService kkoAlimtalkService; + + Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).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; + + /** + * 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-KKOAT-%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))); + + KkoAlimtalkAcceptReqDTO reqDTO = this.convertTbInputDataToAcceptReqDTO(tbInputDataXitRepository.findAllFetchByLnkInputId(tbInputXit.getLnkInputId())); + + EnsResponseVO reqResp = kkoAlimtalkService.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())) { + 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 KkoAlimtalkAcceptReqDTO convertTbInputDataToAcceptReqDTO(List list) { + + return KkoAlimtalkAcceptReqDTO.builder() + .vender(VenderCd.biztalk.getCode()) + .org_cd(list.get(0).getTbInputXit().getOrgCd()) +// .tmplt_cd(list.get(0).getTbInputXit().getFsJob().getTemplateCd()) + .tmplt_cd(list.get(0).getTbInputXit().getFsJob().getJobCd()) + .post_bundle_title( + String.format("%s(%s건)-%s" + , IupSendTypeCd.NI.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 { + + return Document.builder() +// .msg_idx(data.getDataId()) + .msg_idx(data.getLinkedUuid()) + .country_code("82") + .recipient(data.getMoblphonNo()) + .app_user_id(null) + .title(null) + .res_method("PUSH") + .attach(this.createAttach(data)) + .supplement(this.createSupplement(data)) + .message_type("AT") + .use_failback(null) + .mms_attach(this.createMmsAttach(data)) + .xit_property(this.createXitProperty(data)) + .build(); + } + + private Attachment createAttach(TbInputDataXit data) { + return null; + } + + private Supplement createSupplement(TbInputDataXit data) { + return null; + } + + private MmsAttach createMmsAttach(TbInputDataXit data) { + return null; + } + + private XitProperty createXitProperty(TbInputDataXit data) { + return XitProperty.builder() +// .bill_link_info(this.createBillLinkInfo(data)) + .bill_acpt_data(this.createBillAcptData(data)) + .tmplt_msg_data(CmmnUtil.isEmpty(data.getMsgData()) ? null : gson.fromJson(data.getMsgData().replace("~~@@!!", "#{").replace("!!@@~~", "}"), Map.class)) + .build(); + } + + +// return BillLinkInfo.builder() +// .button_name("납부하기") +// .button_type("WL") +// .expire_at(data.getTbInputXit().getPayExpiresDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) +// .notice_url(this.BILL_HOST + this.BILL_NOTICE_URL) +// .prepay_url(this.BILL_HOST + this.BILL_PREPAY_URL) +// .pay_result_url(this.BILL_HOST + this.BILL_PAYREUSLT_URL) +// .build(); +// } + protected BillAcptReqDTO createBillAcptData(TbInputDataXit data) { + return BillAcptReqDTO.builder() + .use_bill_uid(false) + .bill_uid(null) + .bill_se(BillSeCd.bpKko) + .bill_kko(BillKkoAcptReqVO.builder() + .billUid(null) + .billerUserKey(data.getLinkedUuid()) + .billedYearMonth(null) + .ordinal(null) + .billerNoticeKey(null) + .expireAt(data.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()) + .build(); + } + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/support/IupAlimtalkFetcher.java b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/support/IupAlimtalkFetcher.java new file mode 100644 index 0000000..cc69684 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/support/IupAlimtalkFetcher.java @@ -0,0 +1,192 @@ +package cokr.xit.ens.biz.iup.alimtalk.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.IupSendTypeCd; +import cokr.xit.ens.biz.iup.domain.TbInputDataXit; +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.StatCd; +import cokr.xit.ens.modules.kkoalimtalk.model.KkoAlimtalkRsltRespDTO; +import cokr.xit.ens.modules.kkoalimtalk.service.KkoAlimtalkService; +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 IupAlimtalkFetcher implements EnsPhaseProcSupport { + + private final TbInputXitRepository tbInputXitRepository; + private final TbInputDataXitRepository tbInputDataXitRepository; + + private final TbSendResultRepository tbSendResultRepository; + + private final KkoAlimtalkService kkoAlimtalkService; + + + + /** + * 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, "연계입수아이디(은)는 필수조건 입니다."); + + + 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); + + try { + Long sendMastId = tbInputDataXitRepository.findLastSendMastIdByLnkInputIdAndSendType(lnkInputId, IupSendTypeCd.NI) + .orElseThrow(() -> new EnsException(EnsErrCd.RSLT404, "일치하는 ENS 접수자료가 없습니다.")); + resultInfo.put("sendMastId", sendMastId); + + + EnsResponseVO apiRespVO = kkoAlimtalkService.sendResultProvide(sendMastId); + KkoAlimtalkRsltRespDTO respDTO = (KkoAlimtalkRsltRespDTO) apiRespVO.getResultInfo(); + + + tbSendResultRepository.saveAll(respDTO.getDocuments().stream() + .map(row -> { + IupSendSttusCd iupSendSttusCd = null; + try { + switch (row.getKkoResultCd()){ + case RS_1000: + iupSendSttusCd = IupSendSttusCd.RECV; + break; + case RS_1014: + case RS_1015: + case RS_3018: + iupSendSttusCd = IupSendSttusCd.NOMB; + break; + case RQ_B400: + case RQ_B401: + case RQ_B402: + case RQ_B403: + case RS_1021: + case RS_1025: + iupSendSttusCd = IupSendSttusCd.DENY; + break; + default: + iupSendSttusCd = IupSendSttusCd.FAIL; + break; +// iupSendSttusCd = IupSendSttusCd.SEND; +// iupSendSttusCd = IupSendSttusCd.RECV; + } + } catch (Exception e){ + log.info("IupSendSttusCd와 일치하는 값 없음. [ dataId {} kkoResultCd {} ]", row.getMsgIdx(), row.getKkoResultCd()); + } + return TbSendResult.builder() + .lnkInputId(lnkInputId) +// .dataId(row.getMsgIdx()) + .dataId(tbInputDataXitRepository.findByLinkedUuid(row.getMsgIdx()) + .orElse(new TbInputDataXit()) + .getDataId()) + .prcsOdr(StatCd.close.equals(respDTO.getStatCd())?"2":"1") + .sendSttusCd(iupSendSttusCd) + .sendType(IupSendTypeCd.NI) + .runDt(DateUtil.toLocalDateTime(respDTO.getSendDt())) + .bizSendDt(null) + .bizRecvDt(null) + .bizReadDt(null) + .bizErrMsg(CmmnUtil.isEmpty(row.getErrorMessage()) ? null : row.getErrorMessage()) + .regId("ENS_SYS") + .regDt(LocalDateTime.now()) + .expiresDt(DateUtil.toLocalDateTime(respDTO.getCloseDt())) + .prcsYn("N") + .build(); + }) + .collect(Collectors.toList()) + ); + + 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.setErrMsg(null); + }else{ + tbInputXit.setUpdId("ENS_SYS"); + tbInputXit.setPrcsCd(IupPrcsCd.FAIL); + tbInputXit.setErrMsg(responseVO.getErrMsg()); + } + } + + return responseVO; + } + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/support/IupAlimtalkMaker.java b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/support/IupAlimtalkMaker.java new file mode 100644 index 0000000..a7f15c5 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/support/IupAlimtalkMaker.java @@ -0,0 +1,66 @@ +package cokr.xit.ens.biz.iup.alimtalk.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.kkoalimtalk.service.KkoAlimtalkService; +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 IupAlimtalkMaker implements EnsPhaseProcSupport { + + private final TbInputDataXitRepository tbInputDataXitRepository; + + private final KkoAlimtalkService kkoAlimtalkService; + + + @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.NI) + .orElseThrow(() -> new EnsException(EnsErrCd.MAKE404, "일치하는 ENS 접수자료가 없습니다.")); + + responseVO = kkoAlimtalkService.make(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/alimtalk/service/support/IupAlimtalkSender.java b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/support/IupAlimtalkSender.java new file mode 100644 index 0000000..8bb8a45 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/alimtalk/service/support/IupAlimtalkSender.java @@ -0,0 +1,66 @@ +package cokr.xit.ens.biz.iup.alimtalk.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.kkoalimtalk.service.KkoAlimtalkService; +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 IupAlimtalkSender implements EnsPhaseProcSupport { + + private final TbInputDataXitRepository tbInputDataXitRepository; + + private final KkoAlimtalkService kkoAlimtalkService; + + + @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.NI) + .orElseThrow(() -> new EnsException(EnsErrCd.SEND404, "일치하는 ENS 접수자료가 없습니다.")); + + responseVO = kkoAlimtalkService.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/billpay/presentation/IupBillPayApiController.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/presentation/IupBillPayApiController.java new file mode 100644 index 0000000..740ab43 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/presentation/IupBillPayApiController.java @@ -0,0 +1,276 @@ +package cokr.xit.ens.biz.iup.billpay.presentation; + +import cokr.xit.ens.biz.iup.billpay.service.IupBillPayApiServiceSupport; +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 = "IupBillPayApiController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class IupBillPayApiController { + + private final TbInputDataXitRepository tbInputDataXitRepository; + + private final Map mIupBillPayApiService; + + + @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와 일치하는 데이터를 찾을 수 없습니다.")); + IupBillPayApiServiceSupport iupBillPayService = mIupBillPayApiService.get("iupBillPayApiService_" + tbInputDataXit.getTbInputXit().getSendType()); + + return new ResponseEntity(iupBillPayService.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와 일치하는 데이터를 찾을 수 없습니다.")); + IupBillPayApiServiceSupport iupBillPayService = mIupBillPayApiService.get("iupBillPayApiService_" + 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와 일치하는 데이터를 찾을 수 없습니다.")); + IupBillPayApiServiceSupport iupBillPayService = mIupBillPayApiService.get("iupBillPayApiService_" + 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/IupBillPayRsltFwdController.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/presentation/IupBillPayRsltFwdController.java new file mode 100644 index 0000000..96d9c1b --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/presentation/IupBillPayRsltFwdController.java @@ -0,0 +1,109 @@ +package cokr.xit.ens.biz.iup.billpay.presentation; + +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.model.IupSigntalkReqVO; +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.intgrnbill.kko.model.BillKkoApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.impl.BillKkoClientServiceImpl; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +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.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Tag(name = "IupBillPayRsltFwdController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class IupBillPayRsltFwdController { + private final TbInputXitRepository tbInputXitRepository; + private final TbInputDataXitRepository tbInputDataXitRepository; + + private final BillKkoClientServiceImpl billKkoClientServiceImpl; + private Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).disableHtmlEscaping().create(); + + @Operation(summary = "납부결과 전달(연계 입수 아이디)") + @PostMapping(value = "/iup/bill/payrslt/fwd/bulk", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity payrsltFwdBulk(@RequestBody IupSigntalkReqVO reqDTO) { + + TbInputXit tbInputXit = tbInputXitRepository.findById(reqDTO.getLnkInputId()) + .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("연계입수아이디(%s)와 일치하는 자료가 없습니다.", reqDTO.getLnkInputId()))); + List billerUserKeys = tbInputDataXitRepository.findAllByTbInputXit(tbInputXit).stream() + .map(tbInputDataXit -> tbInputDataXit.getLinkedUuid()) + .collect(Collectors.toList()); + + + BillKkoApiRespDTO resultInfo = billKkoClientServiceImpl.fwdPayRslt(tbInputXit.getOrgCd(), billerUserKeys).getResultInfo(); + + return new ResponseEntity(EnsResponseVO.okBuilder().resultInfo(resultInfo).build(), HttpStatus.OK); + } + + + @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { + @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "Sample Example..." + , summary = "sample" + , value = "{\"biller_user_key\":[\"abcd11234\",\"dddd1234\"]}") + }) + }) + @Operation(summary = "납부결과 전달(빌러 유저 키)") + @PostMapping(value = "/iup/bill/payrslt/fwd/ids", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity payrsltFwdIds(@RequestBody Map> mParam) { + List> data = mParam.get("biller_user_key").stream() + .map(s -> tbInputDataXitRepository.findById(s)) + .filter(tbInputDataXit -> tbInputDataXit.isPresent()) + .map(tbInputDataXit -> billKkoClientServiceImpl.fwdPayRslt(tbInputDataXit.get().getTbInputXit().getOrgCd(), Collections.singletonList(tbInputDataXit.get().getLinkedUuid()))) + .map(ensResponseVO -> ensResponseVO.getResultInfo().getData()) + .collect(Collectors.toList()); + BillKkoApiRespDTO resultInfo = BillKkoApiRespDTO.okBuilder().data(data).build(); + + return new ResponseEntity(EnsResponseVO.okBuilder().resultInfo(resultInfo).build(), HttpStatus.OK); + } + + +// @Operation(summary = "[미전달분-일회성] - 납부결과 전달(2022.07.04 09:00:00 ~ 2022.07.05 15:00:00 데이터)") +// @PostMapping(value = "/iup/bill/payrslt/fwd/bulk/temp", produces = MediaType.APPLICATION_JSON_VALUE) +// public ResponseEntity payrsltFwdBulkTemp() { +// +// List resultInfo = tbInputDataXitRepository.findAllByNoFwdPayResult().stream() +// .map(tbInputDataXit -> { +// String billerUserKey = tbInputDataXit.getLinkedUuid(); +// +// OrgMng orgMng = orgMngRepository.findById(tbInputDataXit.getTbInputXit().getOrgCd()).orElse(null); +// if (orgMng == null) +// return BillKkoApiRespDTO.errBuilder().resCode(EnsErrCd.ERR404.getCode()).message(String.format("기관코드(%s)와 일치하는 자료가 없습니다. [ biller_user_key %s ]", tbInputDataXit.getTbInputXit().getOrgCd(), billerUserKey)).build(); +// +// KkoBillHist kkoBillHist = kkoBillHistRepository.findByBillerUserKeyAndReqSeAndLast(billerUserKey, KkoBillReqSeCd.PAYRSLT).orElse(null); +// if (kkoBillHist == null) +// return BillKkoApiRespDTO.errBuilder().resCode(EnsErrCd.ERR404.getCode()).message(String.format(" 일치하는 청구서 납부결과가 없습니다. [ biller_user_key %s ]", billerUserKey)).build(); +// else { +// String uri = orgMng.getKkoBpCsignPayresultApi(); +// Map param = gson.fromJson(kkoBillHist.getRequestData(), Map.class); +// return kkoBillClientApi.callApiByOrg(uri, param); +// } +// }) +// .collect(Collectors.toList()); +// +// +// return new ResponseEntity(EnsResponseVO.okBuilder().resultInfo(resultInfo).build(), HttpStatus.OK); +// } +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/billpay/service/IupBillPayApiServiceSupport.java b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/IupBillPayApiServiceSupport.java new file mode 100644 index 0000000..1ba00de --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/billpay/service/IupBillPayApiServiceSupport.java @@ -0,0 +1,114 @@ +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.modules.common.ctgy.intgrnbill.kko.service.BillKkoClientApiSupport; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import lombok.extern.slf4j.Slf4j; +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 IupBillPayApiServiceSupport extends BillKkoClientApiSupport { + + /** + * 청구서조회 "강제징수" 응답메시지 매핑 + * + * @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("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/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..af87b32 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/FsJob.java @@ -0,0 +1,88 @@ +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; + + +} 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/TbKakaoPayResult.java b/src/main/java/cokr/xit/ens/biz/iup/domain/TbKakaoPayResult.java new file mode 100644 index 0000000..7f5a18c --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/TbKakaoPayResult.java @@ -0,0 +1,106 @@ +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/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..c18e26f --- /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..7800f0a --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbEnfrcLevRcivRepository.java @@ -0,0 +1,13 @@ +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; +import java.util.Optional; + + +public interface TbEnfrcLevRcivRepository extends JpaRepository, TbEnfrcLevRcivRepositoryCustom { + + List findAllByEnfrcLevMastrIdAndDeleteAt(String enfrcLevMastrId, String deleteAt); +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbEnfrcLevRcivRepositoryCustom.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbEnfrcLevRcivRepositoryCustom.java new file mode 100644 index 0000000..348eefa --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbEnfrcLevRcivRepositoryCustom.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +public interface TbEnfrcLevRcivRepositoryCustom { + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbEnfrcLevRcivRepositoryImpl.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbEnfrcLevRcivRepositoryImpl.java new file mode 100644 index 0000000..2f24ef3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbEnfrcLevRcivRepositoryImpl.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class TbEnfrcLevRcivRepositoryImpl implements TbEnfrcLevRcivRepositoryCustom { + + private final JPAQueryFactory query; + + +} 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..c24f02b --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/TbInputDataXitCustomRepositoryImpl.java @@ -0,0 +1,120 @@ +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.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.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.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.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/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/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..98187d7 --- /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, VKakaoNoticeInfoRepositoryCustom { + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoRepositoryCustom.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoRepositoryCustom.java new file mode 100644 index 0000000..44cd4df --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoRepositoryCustom.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +public interface VKakaoNoticeInfoRepositoryCustom { + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoRepositoryImpl.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoRepositoryImpl.java new file mode 100644 index 0000000..b72a6d9 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoRepositoryImpl.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class VKakaoNoticeInfoRepositoryImpl implements VKakaoNoticeInfoRepositoryCustom { + + private final JPAQueryFactory query; + + +} 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..13228af --- /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, VKakaoNoticeInfoSnRepositoryCustom { + + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoSnRepositoryCustom.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoSnRepositoryCustom.java new file mode 100644 index 0000000..e9435ef --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoSnRepositoryCustom.java @@ -0,0 +1,5 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +public interface VKakaoNoticeInfoSnRepositoryCustom { + +} diff --git a/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoSnRepositoryImpl.java b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoSnRepositoryImpl.java new file mode 100644 index 0000000..9b92984 --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/domain/repository/VKakaoNoticeInfoSnRepositoryImpl.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.biz.iup.domain.repository; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class VKakaoNoticeInfoSnRepositoryImpl implements VKakaoNoticeInfoSnRepositoryCustom { + + private final JPAQueryFactory query; + + +} 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/IupBillPayApiSigntalkService.java b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/IupBillPayApiSigntalkService.java new file mode 100644 index 0000000..165918d --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/IupBillPayApiSigntalkService.java @@ -0,0 +1,476 @@ +package cokr.xit.ens.biz.iup.signtalk.service; + +import cokr.xit.ens.biz.iup.billpay.service.IupBillPayApiServiceSupport; +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.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.api.BillKkoClientApiSpec; +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.BillKkoPayResultDTO; +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 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("iupBillPayApiService_KP") +@RequiredArgsConstructor +public class IupBillPayApiSigntalkService extends IupBillPayApiServiceSupport { + + + 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 TbEnfrcLevMastrRepository tbEnfrcLevMastrRepository; + private final TbKakaoPayResultRepository tbKakaoPayResultRepository; + private final BillKkoClientApiSpec billKkoClientApi; + + + /** + * 청구서 조회 + * + * @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); + if (!tbInputDataXit.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E402; + throw new EnsException(EnsErrCd.ERR404, "일치하는 발송상세정보가 없습니다."); + } + final String dataId = tbInputDataXit.get().getDataId(); + + Optional vKakaoNoticeInfo = Optional.ofNullable(null); +// List tbEnfrcLevRcivs = new ArrayList<>(); + + + if ("Y".equals(orgMng.get().getKkoBpCsignYn())) { + Optional vKakaoNoticeInfoSn = vKakaoNoticeInfoSnRepository.findById(dataId); + if (!vKakaoNoticeInfoSn.isPresent()) { + kkoBillErrCd = BillKkoErrCd.E502; + throw new EnsException(EnsErrCd.ERR404, "일치하는 단순미납 자료가 없습니다."); + } + + respVO = billKkoClientApi.callApiByOrg(orgMng.get().getKkoBpCsignPrepayApi(), 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(orgMng.get().getKkoBpCsignYn())) { + 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(); + BillKkoPayResultDTO kkoBillPayResultVO = gson.fromJson(gson.toJson(data), BillKkoPayResultDTO.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, "일치하는 기관정보가 없습니다."); + } + + if (!tbKakaoPayResultRepository.findById(kkoBillPayResultVO.getBiller_user_key()).isPresent()) + tbKakaoPayResultRepository.save(this.createTbKakaoPayResult(kkoBillPayResultVO)); + + + if ("Y".equals(orgMng.get().getKkoBpCsignYn())) { + respVO = billKkoClientApi.callApiByOrg(orgMng.get().getKkoBpCsignPayresultApi(), 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(orgMng.get().getKkoBpCsignYn())) { + + } 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(BillKkoPayResultDTO 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(); + + } +} 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..e6a626f --- /dev/null +++ b/src/main/java/cokr/xit/ens/biz/iup/signtalk/service/support/IupSigntalkAcceptor.java @@ -0,0 +1,303 @@ +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.modules.common.ctgy.intgrnbill.BillAcptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoAcptReqVO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.config.CustomUrl; +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("${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; + + @Value("${xit.mblpage.intgrn.url}") + private String MBLPAGE_URL; + @Value("${xit.mblpage.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_link_info(this.createBillLinkInfo(data)) + .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 List> createDetails(TbInputDataXit data) { +// return null; +// } + +// private BillLinkInfo createBillLinkInfo(TbInputDataXit data) { +// return BillLinkInfo.builder() +// .use_bill_mast_id(false) +// .bill_mast_id(null) +// .button_name("납부하기") +// .button_type("WL") +// .expire_at(data.getTbInputXit().getPayExpiresDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))) +// .notice_url(this.BILL_HOST + this.BILL_NOTICE_URL) +// .prepay_url(this.BILL_HOST + this.BILL_PREPAY_URL) +// .pay_result_url(this.BILL_HOST + this.BILL_PAYREUSLT_URL) +// .build(); +// } + + private BillAcptReqDTO createBillAcptData(TbInputDataXit data) { + return BillAcptReqDTO.builder() + .use_bill_uid(false) + .bill_uid(null) + .bill_se(BillSeCd.bpKko) + .bill_kko(BillKkoAcptReqVO.builder() + .billUid(null) + .billerUserKey(data.getLinkedUuid()) + .billedYearMonth(null) + .ordinal(null) + .billerNoticeKey(null) + .expireAt(data.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()) + .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..469a305 --- /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.modules.common.ctgy.intgrnbill.BillAcptReqDTO; +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.intgrn.url}") + private String MBLPAGE_URL; + @Value("${xit.mblpage.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 BillAcptReqDTO 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..81c2c23 --- /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") + .kkoBpCsignPrepayApi(null) + .kkoBpCsignPayResultApi(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..e9253d0 --- /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..4dba4c4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/aop/EnsResponseVO.java @@ -0,0 +1,44 @@ +package cokr.xit.ens.core.aop; + +import cokr.xit.ens.core.exception.code.EnsErrCd; +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 = " ") + private EnsErrCd errCode = null; + + @Schema(required = true, title = "에러 메시지", example = " ") + private String errMsg = null; + + @Schema(required = false, title = "결과 데이터", example = " ") + 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/SpringDocConfig.java b/src/main/java/cokr/xit/ens/core/config/SpringDocConfig.java new file mode 100644 index 0000000..766d4fb --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/SpringDocConfig.java @@ -0,0 +1,192 @@ +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"}) + @Bean + public GroupedOpenApi cmmnFtBillApiDoc() { + return GroupedOpenApi.builder() + .group("CF. 공통기능-청구서(kakaopay)") + .pathsToMatch("/bill/kko/**") + .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"}) + @Bean + public GroupedOpenApi kkoMydocApiDoc() { + return GroupedOpenApi.builder() + .group("CMPT. 전자고지-kakaopay 인증톡(내문서함)") + .pathsToMatch("/kko/mydoc/**") + .build(); + } + + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-iup"}) + @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"}) + @Bean + public GroupedOpenApi intgrnNotiApiDoc() { + return GroupedOpenApi.builder() + .group("CMPT. 전자고지-통합고지") + .pathsToMatch("/intgrn/noti/**") + .build(); + } + + + @Profile({"local", "local-test", "local-maria", "local-oracle", "prod-iup"}) + @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..578bc64 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/config/redis/EmbeddedRedisConfig.java @@ -0,0 +1,96 @@ +package cokr.xit.ens.core.config.redis; + +import cokr.xit.ens.core.utils.CmmnUtil; +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..797c4f2 --- /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/dialect/MariaDB103DialectCustom.java b/src/main/java/cokr/xit/ens/core/dialect/MariaDB103DialectCustom.java new file mode 100644 index 0000000..b2d99c4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/dialect/MariaDB103DialectCustom.java @@ -0,0 +1,16 @@ +package cokr.xit.ens.core.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/dialect/Oracle10gDialectCustom.java b/src/main/java/cokr/xit/ens/core/dialect/Oracle10gDialectCustom.java new file mode 100644 index 0000000..4a54670 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/dialect/Oracle10gDialectCustom.java @@ -0,0 +1,15 @@ +package cokr.xit.ens.core.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/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..51387fc --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/exception/code/EnsErrCd.java @@ -0,0 +1,160 @@ +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("알수없음") + + , ERR401("필수 파라미터가 없습니다.") + , ERR402("파라미터 유효성 검증 오류") + , ERR403("잘못된 파라미터 입니다.") + , ERR404("일치하는 자료가 없습니다.") + , ERR405("잘못된 요청 값.") + , ERR410("필수값 없음") + , ERR411("잘못된 JSON 포맷 문자열") + , ERR500("서버 오류") + , ERR501("HttpServer 오류") + , ERR502("HttpClient 오류") + , ERR503("RestClient 오류") + , ERR504("요청 데이터 Json 파싱 오류") + , ERR505("응답 데이터 Json 파싱 오류") + , ERR506("Hash 생성 오류") + , ERR507("유효하지 않은 데이터") + , ERR511("JSON 형식으로 변환 실패") + , ERR521("방화벽 설정 오류") + , ERR540("중복된 데이터") + , ERR600("API 오류") + , ERR601("API서버 응답 오류") + , ERR602("API서버 내부 오류") + , ERR603("유효하지 않은 토큰(OTT) 값") + , 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") //json 변환 실패 + , BILL511("청구서 URL 생성 병렬처리 중 ERROR") + , BILL512("청구서 URL 생성 실패") + , BILL601("json parsing fail") //json 분석 실패 + , BILL602("http status failure response") //http staus 오류 + , 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..ef51f0b --- /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) + .kkoBpCsignPrepayApi(kkoBpPrepayApi) + .kkoBpCsignPayResultApi(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/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/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..3576bce --- /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.modules.common.ctgy.intgrnbill.BillAcptReqDTO; +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},\"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\",\"properties\":{\"billSe\":\"bpKko\"}}]}") + 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 BillAcptReqDTO 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..160194d --- /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..9551480 --- /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..57e4c9e --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/CmmnUtil.java @@ -0,0 +1,211 @@ + +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. + * @apiNote: 사이트 참조 https://e2e2e2.tistory.com/15 + */ + 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); + + } 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..4f68733 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/DateUtil.java @@ -0,0 +1,379 @@ + +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..1f3fdff --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/IdGenerator.java @@ -0,0 +1,91 @@ +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..ae4b694 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/JwtUtil.java @@ -0,0 +1,112 @@ +package cokr.xit.ens.core.utils; + +import java.util.Base64; +import java.util.Date; +import java.util.Iterator; +import java.util.Map; +import java.util.Base64.Decoder; + +import org.springframework.util.StringUtils; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.Claim; + +import lombok.Builder; +import lombok.Getter; + +@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..d1abb9d --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/MapDeserailizer.java @@ -0,0 +1,57 @@ +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..522cb25 --- /dev/null +++ b/src/main/java/cokr/xit/ens/core/utils/RequireValidator.java @@ -0,0 +1,79 @@ +package cokr.xit.ens.core.utils; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; + +import org.springframework.util.StringUtils; + +import lombok.Builder; +import lombok.Getter; + +@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..3b1cf98 --- /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_kko_nv_req_his") + ,SendDetailNvSigntalkStatHist("ens_snd_dtl_kko_nv_stat_his") + ,SendDetailNvSigntalkTokenHist("ens_snd_dtl_kko_nv_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/BillAcptReqDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillAcptReqDTO.java new file mode 100644 index 0000000..7198ce4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillAcptReqDTO.java @@ -0,0 +1,38 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoAcptReqVO; +import com.fasterxml.jackson.annotation.JsonAlias; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +@Builder +@Getter +@Setter +@Schema(name = "BillAcptReqDTO") +public class BillAcptReqDTO { + + @NotNull(message = "청구서ID 사용 여부는 필수 입력값 입니다.") + @Schema(required = true, title = "청구서ID 사용 여부", example = "false") + private Boolean use_bill_uid; + + @Schema(required = false, title = "청구서 유니크ID", example = " ") + private String bill_uid; + + @NotNull + @Schema(required = true, title = "청구서 타입", example = "all") + private BillSeCd bill_se; + + @Valid + @JsonAlias({"bill_kko"}) + private BillKkoAcptReqVO bill_kko; +// @Valid +// @JsonAlias({"bill_nv"}) +// private BillNvAcptReqVO bill_nv; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillAcptReqData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillAcptReqData.java new file mode 100644 index 0000000..4434b8b --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillAcptReqData.java @@ -0,0 +1,6 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill; + +public interface BillAcptReqData { + + T get(); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillMakerSupport.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillMakerSupport.java new file mode 100644 index 0000000..ba0f20a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillMakerSupport.java @@ -0,0 +1,127 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill; + +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.ctgy.intgrnbill.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.Bill; +import cokr.xit.ens.modules.common.monitor.MessageByBill; +import com.google.common.collect.Lists; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +public abstract class BillMakerSupport implements Consumer>, Function, EnsResponseVO> { + + @Autowired + private ApplicationEventPublisher applicationEventPublisher; + + @Transactional + @Override + public void accept(List bills) { + try { + Lists.partition(filter(bills), 500).stream() + .forEach(partBillUids -> { + List partBills = findBillsByBillUidsAndNotExists(partBillUids); + acceptProc(partBills); + }); + } catch (EnsException e) { + throw e; + } catch (Exception e) { + throw new EnsException(EnsErrCd.BILL999, e.getMessage()); + } + + } + + @Transactional(propagation = Propagation.REQUIRES_NEW) + @Override + public EnsResponseVO apply(List bills) { + try { + if (CmmnUtil.isEmpty(bills)) + return EnsResponseVO.okBuilder().build(); + + int cntTotFail = Lists.partition(filter(bills), 500).stream() + .map(partBillUids -> { + List partBills = findBillsByBillUidsAndUrlIsNull(partBillUids); + if (partBills.size() == 0) + return 0; + + + return generateUrlProc(partBills); + }) + .reduce(Integer::sum) + .get(); + + + if (cntTotFail == 0) + return EnsResponseVO.okBuilder().build(); + else + return EnsResponseVO.errBuilder() + .errCode(EnsErrCd.BILL512) + .errMsg(String.format("총 %d건 중 %d건 생성 실패", bills.size(), cntTotFail)) + .build(); + } catch (EnsException e) { + return EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + } catch (Exception e) { + return EnsResponseVO.errBuilder() + .errCode(EnsErrCd.BILL999) + .errMsg(e.getMessage()) + .build(); + } + } + + abstract protected BillSeCd getBillSeCd(); + + abstract protected List filter(List bills); + + /** + * 청구서 접수 처리 + * @param bills + * @throws EnsException + */ + abstract protected void acceptProc(List bills) throws EnsException; + + /** + * 미접수 청구서 조회 + * @param billUids + * @return + */ + abstract protected List findBillsByBillUidsAndNotExists(List billUids); + + /** + * 청구서 URL 생성 처리 + * @param bills + * @return + */ + abstract protected int generateUrlProc(List bills); + + /** + * URL 미생성 청구서 조회 + * @param billUids + * @return + */ + abstract protected List findBillsByBillUidsAndUrlIsNull(List billUids); + + protected void errSend(EnsErrCd ensErrCd, String message, Exception e) { + + applicationEventPublisher.publishEvent(MonitorEvent.builder() + .message(MessageByBill.builder() + .oClass(getClass().getSimpleName() + "." + new Throwable().getStackTrace()[0].getMethodName()) + .billSeCd(getBillSeCd()) + .errCd(ensErrCd) + .message(message + "\n" + CmmnUtil.printStackTraceToString(e)) + .build()) + .build()); + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillService.java new file mode 100644 index 0000000..543383b --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillService.java @@ -0,0 +1,8 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill; + +public interface BillService { + T accept(ACPTREQ acptreq); + + T createUrl(URLREQ urlreq); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillUrlReqData.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillUrlReqData.java new file mode 100644 index 0000000..653e821 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/BillUrlReqData.java @@ -0,0 +1,6 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill; + +public interface BillUrlReqData { + + T get(); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/code/BillReqSeCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/code/BillReqSeCd.java new file mode 100644 index 0000000..9536e11 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/code/BillReqSeCd.java @@ -0,0 +1,41 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *
    + *
  • 업무 그룹명: 청구서API - 요청구분 코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2022. 2. 15. 오후 3:51:43 + *
+ * @author 박민규 + */ + +public enum BillReqSeCd implements CodeMapperType { + + ACPT("요청 접수") + ,URL("청구서링크생성") + ,REURL("청구서링크재생성") + ,NOTICE("청구서조회") + ,PREPAY("납부가능조회") + ,PAYRSLT("납부결과전달") + ; + + 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/code/BillSeCd.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/code/BillSeCd.java new file mode 100644 index 0000000..e8d0411 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/code/BillSeCd.java @@ -0,0 +1,38 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.code; + +import cokr.xit.ens.core.code.CodeMapperType; + + +/** + *
    + *
  • 업무 그룹명: 청구서API - 청구서 구분 코드
  • + *
  • 설 명:
  • + *
  • 작성일: 2022. 9. 20. 오후 3:51:43 + *
+ * + * @author 박민규 + */ +public enum BillSeCd implements CodeMapperType { + + bpKko("카카오페이"), + bpNv("네이버페이"), + 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/entity/Bill.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/Bill.java new file mode 100644 index 0000000..a230795 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/Bill.java @@ -0,0 +1,50 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.entity; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillSeCd; +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 = "") +public class Bill extends BillEntity 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) + + private Long billId; + + @Enumerated(EnumType.STRING) + + @Column(name = "bill_se_cd") + private BillSeCd billSeCd; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "org_cd") + @Setter + private OrgMng orgMng; + + + @Column(name = "doc_bill_kko", nullable = true) + @Lob + private String docBillKko; + + + @Column(name = "doc_bill_nv", nullable = true) + @Lob + private String docBillNv; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/BillEntity.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/BillEntity.java new file mode 100644 index 0000000..13adf29 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/BillEntity.java @@ -0,0 +1,22 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.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 BillEntity extends BaseEntity { + + @Column(name = "bill_uid", nullable = true, unique = true, length = 45) + private String billUid; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/BillHist.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/BillHist.java new file mode 100644 index 0000000..2b8ee12 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/BillHist.java @@ -0,0 +1,70 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.entity; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillSeCd; +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") +}) +public class BillHist extends BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id", nullable = false) + + private Long id; + + + @Column(name = "bill_uid", nullable = true, unique = false, length = 45) + private String billUid; + + + @Column(name = "bill_se", nullable = false) + @Enumerated(EnumType.STRING) + private BillSeCd billSe; + + + @Column(name = "req_se", nullable = false) + @Enumerated(EnumType.STRING) + private BillReqSeCd reqSe; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "org_cd") + + private OrgMng orgMng; + + + @Column(name = "linked_uuid") + @Setter + private String linkedUuid; + + + @Column(name = "request_data", nullable = true) + @Lob + private String requestData; + + + @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/entity/repository/BillHistRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/repository/BillHistRepository.java new file mode 100644 index 0000000..4dc0b77 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/repository/BillHistRepository.java @@ -0,0 +1,9 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.repository; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.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/entity/repository/BillRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/repository/BillRepository.java new file mode 100644 index 0000000..1016852 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/repository/BillRepository.java @@ -0,0 +1,16 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.repository; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.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/entity/repository/BillSeRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/repository/BillSeRepository.java new file mode 100644 index 0000000..b58472e --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/entity/repository/BillSeRepository.java @@ -0,0 +1,10 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.repository; + +public interface BillSeRepository { + + String findUrlByBillUid(String billUid); + + + + +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoApi.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoApi.java new file mode 100644 index 0000000..67b1161 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoApi.java @@ -0,0 +1,168 @@ +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 BillKkoApi implements BillKkoApiSpec { + + @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"))); + 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; + } + + + /** + *
메소드 설명: 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(2000); +// factory.setReadTimeout(2000); + 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("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; + } + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoApiSpec.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoApiSpec.java new file mode 100644 index 0000000..c2d83f2 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoApiSpec.java @@ -0,0 +1,27 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.api; + +import org.springframework.http.ResponseEntity; + +public interface BillKkoApiSpec { + + /** + * 청구서링크 생성 + * + * @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/BillKkoApiTest.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoApiTest.java new file mode 100644 index 0000000..a7a01a8 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoApiTest.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 BillKkoApiTest implements BillKkoApiSpec { + + @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/api/BillKkoClientApi.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoClientApi.java new file mode 100644 index 0000000..6b0e112 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoClientApi.java @@ -0,0 +1,190 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.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 BillKkoClientApi implements BillKkoClientApiSpec { + + /** + * 고객사별 납부가능조회 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/modules/common/ctgy/intgrnbill/kko/api/BillKkoClientApiSpec.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoClientApiSpec.java new file mode 100644 index 0000000..dba42fd --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoClientApiSpec.java @@ -0,0 +1,17 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.api; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoApiRespDTO; + +import java.util.Map; + +public interface BillKkoClientApiSpec { + + /** + * 고객사별 납부가능조회 API 호출 + * + * @param uri + * @param mParam + * @return + */ + BillKkoApiRespDTO callApiByOrg(String uri, Map mParam); +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoClientApiTest.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoClientApiTest.java new file mode 100644 index 0000000..3e42f24 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/api/BillKkoClientApiTest.java @@ -0,0 +1,104 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.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 BillKkoClientApiTest implements BillKkoClientApiSpec { + + /** + * 고객사별 납부가능조회 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/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/BillKko.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/BillKko.java new file mode 100644 index 0000000..a0d7110 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/BillKko.java @@ -0,0 +1,69 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.BillEntity; +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 = "BillKko") +public class BillKko extends BillEntity { + @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 = true, title = "기관에서 관리하는 해당 고객번호 혹은 계약번호", example = " ") + @Column(name = "biller_user_key", nullable = false, length = 40) + private String billerUserKey; + + @Schema(required = false, title = "청구 연월", example = " ") + @Column(name = "billed_year_month", nullable = true) + private String billedYearMonth; + + @Schema(required = false, title = "동일 고객번호 구분 값", example = " ") + @Column(name = "ordinal", nullable = true) + private String ordinal; + + @Schema(required = false, title = "개별 청구서를 식별하는 키 값", example = " ") + @Column(name = "biller_notice_key", nullable = true) + private String billerNoticeKey; + + @Schema(required = true, title = "URL 만료일", example = "20200130235959") + @Column(name = "expire_at", nullable = false) + private String expireAt; + + @Schema(required = false, title = "API 호출 시 함께 전달할 JSON형태의 문자열", example = " ") + @Column(name = "parameters", nullable = true) + @Lob + 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) + private String customUrl; + + @Schema(required = false, title = "청구서URL", example = " ") + @Column(name = "url", nullable = true) + @Setter + private String url; + + @Embedded + @Setter + private FieldError error; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillKkoRepository.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillKkoRepository.java new file mode 100644 index 0000000..a10f45b --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillKkoRepository.java @@ -0,0 +1,12 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.repository; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.BillKko; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface BillKkoRepository extends JpaRepository, BillKkoRepositoryCustom { + + Optional findByBillUid(String billUid); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillKkoRepositoryCustom.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillKkoRepositoryCustom.java new file mode 100644 index 0000000..8f840c3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillKkoRepositoryCustom.java @@ -0,0 +1,11 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.repository; + +import java.util.List; + +public interface BillKkoRepositoryCustom { + + List findBillUidsByBillUidIn(List billUids); + + List findBillerUserKeysByBillerUserKeyIn(List billerUserKeys); + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillKkoRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillKkoRepositoryImpl.java new file mode 100644 index 0000000..96b8354 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillKkoRepositoryImpl.java @@ -0,0 +1,42 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.repository; + +import com.google.common.collect.Lists; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +import static cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.QBillKko.billKko; + +@RequiredArgsConstructor +public class BillKkoRepositoryImpl implements BillKkoRepositoryCustom { + + private final JPAQueryFactory query; + + @Override + public List findBillUidsByBillUidIn(List billUids) { + List result = new ArrayList<>(); + Lists.partition(billUids, 1000) + .forEach(ids -> result.addAll( + query.select(billKko.billUid) + .from(billKko) + .where(billKko.billUid.in(ids)) + .fetch()) + ); + return result; + } + + @Override + public List findBillerUserKeysByBillerUserKeyIn(List billerUserKeys) { + List result = new ArrayList<>(); + Lists.partition(billerUserKeys, 1000) + .forEach(ids -> result.addAll( + query.select(billKko.billerUserKey) + .from(billKko) + .where(billKko.billerUserKey.in(ids)) + .fetch()) + ); + return result; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillSeKkoRepositoryImpl.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillSeKkoRepositoryImpl.java new file mode 100644 index 0000000..d534dc7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/entity/repository/BillSeKkoRepositoryImpl.java @@ -0,0 +1,26 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.repository; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.repository.BillSeRepository; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import static cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.QBillKko.billKko; + +@Repository(value = "bpKko") +@RequiredArgsConstructor +public class BillSeKkoRepositoryImpl implements BillSeRepository { + + private final JPAQueryFactory query; + + @Override + public String findUrlByBillUid(String billUid) { + String url = query.select(billKko.url) + .from(billKko) + .where(billKko.billUid.eq(billUid) + .and(billKko.url.isNotNull()) + ) + .fetchOne(); + return url; + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoAcptReqDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoAcptReqDTO.java new file mode 100644 index 0000000..9f86e7f --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoAcptReqDTO.java @@ -0,0 +1,32 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model; + +import com.fasterxml.jackson.annotation.JsonAlias; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; + +@Builder +@Getter +@Setter +@Schema(name = "BillKkoAcptReqDTO") +public class BillKkoAcptReqDTO { + + @NotBlank(message = "(계약정보)빌러코드는 필수 입력값 입니다.") + @Schema(required = true, title = "(계약정보)빌러코드", example = "LIF378880088002") + @JsonAlias({"biller_code"}) + private String billerCode; + + @NotBlank(message = "(계약정보)허가코드는 필수 입력값 입니다.") + @Schema(required = true, title = "(계약정보)허가코드", example = "LG7upsMTsXbQiMGP4htZi/IXS7LJvEOmAx2HmY6X6Q8jh1dpv6vgNxbA4a4H2n3r") + @JsonAlias({"authorization"}) + private String authorization; + + @Valid + @JsonAlias({"documents"}) + private BillKkoAcptReqVO documents; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoAcptReqVO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoAcptReqVO.java new file mode 100644 index 0000000..1937ecc --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoAcptReqVO.java @@ -0,0 +1,68 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.config.CustomUrl; +import com.fasterxml.jackson.annotation.JsonAlias; +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.Valid; +import javax.validation.constraints.NotEmpty; +import java.util.Map; + +@Builder +@Getter +@Schema(name = "BillKkoAcptReqVO") +public class BillKkoAcptReqVO { + + @Length(max = 45, message = "청구서 유니크 아이디의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "청구서 유니크 아이디", example = " ") + @JsonAlias({"bill_uid"}) + @Setter + private String billUid; + + @NotEmpty(message = "계약번호는 필수 입력값 입니다.") + @Length(max = 50, message = "계약번호의 최대 길이를 초과 했습니다.") + @Schema(required = true, title = "기관에서 관리하는 해당 고객번호 혹은 계약번호", example = " ") + @JsonAlias({"biller_user_key"}) + private String billerUserKey; + + @Length(max = 6, message = "청구연월의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "청구 연월", example = "202203") + @JsonAlias({"billed_year_month"}) + private String billedYearMonth; + + @Length(max = 24, message = "고객번호구분값의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "동일 고객번호 구분 값", example = " ") + @JsonAlias({"ordinal"}) + private String ordinal; + + @Length(max = 80, message = "개별청구서식별키의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "개별 청구서를 식별하는 키 값", example = " ") + @JsonAlias({"biller_notice_key"}) + private String billerNoticeKey; + + @NotEmpty(message = "URL만료일은 필수 입력값 입니다.") + @Schema(required = true, title = "URL 만료일", example = "20200130235959") + @JsonAlias({"expire_at"}) + private String expireAt; + + +// @Valid +// private Parameters parameters; + @Schema(required = false, title = "API 호출 시 함께 전달할 JSON형태의 문자열", example = "{\"some_param\": \"...\"}") + @JsonAlias({"parameters"}) + private Map parameters; + + +// " \"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" + +// " }") + @Valid + @JsonAlias({"custom_url"}) + private CustomUrl customUrl; + +} 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/BillKkoPayResultDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoPayResultDTO.java new file mode 100644 index 0000000..1a8e304 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoPayResultDTO.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 = "BillKkoPayResultDTO") +public class BillKkoPayResultDTO { + + @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/model/BillKkoRsltFwdFailDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoRsltFwdFailDTO.java new file mode 100644 index 0000000..1eac94a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoRsltFwdFailDTO.java @@ -0,0 +1,25 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "BillKkoRsltFwdFailDTO") +public class BillKkoRsltFwdFailDTO { + + @Schema(title = "기관코드", example = " ") + private String org_cd; + @Schema(title = "기관코드명", example = " ") + private String org_nm; + @Schema(title = "빌러유저키", example = " ") + private List biller_user_key; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoRsltFwdFailSearchDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoRsltFwdFailSearchDTO.java new file mode 100644 index 0000000..3958c58 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoRsltFwdFailSearchDTO.java @@ -0,0 +1,18 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import java.util.List; + +@Builder +@Data +@Schema(name = "BillKkoRsltFwdFailSearchDTO") +public class BillKkoRsltFwdFailSearchDTO { + + @Schema(title = "기관코드", example = "[]") + private List schOrgCd; + @Schema(title = "기관코드명", example = "[]") + private List schOrgNm; +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoUrlReqDTO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoUrlReqDTO.java new file mode 100644 index 0000000..750e5a7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoUrlReqDTO.java @@ -0,0 +1,32 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model; + +import com.fasterxml.jackson.annotation.JsonAlias; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Builder +@Data +@Schema(name = "BillKkoUrlReqDTO") +public class BillKkoUrlReqDTO { + + @NotBlank(message = "(계약정보)빌러코드는 필수 입력값 입니다.") + @Schema(required = true, title = "(계약정보)빌러코드", example = "LIF378880088002") + @JsonAlias({"biller_code"}) + private String billerCode; + + @NotBlank(message = "(계약정보)허가코드는 필수 입력값 입니다.") + @Schema(required = true, title = "(계약정보)허가코드", example = "LG7upsMTsXbQiMGP4htZi/IXS7LJvEOmAx2HmY6X6Q8jh1dpv6vgNxbA4a4H2n3r") + @JsonAlias({"authorization"}) + private String authorization; + + @NotNull(message = "청구서 유니크 아이디는 필수 입력값 입니다.") + @Schema(required = false, title = "청구서 유니크 아이디", example = " ") + @JsonAlias({"bill_uids"}) + private List billUids; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoUrlReqVO.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoUrlReqVO.java new file mode 100644 index 0000000..379fb49 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/BillKkoUrlReqVO.java @@ -0,0 +1,33 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillReqSeCd; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Builder +@Data +@Schema(name = "BillKkoUrlReqVO") +public class BillKkoUrlReqVO { + + @NotNull(message = "요청구분은 필수 입력값 입니다.") + @Schema(required = true, title = "요청구분", example = "URL") + private BillReqSeCd reqSe; + + @NotBlank(message = "(계약정보)빌러코드는 필수 입력값 입니다.") + @Schema(required = true, title = "(계약정보)빌러코드", example = " ") + private String billerCode; + + @NotBlank(message = "(계약정보)허가코드는 필수 입력값 입니다.") + @Schema(required = true, title = "(계약정보)허가코드", example = " ") + private String authorization; + + @Length(max = 45, message = "청구서 유니크 아이디의 최대 길이를 초과 했습니다.") + @Schema(required = false, title = "청구서 유니크 아이디", example = " ") + private String billUid; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/config/CustomUrl.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/config/CustomUrl.java new file mode 100644 index 0000000..2477d1e --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/model/config/CustomUrl.java @@ -0,0 +1,35 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.config; + +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({"notice_url"}) + @SerializedName("notice_url") + private String noticeUrl; + + @NotEmpty(message = "납부가능조회URL은 필수 입력값 입니다.") + @Schema(required = true, title = "납부 가능 조회 URL", example = "http://wwww.xit.co.kr/kakao/prepay") + @JsonAlias({"prepay_url"}) + @SerializedName("prepay_url") + private String prepayUrl; + + @NotEmpty(message = "납부결과전달URL은 필수 입력값 입니다.") + @Schema(required = true, title = "납부 결과 전달 URL", example = "http://wwww.xit.co.kr/kakao/pay-result") + @JsonAlias({"pay_result_url"}) + @SerializedName("pay_result_url") + private String payResultUrl; + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/presentation/BillKkoClientController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/presentation/BillKkoClientController.java new file mode 100644 index 0000000..83b8e0e --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/presentation/BillKkoClientController.java @@ -0,0 +1,114 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.presentation; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoRsltFwdFailSearchDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.impl.BillKkoClientServiceImpl; +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.*; + +import java.util.List; +import java.util.Map; + +@Tag(name = "BillKkoClientController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class BillKkoClientController { + + private final BillKkoClientServiceImpl billKkoClientServiceImpl; + + + @Operation(summary = "납부결과 전달실패 자료 조회") + @GetMapping(value = "/bill/kko/fwd/fail/{orgCd}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity findAllByFwdFail(@PathVariable String orgCd) { + + EnsResponseVO responseVO = billKkoClientServiceImpl.findBillerUserKeysByOrgCdAndPayresultFwdFail(orgCd); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "납부결과 전달실패 자료 조회(일괄)") + @PostMapping(value = "/bill/kko/fwd/fail/bulk", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity findAllByFwdFailBulk(@RequestBody BillKkoRsltFwdFailSearchDTO searchDTO) { + + EnsResponseVO responseVO = billKkoClientServiceImpl.findBillerUserKeysBySearchDTOAndPayresultFwdFail(searchDTO); + + 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 = "sample" + , value = "{ \"org_cd\" : \"EX_ORG001\", \"biller_user_key\" : [\"a1b2c3d4e5f6g7h8i9j0\", \"A1B2C3D4E5F6G7H8I9J0\"] }") + }) + }) + @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 = "/bill/kko/fwd/pay-reuslt", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity fwdPayRslt(@RequestBody Map mParam) { + + EnsResponseVO responseVO = billKkoClientServiceImpl.fwdPayRslt((String) mParam.get("org_cd"), (List) mParam.get("biller_user_key")); + + + 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 = "sample" + , value = "{ \"targets\" : [{\"org_cd\" : \"EX_ORG001\", \"biller_user_key\" : [\"a1b2c3d4e5f6g7h8i9j0\", \"A1B2C3D4E5F6G7H8I9J0\"]}, {\"org_cd\" : \"0001\", \"biller_user_key\" : [\"fffffffffffffffffffff\"]} ] }") + }) + }) + @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 = "/bill/kko/fwd/pay-reuslt/bulk", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity fwdPayRsltBulk(@RequestBody Map mParam) { + + List> targets = (List>) mParam.get("targets"); + + EnsResponseVO responseVO = billKkoClientServiceImpl.fwdPayRsltBulk(targets); + + + return new ResponseEntity(responseVO, HttpStatus.OK); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/presentation/BillKkoController.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/presentation/BillKkoController.java new file mode 100644 index 0000000..cce9126 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/presentation/BillKkoController.java @@ -0,0 +1,118 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.presentation; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.core.exception.code.EnsErrCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.BillAcptReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.BillUrlReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.BillKko; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoAcptReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoAcptReqVO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoUrlReqDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoUrlReqVO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.BillKkoService; +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.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; +import java.util.stream.Collectors; + +@Tag(name = "BillKkoController") +@Slf4j +@RequiredArgsConstructor +@RestController +public class BillKkoController { + + private final BillKkoService billKkoService; + + @Operation(summary = "청구서링크 생성") + @PostMapping(value = "/bill/kko/url/bulk", produces = MediaType.APPLICATION_JSON_VALUE) + @Transactional + public ResponseEntity url(@RequestBody BillKkoAcptReqDTO reqDTO) { + BillAcptReqData acptreq = new BillAcptReqData() { + @Override + public BillKkoAcptReqVO get() { + return reqDTO.getDocuments(); + } + }; + EnsResponseVO responseVO = billKkoService.accept(Arrays.asList(acptreq)); + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) + return new ResponseEntity(responseVO, HttpStatus.OK); + List> result = (List>) responseVO.getResultInfo(); + + List> resultInfo = result.stream() + .map(m -> { + Set billerUserKeys = m.keySet(); + return billerUserKeys.stream() + .map(billerUserKey -> { + Map mOutput = new HashMap<>(); + this.callUrlCreate(BillReqSeCd.URL, reqDTO.getBillerCode(), reqDTO.getAuthorization(), m.get(billerUserKey), mOutput); + mOutput.put("biller_user_key", billerUserKey); + mOutput.put("bill_uid", m.get(billerUserKey)); + return mOutput; + }) + .collect(Collectors.toList()); + }).collect(Collectors.toList()) + .get(0); + responseVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + @Operation(summary = "청구서링크 재생성") + @PostMapping(value = "/bill/kko/re/url/bulk", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity reUrl(@RequestBody BillKkoUrlReqDTO reqDTO) { + + List> resultInfo = reqDTO.getBillUids().stream() + .map(billUid -> { + Map mOutput = new HashMap<>(); + this.callUrlCreate(BillReqSeCd.REURL, reqDTO.getBillerCode(), reqDTO.getAuthorization(), billUid, mOutput); + mOutput.put("bill_uid", billUid); + return mOutput; + }) + .collect(Collectors.toList()); + + + EnsResponseVO responseVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + + + return new ResponseEntity(responseVO, HttpStatus.OK); + } + + private void callUrlCreate(BillReqSeCd billReqSeCd, String billerCode, String authorization, String billUid, Map mOutput) { + + BillUrlReqData urlreq = new BillUrlReqData() { + @Override + public BillKkoUrlReqVO get() { + return BillKkoUrlReqVO.builder() + .reqSe(billReqSeCd) + .billerCode(billerCode) + .authorization(authorization) + .billUid(billUid) + .build(); + } + }; + + try { + EnsResponseVO response = billKkoService.createUrl(urlreq); + mOutput.put("errCode", response.getErrCode().getCode()); + mOutput.put("errMsg", response.getErrMsg()); + if (EnsErrCd.OK.equals(response.getErrCode())) + mOutput.put("url", ((BillKko) response.getResultInfo()).getUrl()); + + } catch (Exception e) { + mOutput.put("errCode", EnsErrCd.ERR999); + mOutput.put("errMsg", "청구서링크 생성 실패. " + e.getMessage()); + } + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/BillKkoClientApiSpec.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/BillKkoClientApiSpec.java new file mode 100644 index 0000000..768c6b4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/BillKkoClientApiSpec.java @@ -0,0 +1,35 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service; + +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoApiRespDTO; + +import java.util.Map; + +public interface BillKkoClientApiSpec { + + + /** + * 청구서 조회 + * + * @param mParam + * @return + */ + BillKkoApiRespDTO findNoticeInfo(Map mParam); + + /** + * 납부 가능 조회 + * + * @param mParam + * @return + */ + BillKkoApiRespDTO findPrepayInfo(Map mParam); + + /** + * 납부결과 저장 + * + * @param mParam + * @return + */ + BillKkoApiRespDTO addPayReultIfno(Map mParam); + + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/BillKkoClientApiSupport.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/BillKkoClientApiSupport.java new file mode 100644 index 0000000..6f2942b --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/BillKkoClientApiSupport.java @@ -0,0 +1,158 @@ +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.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoApiRespDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoRsltFwdFailDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoRsltFwdFailSearchDTO; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +import cokr.xit.ens.modules.common.domain.support.FieldError; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.Tuple; +import com.querydsl.core.types.dsl.CaseBuilder; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.stream.Collectors; + +import static cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.QBillHist.billHist; +import static cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng.orgMng; + +@Slf4j +@Component +public abstract class BillKkoClientApiSupport implements BillKkoClientApiSpec { + + @Autowired + private JPAQueryFactory query; + @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 respVO + * @param errCd + * @param errMsg + */ + protected void modifyBillHistByRespInfo(BillHist billHist, BillKkoApiRespDTO respVO, EnsErrCd errCd, String errMsg) { + billHist.setResponseData(CmmnUtil.toJsonString(respVO)); + billHist.setError(FieldError.initBuilder() + .errorCode(CmmnUtil.isEmpty(errCd) ? null : errCd.getCode()) + .errorMessage(errMsg) + .build()); + billHistRepository.save(billHist); + } + + + protected Optional findByOrgMngAndBillerUserKeyAndReqSeAndLast(OrgMng orgMng, String billerUserKey, BillReqSeCd reqSeCd) { + return Optional.ofNullable(query.selectFrom(billHist) + .where( + billHist.orgMng.eq(orgMng) + .and(billHist.linkedUuid.eq(billerUserKey)) + .and(billHist.billSe.eq(BillSeCd.bpKko)) + .and(billHist.reqSe.eq(reqSeCd)) + ) + .orderBy(billHist.id.desc()) + .fetchFirst()); + } + + protected BillKkoRsltFwdFailDTO findBillerUserKeysByPayresultFwdFailAndOrgCd(String orgCd) { + BillKkoRsltFwdFailSearchDTO searchDTO = BillKkoRsltFwdFailSearchDTO.builder().schOrgCd(Collections.singletonList(orgCd)).build(); + List result = this.findBillerUserKeysByPayresultFwdFail(searchDTO); + + if (result.size() > 0) + return result.get(0); + else { + OrgMng e = Optional.ofNullable(query.select(orgMng) + .from(orgMng) + .where(orgMng.orgCd.eq(orgCd)) + .fetchOne()) + .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("등록되지 않은 기관(%s) 입니다.", orgCd))); + return BillKkoRsltFwdFailDTO.builder().org_cd(e.getOrgCd()).org_nm(e.getOrgNm()).build(); + } + } + + protected List findBillerUserKeysByPayresultFwdFail(BillKkoRsltFwdFailSearchDTO searchDTO) { + BooleanBuilder builder = new BooleanBuilder(); + builder.and(billHist.billSe.eq(BillSeCd.bpKko)); + builder.and(billHist.reqSe.eq(BillReqSeCd.PAYRSLT)); + 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())); + + + 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")) + )) + ) + .then(1) + .otherwise(0) + .sum().longValue().as("failCnt") + , billHist.orgMng.orgCd + , billHist.orgMng.orgNm + ) + .from(billHist) + .innerJoin(billHist.orgMng, orgMng) + .where(builder) + .groupBy(billHist.orgMng, billHist.linkedUuid, orgMng.orgNm) + .fetch(); + + + Map m = new HashMap<>(); + list.stream() + .filter(tuple -> tuple.get(1, Long.class) == tuple.get(2, Long.class)) + .forEach(tuple -> { + BillKkoRsltFwdFailDTO dto = m.getOrDefault(tuple.get(billHist.orgMng.orgCd), BillKkoRsltFwdFailDTO.builder() + .org_cd(tuple.get(billHist.orgMng.orgCd)) + .org_nm(tuple.get(billHist.orgMng.orgNm)) + .biller_user_key(new ArrayList<>()) + .build()); + dto.getBiller_user_key().add(tuple.get(billHist.linkedUuid)); + m.put(tuple.get(billHist.orgMng.orgCd), dto); + }); + + ObjectMapper mapper = new ObjectMapper(); + return m.keySet().stream() + .map(key -> mapper.convertValue(m.get(key), BillKkoRsltFwdFailDTO.class)) + .collect(Collectors.toList()); + + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/BillKkoService.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/BillKkoService.java new file mode 100644 index 0000000..4300b09 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/BillKkoService.java @@ -0,0 +1,13 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service; + +import cokr.xit.ens.core.aop.EnsResponseVO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.BillAcptReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.BillService; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.BillUrlReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoAcptReqVO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoUrlReqVO; + +import java.util.List; + +public interface BillKkoService extends BillService>, BillUrlReqData> { +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/impl/BillKkoClientServiceImpl.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/impl/BillKkoClientServiceImpl.java new file mode 100644 index 0000000..29efed6 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/impl/BillKkoClientServiceImpl.java @@ -0,0 +1,175 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.impl; + +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.MapDeserailizer; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.api.BillKkoClientApiSpec; +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.BillKkoRsltFwdFailDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoRsltFwdFailSearchDTO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.BillKkoClientApiSupport; +import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng; +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 java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class BillKkoClientServiceImpl extends BillKkoClientApiSupport { + + private final BillKkoClientApiSpec billKkoClientApi; + + private Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).disableHtmlEscaping().create(); + + + /** + * 청구서 조회 + * + * @param mParam + * @return + */ + @Override + @Transactional(propagation = Propagation.NEVER) + public BillKkoApiRespDTO findNoticeInfo(Map mParam) { + return null; + } + + /** + * 납부가능 조회 + * + * @param mParam + * @return + */ + @Override + @Transactional(propagation = Propagation.NEVER) + public BillKkoApiRespDTO findPrepayInfo(Map mParam) { + return null; + } + + /** + * 납부결과 전달 + * + * @param mParam + * @return + */ + @Override + @Transactional(propagation = Propagation.NEVER) + public BillKkoApiRespDTO addPayReultIfno(Map mParam) { + return null; + } + + + @Transactional(readOnly = true) + public EnsResponseVO findBillerUserKeysByOrgCdAndPayresultFwdFail(String orgCd) { + if (CmmnUtil.isEmpty(orgCd)) + throw new EnsException(EnsErrCd.BILL403, "기관코드는 필수조건 입니다."); + + return EnsResponseVO.okBuilder() + .resultInfo(super.findBillerUserKeysByPayresultFwdFailAndOrgCd(orgCd)) + .build(); + } + + @Transactional(readOnly = true) + public EnsResponseVO> findBillerUserKeysBySearchDTOAndPayresultFwdFail(BillKkoRsltFwdFailSearchDTO searchDTO) { + + return EnsResponseVO.>okBuilder().resultInfo(super.findBillerUserKeysByPayresultFwdFail(searchDTO)).build(); + } + + + @Transactional(propagation = Propagation.NEVER) + public EnsResponseVO>> fwdPayRslt(String orgCd, List billerUserKeys) { + + Map result = billerUserKeys.stream() + .map(billerUserKey -> { + Map m = new HashMap<>(); + m.put("key", billerUserKey); + m.put("value", this.fwdPayRsltProc(orgCd, billerUserKey)); + return m; + }) + .collect(Collectors.toMap(m -> (String) m.get("key"), m -> (BillKkoApiRespDTO) m.get("value"), (k1, k2) -> k1)); + + + Map data = new LinkedHashMap<>(); + data.put("org_cd", orgCd); + data.put("biller_user_key", result); + + + BillKkoApiRespDTO resultInfo = BillKkoApiRespDTO.>okBuilder().data(data).build(); + return EnsResponseVO.>>okBuilder().resultInfo(resultInfo).build(); + } + + @Transactional(propagation = Propagation.NEVER) + public EnsResponseVO>>> fwdPayRsltBulk(List> targets) { + List> data = targets.stream() + .map(m -> this.fwdPayRslt((String) m.get("org_cd"), (List) m.get("biller_user_key")).getResultInfo().getData()) + .collect(Collectors.toList()); + + + BillKkoApiRespDTO resultInfo = BillKkoApiRespDTO.okBuilder().data(data).build(); + return EnsResponseVO.>>>okBuilder().resultInfo(resultInfo).build(); + + } + + private BillKkoApiRespDTO fwdPayRsltProc(String orgCd, String billerUserKey) { + BillKkoErrCd billKkoErrCd = BillKkoErrCd.E601; + + BillHist data = super.findByOrgMngAndBillerUserKeyAndReqSeAndLast(OrgMng.builder().orgCd(orgCd).build(), billerUserKey, BillReqSeCd.PAYRSLT).orElse(null); + if (data == null) + return BillKkoApiRespDTO.errDataBuilder() + .resCode(billKkoErrCd.getCode()) + .message(billKkoErrCd.getCodeNm()) + .data(String.format("%s 일치하는 납부결과 자료가 없습니다.", EnsErrCd.BILL404)) + .build(); + + + BillKkoApiRespDTO respVO = null; + BillHist billHist = null; + try { + Map mParam = gson.fromJson(data.getRequestData(), Map.class); + + billHist = this.addBillHistByReqInfo(BillReqSeCd.PAYRSLT, billerUserKey, orgCd, data.getBillUid(), mParam); + + respVO = billKkoClientApi.callApiByOrg(data.getOrgMng().getKkoBpCsignPayresultApi(), mParam); + if (!"OK".equals(respVO.getRes_code())) { + billKkoErrCd = BillKkoErrCd.valueOf(respVO.getRes_code()); + throw new EnsException(EnsErrCd.BILL604, String.format("[%s] %s", respVO.getRes_code(), respVO.getMessage())); + } + + billKkoErrCd = BillKkoErrCd.OK; + this.modifyBillHistByRespInfo(billHist, respVO, null, null); + } catch (EnsException e) { + respVO = BillKkoApiRespDTO.errDataBuilder() + .resCode(billKkoErrCd.getCode()) + .message(billKkoErrCd.getCodeNm()) + .data(e.getMessage()) + .build(); + this.modifyBillHistByRespInfo(billHist, respVO, e.getErrCd(), e.getMessage()); + } catch (Exception e) { + respVO = BillKkoApiRespDTO.errDataBuilder() + .resCode(BillKkoErrCd.E601.getCode()) + .message(BillKkoErrCd.E601.getCodeNm()) + .data(e.getMessage()) + .build(); + this.modifyBillHistByRespInfo(billHist, respVO, EnsErrCd.BILL999, e.getMessage()); + } + + return respVO; + } + +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/impl/BillKkoMaker.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/impl/BillKkoMaker.java new file mode 100644 index 0000000..8cf1b4e --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/impl/BillKkoMaker.java @@ -0,0 +1,163 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.impl; + +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.intgrnbill.BillAcptReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.BillMakerSupport; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.BillUrlReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoAcptReqVO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoUrlReqVO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.BillKkoService; +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.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.stream.Collectors; + +import static cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.QBill.bill; +import static cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.QBillKko.billKko; +import static cokr.xit.ens.modules.common.ctgy.sys.mng.domain.QOrgMng.orgMng; + +@Slf4j +@Component +@RequiredArgsConstructor +public class BillKkoMaker extends BillMakerSupport { + + private final JPAQueryFactory query; + + private Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).disableHtmlEscaping().create(); + private final BillKkoService billKkoService; + + @Value("${app.pallel.thread.bill.cnt}") + private int CNT_THREAD; + + + @Override + protected BillSeCd getBillSeCd() { + return BillSeCd.bpKko; + } + + @Override + protected List filter(List bills) { + return bills.stream() + .filter(bill -> bill.getDocBillKko() != null) + .map(Bill::getBillUid) + .collect(Collectors.toList()); + } + + @Override + protected void acceptProc(List bills) throws EnsException { + if (bills.size() > 0) { + List> acptreqs = bills.stream() + .map(bill -> { + BillAcptReqData acptreq = new BillAcptReqData() { + @Override + public BillKkoAcptReqVO get() { + BillKkoAcptReqVO billKkoAcptReqVO = gson.fromJson(bill.getDocBillKko(), BillKkoAcptReqVO.class); + billKkoAcptReqVO.setBillUid(bill.getBillUid()); + return billKkoAcptReqVO; + } + }; + return acptreq; + }) + .collect(Collectors.toList()); + EnsResponseVO responseVO = billKkoService.accept(acptreqs); + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) +// throw new EnsException(EnsErrCd.ACPT412, String.format("[%s] %s", responseVO.getErrCode(), responseVO.getErrMsg())); + throw new EnsException(responseVO.getErrCode(), responseVO.getErrMsg()); + } + + } + + @Override + protected List findBillsByBillUidsAndNotExists(List billUids) { + return query.select(bill) + .from(bill) + .innerJoin(bill.orgMng, orgMng).fetchJoin() + .leftJoin(billKko).on(bill.billUid.eq(billKko.billUid)).fetchJoin() + .where(bill.billUid.in(billUids) + .and(bill.docBillKko.isNotNull()) + .and(bill.billSeCd.in(Arrays.asList(BillSeCd.bpKko, BillSeCd.all))) + .and(billKko.billId.isNull()) + ) + .fetch(); + } + + + @Override + protected int generateUrlProc(List bills) { + + ForkJoinPool forkJoinPool = new ForkJoinPool(CNT_THREAD); + Optional cntSuccess = Optional.of(0); + try { + cntSuccess = forkJoinPool.submit(() -> { + return bills.stream() + .map(bill -> { + BillUrlReqData urlreq = new BillUrlReqData() { + @Override + public BillKkoUrlReqVO get() { + return BillKkoUrlReqVO.builder() + .reqSe(BillReqSeCd.URL) + .billerCode(bill.getOrgMng().getKkoBpBillerCode()) + .authorization(bill.getOrgMng().getKkoBpAuthorization()) + .billUid(bill.getBillUid()) + .build(); + } + }; + + try { + if (EnsErrCd.OK.equals(billKkoService.createUrl(urlreq).getErrCode())) + return 1; + else + return 0; + } catch (Exception e) { + return 0; + } + }) + .reduce(Integer::sum); + }) + .get(); + + if (bills.size() == cntSuccess.get()) return 0; + else return 1; + } catch (InterruptedException e) { + + forkJoinPool.shutdown(); + this.errSend(EnsErrCd.BILL511, "-.BillUid: " + bills.stream().map(Bill::getBillUid).collect(Collectors.toList()).toString(), e); + return bills.size(); + } catch (ExecutionException e) { + + forkJoinPool.shutdown(); + this.errSend(EnsErrCd.BILL511, "-.BillUid: " + bills.stream().map(Bill::getBillUid).collect(Collectors.toList()).toString(), e); + return bills.size(); + } + } + + + @Override + protected List findBillsByBillUidsAndUrlIsNull(List billUids) { + return query.select(bill) + .from(bill) + .innerJoin(bill.orgMng, orgMng).fetchJoin() + .innerJoin(billKko).on(bill.billUid.eq(billKko.billUid)).fetchJoin() + .where(bill.billUid.in(billUids) + .and(billKko.url.isNull()) + ) + .fetch(); + } +} diff --git a/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/impl/BillKkoServiceImpl.java b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/impl/BillKkoServiceImpl.java new file mode 100644 index 0000000..77951e4 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnbill/kko/service/impl/BillKkoServiceImpl.java @@ -0,0 +1,288 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.impl; + +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.IdGenerator; +import cokr.xit.ens.core.utils.MapDeserailizer; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.BillAcptReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.BillUrlReqData; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillReqSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.code.BillSeCd; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.BillHist; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.repository.BillHistRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.repository.BillRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.api.BillKkoApiSpec; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.BillKko; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.entity.repository.BillKkoRepository; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoAcptReqVO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoUrlReqVO; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.BillKkoService; +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.google.gson.GsonBuilder; +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.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.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class BillKkoServiceImpl implements BillKkoService { + + private final BillRepository billRepository; + private final BillKkoRepository billKkoRepository; + private final BillHistRepository billHistRepository; + private Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).disableHtmlEscaping().create(); + + + private final BillKkoApiSpec billKkoApi; + + + @Override + @Transactional(propagation = Propagation.REQUIRED) + public EnsResponseVO accept(List> acptreqList) { + final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + Map mValidate = new LinkedHashMap<>(); + acptreqList.forEach(reqData -> { + Set> list = validator.validate(reqData.get()); + if (list.size() > 0) { + { + mValidate.put(reqData.get().getBillerUserKey(), EnsResponseVO.errRsltBuilder() + .errCode(EnsErrCd.BILL405) + .errMsg("유효하지 않은 요청값 입니다.") + .resultInfo(list.stream() + .map(row -> String.format("%s [ %s ]", row.getMessageTemplate(), row.getPropertyPath())) + .collect(Collectors.toList())) + .build()); + } + } + }); + if (!mValidate.isEmpty()) + return EnsResponseVO.errRsltBuilder().errCode(EnsErrCd.BILL403).errMsg("유효하지 않은 청구서생성 요청값이 포함되어 있습니다.").resultInfo(mValidate).build(); + + List billUids = acptreqList.stream() + .filter(reqData -> reqData.get().getBillUid() != null) + .map(reqData -> reqData.get().getBillUid()) + .collect(Collectors.toList()); + billUids = billKkoRepository.findBillUidsByBillUidIn(billUids); + if (billUids.size() > 0) + return EnsResponseVO.errRsltBuilder().errCode(EnsErrCd.BILL401).errMsg("이미 등록된 청구서 UniqueID가 있습니다.").resultInfo(billUids).build(); + + List billerUserKeys = acptreqList.stream() + .filter(reqData -> reqData.get().getBillerUserKey() != null) + .map(reqData -> reqData.get().getBillerUserKey()) + .collect(Collectors.toList()); + billerUserKeys = billKkoRepository.findBillerUserKeysByBillerUserKeyIn(billerUserKeys); + if (billerUserKeys.size() > 0) + return EnsResponseVO.errRsltBuilder().errCode(EnsErrCd.BILL402).errMsg("이미 등록된 기관관리번호(=계약번호)가 있습니다.").resultInfo(billerUserKeys).build(); + + + + + String prefix = IdGenerator.getRandomString(6) + "-" + IdGenerator.getCurrentTimeSec(); + List billKkos = acptreqList.stream() + .map(reqData -> reqData.get()) + .map(vo -> BillKko.builder() + .billUid(CmmnUtil.isEmpty(vo.getBillUid()) ? IdGenerator.getShortUUID(prefix) : vo.getBillUid()) + .billerUserKey(vo.getBillerUserKey()) + .billedYearMonth(vo.getBilledYearMonth()) + .ordinal(vo.getOrdinal()) + .billerNoticeKey(vo.getBillerNoticeKey()) + .expireAt(vo.getExpireAt()) + .parameters(CmmnUtil.isEmpty(vo.getParameters()) ? null : gson.toJson(vo.getParameters())) + .customUrl(CmmnUtil.isEmpty(vo.getCustomUrl()) ? null : gson.toJson(vo.getCustomUrl())) + .build()) + .collect(Collectors.toList()); + billKkoRepository.saveAll(billKkos); + List billHists = billKkos.stream() + .map(billKko -> BillHist.builder() + .billUid(billKko.getBillUid()) + .billSe(BillSeCd.bpKko) + .reqSe(BillReqSeCd.ACPT) + .orgMng(null) + .linkedUuid(billKko.getBillerUserKey()) + .requestData(null) + .responseData(null) + .error(null) + .build()) + .collect(Collectors.toList()); + billHistRepository.saveAll(billHists); + + + List> resultInfo = billKkos.stream() + .map(billKko -> { + Map ids = new HashMap<>(); + ids.put(billKko.getBillerUserKey(), billKko.getBillUid()); + return ids; + }) + .collect(Collectors.toList()); + return EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); + } + + @Override + @Transactional(propagation = Propagation.REQUIRED) + public EnsResponseVO createUrl(BillUrlReqData billUrlReqData) { + BillKkoUrlReqVO reqVO = billUrlReqData.get(); + + Bill bill = Bill.builder().build(); + BillKko billKko = null; + BillHist billHist = null; + EnsResponseVO respVO = null; + String requestData = null; + String responseData = null; + try { + if ((BillReqSeCd.URL.equals(reqVO.getBillerCode()) || BillReqSeCd.REURL.equals(reqVO.getBillerCode()))) + throw new EnsException(EnsErrCd.BILL405, "유효하지 않은 요청구분 입니다. 사용가능한 요청구분은 \"URL\" or \"REURL\" 입니다."); + + bill = billRepository.findByBillUid(reqVO.getBillUid()).orElse(Bill.builder().build()); + billKko = billKkoRepository.findByBillUid(reqVO.getBillUid()).orElseThrow(() -> new EnsException(EnsErrCd.BILL404, "일치하는 청구서 자료가 없습니다.")); + if (BillReqSeCd.URL.equals(reqVO.getReqSe()) && !CmmnUtil.isEmpty(billKko.getUrl())) + return EnsResponseVO.okBuilder().resultInfo(billKko).build(); + Map parameters = this.createParameters(billKko, bill.getOrgMng()); + try { + requestData = gson.toJson(parameters); + } catch (Exception e) { + throw new EnsException(EnsErrCd.BILL501, String.format("청구서링크생성 파라미터 JSON 데이터로 변환 실패. [ data %s ]", parameters.toString())); + } + + ResponseEntity resp = BillReqSeCd.URL.equals(reqVO.getReqSe()) + ? billKkoApi.url(reqVO.getBillerCode(), reqVO.getAuthorization(), requestData) + : billKkoApi.reUrl(reqVO.getBillerCode(), reqVO.getAuthorization(), requestData); + responseData = resp.getBody(); + if (resp.getStatusCode() != HttpStatus.OK) + throw new EnsException(EnsErrCd.BILL602, String.format("청구서링크생성 HttpStatus Fail.. [ response raw ]: %s %s", resp.getStatusCode().toString(), responseData)); + Map mResp = null; + try { + mResp = gson.fromJson(responseData, Map.class); + } catch (Exception e) { + throw new EnsException(EnsErrCd.BILL601, String.format("청구서링크생성 JSON 응답 메시지가 유효하지 않습니다. [ response raw ]: %s", responseData)); + } + if (CmmnUtil.isEmpty(mResp.get("data"))) + throw new EnsException(EnsErrCd.BILL603, String.format("청구서링크생성 응답 데이터 중 data 키의 값이 없습니다. [ response raw ]: %s", responseData)); + Map data = (Map) mResp.get("data"); + String url = data.get("url"); + + + billKko.setUrl(url); + billKko.setError(FieldError.initBuilder().build()); + + billHist = BillHist.builder() + .billUid(billKko.getBillUid()) + .billSe(BillSeCd.bpKko) + .reqSe(billUrlReqData.get().getReqSe()) + .orgMng(bill.getOrgMng()) + .linkedUuid(billKko.getBillerUserKey()) + .requestData(CmmnUtil.toJsonString(parameters)) + .responseData(responseData) + .error(FieldError.initBuilder().build()) + .build(); + + + respVO = EnsResponseVO.okBuilder().resultInfo(billKko).build(); + + } catch (EnsException e) { + if (!CmmnUtil.isEmpty(billKko)) { + + billKko.setError(FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()); + + billHist = BillHist.builder() + .billUid(billKko.getBillUid()) + .billSe(BillSeCd.bpKko) + .reqSe(billUrlReqData.get().getReqSe()) + .orgMng(bill.getOrgMng()) + .linkedUuid(billKko.getBillerUserKey()) + .requestData(requestData) + .responseData(responseData) + .error(FieldError.initBuilder() + .errorCode(e.getErrCd().getCode()) + .errorMessage(e.getMessage()) + .build()) + .build(); + } + + respVO = EnsResponseVO.errBuilder() + .errCode(e.getErrCd()) + .errMsg(e.getMessage()) + .build(); + + + if (BillReqSeCd.URL.equals(reqVO.getReqSe()) + && EnsErrCd.BILL602.equals(e.getErrCd()) && e.getMessage().contains("Read timed out")) { + return this.createUrl( + new BillUrlReqData() { + @Override + public BillKkoUrlReqVO get() { + return BillKkoUrlReqVO.builder() + .reqSe(BillReqSeCd.REURL) + .billerCode(reqVO.getBillerCode()) + .authorization(reqVO.getAuthorization()) + .billUid(reqVO.getBillUid()) + .build(); + } + }); + } + } finally { + if (!CmmnUtil.isEmpty(billHist)) + + billHistRepository.save(billHist); + } + + return respVO; + } + + + /** + * 청구서링크생성API body Message로 변환하여 반환 한다. + * + * @param dataset + * @return + */ + private Map createParameters(BillKko dataset, OrgMng orgMng) { + Map parameters = null; + Map customUrl = null; + try { + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + parameters = CmmnUtil.isEmpty(dataset.getParameters()) ? new HashMap<>() : gson.fromJson(dataset.getParameters(), Map.class); + + parameters.put("orgCd", orgMng == null ? null : orgMng.getOrgCd()); +// parameters.put("billUid", dataset.getBillUid()); + customUrl = Optional.ofNullable(dataset.getCustomUrl()).isPresent() ? gson.fromJson(dataset.getCustomUrl(), Map.class) : null; + } catch (Exception e) { + log.info("========================================="); + log.info("청구서링크 제작 중 parameters 변환(Json => Map) 실패."); + log.info("Error: " + e.getMessage()); + log.info("========================================="); + } + + Map data = new HashMap(); + data.put("biller_user_key", dataset.getBillerUserKey()); + data.put("billed_year_month", dataset.getBilledYearMonth()); + data.put("ordinal", dataset.getOrdinal()); + data.put("biller_notice_key", dataset.getBillerNoticeKey()); + data.put("expire_at", dataset.getExpireAt()); + data.put("parameters", parameters); + data.put("custom_url", customUrl); + + + Map m = new HashMap(); + m.put("data", data); + return m; + } +} 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..f156b47 --- /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.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..57615f7 --- /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.modules.common.ctgy.intgrnbill.BillAcptReqDTO; +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},\"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\",\"properties\":{\"billSe\":\"bpKko\"}}]}") + 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 BillAcptReqDTO 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..c05df87 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/presentation/IntgrnNotiMblPageController.java @@ -0,0 +1,75 @@ +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.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; + + + @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(intgrnSendDetail.getCurPostSe())) url = "/kko/mydoc/page/prnt"; +// else if (PostSeCd.nvSigntalk.equals(intgrnSendDetail.getCurPostSe())) url = "/nv/signtalk/page/prnt"; +// else if (PostSeCd.ktSigntalk.equals(intgrnSendDetail.getCurPostSe())) url = "/kt/signtalk/page/prnt"; +// else if (PostSeCd.ktGibis.equals(intgrnSendDetail.getCurPostSe())) url = "/kt/gibis/page/prnt"; + if (PostSeCd.kkoMydoc.equals(postSeCd)) url = "/kko/mydoc/page/prnt"; + else if (PostSeCd.nvSigntalk.equals(postSeCd)) url = "/nv/signtalk/page/prnt"; + else if (PostSeCd.ktSigntalk.equals(postSeCd)) url = "/kt/signtalk/page/prnt"; + else if (PostSeCd.ktGibis.equals(postSeCd)) url = "/kt/gibis/page/prnt"; + 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..825abf1 --- /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()); + 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..a8a1ab7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/strategy/TmpltMngStrategyIntegration.java @@ -0,0 +1,234 @@ +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.ktsigntalk.direct.domain.TmpltMngKtSigntalk; +import cokr.xit.ens.modules.ktsigntalk.direct.model.struct.TmpltMngKtSigntalkMapper; +import cokr.xit.ens.modules.ktsigntalk.gibis.domain.TmpltMngKtGibis; +import cokr.xit.ens.modules.ktsigntalk.gibis.model.struct.TmpltMngKtGibisMapper; +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 cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.TmpltMngKtSigntalkMapper tmpltMngKtSigntalkMapper; + private final cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.TmpltMngKtGibisMapper tmpltMngKtGibisMapper; + 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()); + if (!CmmnUtil.isEmpty(dto.getKtSigntalk())) + this.toMappedChildTmpltMng(dto, dto.getKtSigntalk()); + if (!CmmnUtil.isEmpty(dto.getKtGibis())) + this.toMappedChildTmpltMng(dto, dto.getKtGibis()); + + 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); + } + if (!CmmnUtil.isEmpty(dto.getKtSigntalk())) { + TmpltMngKtSigntalkMapper mapper = Mappers.getMapper(TmpltMngKtSigntalkMapper.class); + TmpltMngKtSigntalk tmpltChild = mapper.toEntity(dto.getKtSigntalk()); + tmpltMngKtSigntalkMapper.add(tmpltChild); + } + if (!CmmnUtil.isEmpty(dto.getKtGibis())) { + TmpltMngKtGibisMapper mapper = Mappers.getMapper(TmpltMngKtGibisMapper.class); + TmpltMngKtGibis tmpltChild = mapper.toEntity(dto.getKtGibis()); + tmpltMngKtGibisMapper.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()))); + if (!"Y".equals(tmpltMng.getUseYn())) + throw new EnsException(EnsErrCd.ERR402, "\"미사용\" 상태의 템플릿은 수정 할 수 없습니다."); + 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); + } + } + + if (!CmmnUtil.isEmpty(dto.getKtSigntalk())) { + TmpltMngKtSigntalkMapper mapper = Mappers.getMapper(TmpltMngKtSigntalkMapper.class); + TmpltMngKtSigntalk tmpltChild = mapper.toEntity(dto.getKtSigntalk()); + if (tmpltMngKtSigntalkMapper.findById(TmpltMngIds.builder().orgMng(dto.getOrgCd()).tmpltCd(dto.getTmpltCd()).build()).isPresent()) { + tmpltChild.setUpdId("ENS_SYS"); + tmpltMngKtSigntalkMapper.modify(tmpltChild); + } else { + tmpltChild.setRegistId("ENS_SYS"); + tmpltMngKtSigntalkMapper.add(tmpltChild); + } + } + + if (!CmmnUtil.isEmpty(dto.getKtGibis())) { + TmpltMngKtGibisMapper mapper = Mappers.getMapper(TmpltMngKtGibisMapper.class); + TmpltMngKtGibis tmpltChild = mapper.toEntity(dto.getKtGibis()); + if (tmpltMngKtGibisMapper.findById(TmpltMngIds.builder().orgMng(dto.getOrgCd()).tmpltCd(dto.getTmpltCd()).build()).isPresent()) { + tmpltChild.setUpdId("ENS_SYS"); + tmpltMngKtGibisMapper.modify(tmpltChild); + } else { + tmpltChild.setRegistId("ENS_SYS"); + tmpltMngKtGibisMapper.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..5c7b216 --- /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 make(); + + 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..6f496ed --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiAcceptor.java @@ -0,0 +1,285 @@ +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.BillMakerSupport; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.Bill; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.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 Map billMakerMap; + 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()) { + bill = billRepository.findByBillUid(document.getXit_property().getBill_acpt_data().getBill_uid()) + .orElseThrow(() -> new RuntimeException("등록된 청구서가 없습니다.")); + } else { + bill = Bill.builder() +// .billId(document.getXit_property().getBill_acpt_data().getBill_id()) + .billId(null) + .billUid(IdGenerator.getShortUUID(prefixBillUid)) + .billSeCd(document.getXit_property().getBill_acpt_data().getBill_se()) + .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()) + ); + billMakerMap.keySet().stream() + .forEach(key -> { + try { + billMakerMap.get(key).accept(bills); + } catch (EnsException e) { + throw new EnsException(EnsErrCd.ACPT412, String.format("[%s] %s", e.getErrCd(), e.getMessage())); + } + }); + + 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..44843d3 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/IntgrnNotiMaker.java @@ -0,0 +1,224 @@ +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.intgrnbill.BillMakerSupport; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.entity.Bill; +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.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class IntgrnNotiMaker extends MakeProcTemplate { + private final Map billMakerMap; + 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())); + + + + try { + List bills = intgrnSendDetails.stream() + .filter(sendDetail -> sendDetail.getBill() != null) + .map(IntgrnSendDetail::getBill) + .collect(Collectors.toList()); + billMakerMap.keySet().stream() + .map(key -> billMakerMap.get(key).apply(bills)) + .forEach(responseVO -> { + if (!EnsErrCd.OK.equals(responseVO.getErrCode())) + throw new EnsException(EnsErrCd.MAKE512, String.format("[%s] %s", responseVO.getErrCode(), responseVO.getErrMsg())); + }); + } catch (EnsException e) { + throw e; + } catch (Exception e) { + throw new EnsException(EnsErrCd.MAKE512, e.getMessage()); + } + 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..2f49a0f --- /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.make()); + + + 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..0a298df --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkoalimtalk/AcceptDataByKkoAlimtalk.java @@ -0,0 +1,93 @@ +package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support.kkoalimtalk; + +import cokr.xit.ens.core.utils.CmmnUtil; +import cokr.xit.ens.modules.common.ctgy.intgrnbill.BillAcptReqDTO; +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 make() { + 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_link_info(this.createBillLinkInfo(intgrnSendDetail)) + .bill_acpt_data(this.createBillAcptData(intgrnSendDetail)) + .tmplt_msg_data(this.createTmpltMsgData(intgrnSendDetail)) + .build(); + } + + +// if (CmmnUtil.isEmpty(intgrnSendDetail.getKkoBillMast())) +// return null; +// else +// return BillLinkInfo.builder() +// .use_bill_mast_id(true) +// .bill_mast_id(intgrnSendDetail.getKkoBillMast().getBillMastId()) +// .build(); +// } + protected BillAcptReqDTO createBillAcptData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getBill())) + return null; + return BillAcptReqDTO.builder() + .use_bill_uid(true) + .bill_uid(intgrnSendDetail.getBill().getBillUid()) + .bill_se(intgrnSendDetail.getBill().getBillSeCd()) + .bill_kko(null) + .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..37c3657 --- /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.make()); + + + 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..d9fbdd9 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/kkomydoc/AcceptDataByKkoMydoc.java @@ -0,0 +1,109 @@ +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.modules.common.ctgy.intgrnbill.BillAcptReqDTO; +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 make() { + 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(); + } + + +// if (CmmnUtil.isEmpty(intgrnSendDetail.getKkoBillMast())) +// return null; +// else +// return BillLinkInfo.builder() +// .use_bill_mast_id(true) +// .bill_mast_id(intgrnSendDetail.getKkoBillMast().getBillMastId()) +// .build(); +// } + protected BillAcptReqDTO createBillAcptData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getBill())) + return null; + return BillAcptReqDTO.builder() + .use_bill_uid(true) + .bill_uid(intgrnSendDetail.getBill().getBillUid()) + .bill_se(intgrnSendDetail.getBill().getBillSeCd()) + .bill_kko(null) + .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..282eb59 --- /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.make()); + + + 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..b89ceb7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktGibis/AcceptDataByKtGibis.java @@ -0,0 +1,86 @@ +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.modules.common.ctgy.intgrnbill.BillAcptReqDTO; +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 make() { + 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 BillAcptReqDTO createBillAcptData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getBill())) + return null; + return BillAcptReqDTO.builder() + .use_bill_uid(true) + .bill_uid(intgrnSendDetail.getBill().getBillUid()) + .bill_se(intgrnSendDetail.getBill().getBillSeCd()) + .bill_kko(null) + .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..9682c5c --- /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.make()); + + + 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..7c0ed91 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/ktSigntalk/AcceptDataByKtSigntalk.java @@ -0,0 +1,107 @@ +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.modules.common.ctgy.intgrnbill.BillAcptReqDTO; +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 make() { + 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(); + } + + +// if (CmmnUtil.isEmpty(intgrnSendDetail.getKkoBillMast())) +// return null; +// else +// return BillLinkInfo.builder() +// .use_bill_mast_id(true) +// .bill_mast_id(intgrnSendDetail.getKkoBillMast().getBillMastId()) +// .build(); +// } + protected BillAcptReqDTO createBillAcptData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getBill())) + return null; + return BillAcptReqDTO.builder() + .use_bill_uid(true) + .bill_uid(intgrnSendDetail.getBill().getBillUid()) + .bill_se(intgrnSendDetail.getBill().getBillSeCd()) + .bill_kko(null) + .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..46c418b --- /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.make()); + + + 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..cb7cd86 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/intgrnnoti/service/support/nvsigntalk/AcceptDataByNvSigntalk.java @@ -0,0 +1,102 @@ +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.modules.common.ctgy.intgrnbill.BillAcptReqDTO; +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 make() { + 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_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 BillLinkInfo createBillLinkInfo(IntgrnSendDetail intgrnSendDetail) { +// if (CmmnUtil.isEmpty(intgrnSendDetail.getKkoBillMast())) +// return null; +// else +// return BillLinkInfo.builder() +// .use_bill_mast_id(true) +// .bill_mast_id(intgrnSendDetail.getKkoBillMast().getBillMastId()) +// .build(); +// } + + protected BillAcptReqDTO createBillAcptData(IntgrnSendDetail intgrnSendDetail) { + if (CmmnUtil.isEmpty(intgrnSendDetail.getBill())) + return null; + return BillAcptReqDTO.builder() + .use_bill_uid(true) + .bill_uid(intgrnSendDetail.getBill().getBillUid()) + .bill_se(intgrnSendDetail.getBill().getBillSeCd()) + .bill_kko(null) + .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..1c67154 --- /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 = "{\"postSe\":\"testMblPage\",\"sendDetailId\":1,\"document\":{\"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\":[{\"링크 이미지\":\"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>> document; + +} 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..e7e454c --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/mblpage/presentation/SendDetailMblPageController.java @@ -0,0 +1,46 @@ +package cokr.xit.ens.modules.common.ctgy.mblpage.presentation; + +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.domain.ids.SendDetailMblPageIds; +import cokr.xit.ens.modules.common.ctgy.mblpage.domain.repository.SendDetailMblPageRepository; +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 java.util.Optional; + +@Tag(name = "SendDetailMblPageTestController") +@Slf4j +@RequiredArgsConstructor +@Controller +public class SendDetailMblPageController { + + private final SendDetailMblPageRepository sendDetailMblPageRepository; + + + @Operation(summary = "모바일페이지 출력") + @GetMapping(value = "/cmft/mbl/page/{postSe}/{sendDetailId}") + public String mblPagePrnt(@PathVariable String postSe, @PathVariable Long sendDetailId, ModelMap model) { + + Optional sendDetailMblPage = sendDetailMblPageRepository.findById(SendDetailMblPageIds.builder() + .postSe(postSe) + .sendDetailId(sendDetailId) + .build()); + + model.put("details", sendDetailMblPage.isPresent() ? sendDetailMblPage.get().getDetails() : "{}"); + model.put("payButtonLinks", "{}"); + 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..89b1336 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/domain/OrgMng.java @@ -0,0 +1,162 @@ +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 = "sub_org_id", nullable = true) + @Setter + private Long subOrgId; + + + @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) + @Setter + private String kkoMdAccessToken; + + @Column(name = "kko_md_contract_uuid", nullable = true) + @Setter + private String kkoMdContractUuid; + + + @Column(name = "kko_bp_biller_code", nullable = true) + @Setter + private String kkoBpBillerCode; + + @Column(name = "kko_bp_authorization", nullable = true) + @Setter + private String kkoBpAuthorization; + + @Column(name = "kko_bp_csign_yn", nullable = true, length = 1) + @Setter + private String kkoBpCsignYn; + + @Column(name = "kko_bp_csign_prepay_api", nullable = true) + @Setter + private String kkoBpCsignPrepayApi; + + @Column(name = "kko_bp_csign_payresult_api", nullable = true) + @Setter + private String kkoBpCsignPayresultApi; + + + @Column(name = "kko_at_bsid", nullable = true) + @Setter + private String kkoAtBsid; + + @Column(name = "kko_at_passwd", nullable = true) + @Setter + private String kkoAtPasswd; + + @Column(name = "kko_at_sender_key", nullable = true) + @Setter + private String kkoAtSenderKey; + + + @Column(name = "nice_cd_site_code", nullable = true) + @Setter + private String niceCdSiteCode; + + @Column(name = "nice_cd_site_pw", nullable = true) + @Setter + private String niceCdSitePw; + + @Column(name = "nice_cd_client_id", nullable = true) + @Setter + private String niceCdClientId; + + @Column(name = "nice_cd_client_sercet", nullable = true) + @Setter + private String niceCdClientSercet; + + + @Column(name = "nv_st_x_naver_client_id", nullable = true) + @Setter + private String nvStXNaverClientId; + + @Column(name = "nv_st_x_naver_client_secret", nullable = true) + @Setter + private String nvStXNaverClientSecret; + + @Column(name = "nv_st_org_id", nullable = true) + @Setter + private String nvStOrgId; + +// @Column(name = "nv_st_org_id", nullable = true) +// @Setter +// private String nvStOrgId; + + + @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) + @Setter + private String ktStServiceKey; + + @Column(name = "kt_st_clientId", nullable = true, length = 255) + @Setter + private String ktStClientId; + + @Column(name = "kt_st_client_secret", nullable = true, length = 255) + @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..2277121 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/model/OrgMngDTO.java @@ -0,0 +1,83 @@ +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; + + + + + + @Schema(required = false, title = "(계약정보)엑세스토큰", example = " ") + private String kkoMdAccessToken; + @Schema(required = false, title = "(계약정보)계약Uuid", example = " ") + private String kkoMdContractUuid; + + @Schema(required = false, title = "(계약정보)빌러코드", example = " ") + private String kkoBpBillerCode; + @Schema(required = false, title = "(계약정보)허가코드", example = " ") + private String kkoBpAuthorization; +// @NotEmpty(message = "납부요청 위탁여부는 필수 입력값 입니다.") + @Pattern(regexp = "(Y|N)", message = "납부요청 위탁여부는 Y 또는 N 만 입력 할 수 있습니다.") + @Schema(required = false, title = "납부요청 위탁여부", example = " ") + private String kkoBpCsignYn; + @Schema(required = false, title = "이용시스템의 납부가능조회API URL", example = " ") + private String kkoBpCsignPrepayApi; + @Schema(required = false, title = "이용시스템의 납부결과API URL", example = " ") + private String kkoBpCsignPayResultApi; + + @Schema(required = false, title = "(계약정보)bs아이디", example = " ") + private String kkoAtBsid; + @Schema(required = false, title = "(계약정보)패스워드", example = " ") + private String kkoAtPasswd; + @Schema(required = false, title = "(계약정보)발송자키", example = " ") + private String kkoAtSenderKey; + + @Schema(required = false, title = "(계약정보)사이트코드(socket)", example = " ") + private String niceCdSiteCode; + @Schema(required = false, title = "(계약정보)사이트패스워드(socket)", example = " ") + private String niceCdSitePw; + @Schema(required = false, title = "(계약정보)클라이언트ID(rest)", example = " ") + private String niceCdClientId; + @Schema(required = false, title = "(계약정보)클라이언트패스워드(rest)", example = " ") + private String niceCdClientSercet; + + @Schema(required = false, title = "(계약정보)클라이언트 아이디", example = " ") + private String nvStXNaverClientId; + @Schema(required = false, title = "(계약정보)클라이언트 패스워드", example = " ") + private String nvStXNaverClientSecret; + @Schema(required = false, title = "(계약정보)하위기관명", example = " ") + private String nvStOrgId; + + @Schema(required = false, title = "(계약정보)엑세스토큰", example = " ") + private String ktStAccessToken; + @Schema(required = false, title = "(계약정보)서비스코드", example = " ") + private String ktStServiceCd; + @Schema(required = false, title = "(계약정보)서비스키", example = " ") + private String ktStServiceKey; + @Schema(required = false, title = "(계약정보)고객ID", example = " ") + private String ktStClientId; + @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..6a8bde7 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/OrgMngService.java @@ -0,0 +1,212 @@ +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.getKkoBpCsignPrepayApi()) || CmmnUtil.isEmpty(dto.getKkoBpCsignPayResultApi())) + 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()) + .kkoBpCsignPrepayApi(dto.getKkoBpCsignPrepayApi()) + .kkoBpCsignPayresultApi(dto.getKkoBpCsignPayResultApi()) + + .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()) + + .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.getKkoBpCsignPrepayApi()) || CmmnUtil.isEmpty(dto.getKkoBpCsignPayResultApi())) + 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.setKkoBpCsignPrepayApi(dto.getKkoBpCsignPrepayApi()); + orgMng.setKkoBpCsignPayresultApi(dto.getKkoBpCsignPayResultApi()); + + 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..e0ae760 --- /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..67aec0a --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/ctgy/sys/mng/service/strategy/TmpltMngStrategyBasic.java @@ -0,0 +1,91 @@ +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.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_basic") +@RequiredArgsConstructor +public class TmpltMngStrategyBasic extends TmpltMngStrategyTemplate, TmpltMngDTO> { + private final OrgMngRepository orgMngRepository; + private final TmpltMngRepository tmpltMngRepository; + private TmpltMngMapper tmpltMngMapper = 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 = tmpltMngMapper.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()))); + if(!"Y".equals(tmpltMng.getUseYn())) + throw new EnsException(EnsErrCd.ERR402, "\"미사용\" 상태의 템플릿은 수정 할 수 없습니다."); + tmpltMngMapper.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..5b81707 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/common/domain/support/FieldError.java @@ -0,0 +1,27 @@ +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; + +@Embeddable +@Getter +@RequiredArgsConstructor +public class FieldError { + + @Column(name = "error_code") + private String errorCode; + + @Column(name = "error_message", length = 4000) + 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..6f39c03 --- /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.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..097a1ff --- /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.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..7972fea --- /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.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