From 57b309c9314cbbffd1c273296b08236510c7873f Mon Sep 17 00:00:00 2001 From: "Jonguk. Lim" Date: Tue, 13 Aug 2024 19:23:46 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=B9=B4=EC=B9=B4=EC=98=A4=ED=86=A1=20?= =?UTF-8?q?make,=20send=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/mens_traffic.sql | 29 ++- .../v2/web/KkotalkEltrcDocController.java | 2 +- .../resources/config/application-local.yml | 2 +- .../xit/biz/ens/mapper/IEnsBatchMapper.java | 28 ++- .../java/kr/xit/biz/ens/model/EnsDTO.java | 156 ++++++++++++++ .../ens/service/EnsBatchExtractService.java | 48 ++++- .../biz/ens/service/EnsBatchMakeService.java | 20 +- .../biz/ens/service/EnsBatchSendService.java | 204 ++++++++++++++++-- .../ens/service/IEnsBatchExtractService.java | 4 +- .../main/resources/config/application-ens.yml | 8 +- .../mapper/biz/ens-mysql-mapper.xml | 179 ++++++++++++--- .../java/kr/xit/biz/common/ApiConstants.java | 4 +- .../biz/ens/model/kakao/v2/KkotalkDTO.java | 2 +- .../biz/ens/model/kakao/v2/KkotalkDocDTO.java | 2 +- 14 files changed, 620 insertions(+), 68 deletions(-) diff --git a/db/mens_traffic.sql b/db/mens_traffic.sql index 1c96eec..9602789 100644 --- a/db/mens_traffic.sql +++ b/db/mens_traffic.sql @@ -23,7 +23,8 @@ select * select * from tb_ens_ci; - +select * + from tb_ens_tmplat_manage; /** 접수 reset */ select * from tb_elctrn_ntic_sndng; @@ -60,4 +61,28 @@ where teim.ihidnum = 'RUNCNjEwM0JERENGMEMzNjRBOTAyMERERjg5MDFEODc='; FROM tb_ens_ihidnum_manage teim LEFT JOIN tb_ens_ci_manage tecm ON teim.ihidnum_manage_id = tecm.ihidnum_manage_id - WHERE teim.ihidnum = 'RUNCNjEwM0JERENGMEMzNjRBOTAyMERERjg5MDFEODc='; \ No newline at end of file + WHERE teim.ihidnum = 'RUNCNjEwM0JERENGMEMzNjRBOTAyMERERjg5MDFEODc='; + + + + + common_categories, + read_expired_at, /* 처리마감시간 */ + -- recv_ci, /* 받는이 CI */ + recv_phone_number, /* 받는이 전화번호 */ + recv_name, /* 받는이 이름 */ + recv_birthday, /* 받는이 생년월일 */ + recv_is_required_verify_name,/* 성명검증옵션 */ + prop_link, /* 모바일페이지 URL */ + prop_payload, + prop_message, + prop_cs_number, /* 고객센터 전화번호 */ + prop_cs_name, /* 고객센터 명 */ + -- external_document_uuid,/* 외부문서 식별번호 */ + regist_dt, + register + + +select DATE_FORMAT(DATE_ADD(clos_dt, INTERVAL 1 DAY), '%Y-%m-%dT%H:%i:%s') + , DATE_FORMAT(clos_dt, '%Y-%m-%dT%H:%i:%s') + from tb_ens_unity_sndng_mastr; diff --git a/mens-api/src/main/java/kr/xit/ens/kakao/v2/web/KkotalkEltrcDocController.java b/mens-api/src/main/java/kr/xit/ens/kakao/v2/web/KkotalkEltrcDocController.java index d26e017..b1c9920 100644 --- a/mens-api/src/main/java/kr/xit/ens/kakao/v2/web/KkotalkEltrcDocController.java +++ b/mens-api/src/main/java/kr/xit/ens/kakao/v2/web/KkotalkEltrcDocController.java @@ -192,7 +192,7 @@ public class KkotalkEltrcDocController { * @return KkotalkDocDTO.BulkStatusResponse */ @Operation(summary = "대량 문서 상태 조회 요청 -> batch statusBulks 에서 호출", description = "카카오페이 전자문서 서버로 대량 문서 상태 조회 요청 -> batch statusBulks 에서 호출") - @PostMapping(value = "/documents/bulk/status", produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(value = "/envelopes/bulk/status", produces = MediaType.APPLICATION_JSON_VALUE) public IApiResponse findBulkStatus( @RequestBody final KkotalkDTO.BulkStatusRequest reqDTO ) { diff --git a/mens-api/src/main/resources/config/application-local.yml b/mens-api/src/main/resources/config/application-local.yml index 136d8e5..efd41e8 100644 --- a/mens-api/src/main/resources/config/application-local.yml +++ b/mens-api/src/main/resources/config/application-local.yml @@ -126,7 +126,7 @@ app: host: http://211.43.10.163:10210/ONLWeb api: # 모바일페이지 : 본문자수신등록 callback url - 토큰인증확인 조회, 열람확인결과 전송 - dp-callback-url: http://${app.api-ip}:8080/api/web/mbl/v1/kt/dpMblPage.do + chuncheon-callback-url: http://${app.api-ip}:8080/api/web/mbl/v1/kt/dpMblPage.do me-callback-url: http://${app.api-ip}:8080/api/web/mbl/v1/kt/meMblPage.do #dp-callback-url: http://211.119.124.73:8081/api/biz/mbl/v1/kt/dpMblPage #me-callback-url: http://211.119.124.73:8081/api/biz/mbl/v1/kt/meMblPage diff --git a/mens-batch/src/main/java/kr/xit/biz/ens/mapper/IEnsBatchMapper.java b/mens-batch/src/main/java/kr/xit/biz/ens/mapper/IEnsBatchMapper.java index 50e1ef8..3704ac9 100644 --- a/mens-batch/src/main/java/kr/xit/biz/ens/mapper/IEnsBatchMapper.java +++ b/mens-batch/src/main/java/kr/xit/biz/ens/mapper/IEnsBatchMapper.java @@ -153,6 +153,8 @@ public interface IEnsBatchMapper { * */ int insertKakaoMyDocs(final T t); + int insertKakaoD10(final T t); + /** *
@@ -162,7 +164,8 @@ public interface IEnsBatchMapper {
      * @return int
      * 
*/ - int insertMobilePageManage(final T t); + int insertKkopayMobilePageManage(final T t); + int insertKkotalkMobilePageManage(final T t); /** *
@@ -258,8 +261,17 @@ public interface IEnsBatchMapper {
      * @return List
      * 
*/ - List selectKakaoSendTgts(final T t); + List selectKakaopaySendTgts(final T t); + /** + *
+     * 카카오톡 전자고지 요청 대상 목록 조회
+     * - tb_ens_sndng_mastr, tb_ens_kakao_d10, tb_ens_ci
+     * @param t status
+     * @return List
+     * 
+ */ + List selectKakaotalkSendTgts(final T t); /** *
      * 발송상태 조회 : 발송후 발송 연계 마스터의 발송상태 변경값 조회
@@ -278,9 +290,17 @@ public interface IEnsBatchMapper {
      * @return int
      * 
*/ - int updateKakaoSendBulksResult(final T t); - + int updateKakaopaySendBulksResult(final T t); + /** + *
+     * 카카오페이 문서요청 결과 반영
+     * - tb_ens_kakao_d10
+     * @param t 문서ID, 에러코드, 에러메세지, 외부문서ID
+     * @return int
+     * 
+ */ + int updateKakaotalkSendBulksResult(final T t); /** *
      * 발송마스터 상태 변경
diff --git a/mens-batch/src/main/java/kr/xit/biz/ens/model/EnsDTO.java b/mens-batch/src/main/java/kr/xit/biz/ens/model/EnsDTO.java
index 6386b8c..c367447 100644
--- a/mens-batch/src/main/java/kr/xit/biz/ens/model/EnsDTO.java
+++ b/mens-batch/src/main/java/kr/xit/biz/ens/model/EnsDTO.java
@@ -113,6 +113,58 @@ public class EnsDTO {
         private long closDt;
     }
 
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @SuperBuilder
+    @EqualsAndHashCode(callSuper = true)
+    public static class SendKakaotalkTgt extends EnsDTO.KakaotalkD10 {
+
+        /**
+         * 발송 마스터 id
+         */
+        private String sndngMastrId;
+
+        /**
+         * 통합 발송 마스터 id
+         */
+        private String unitySndngMastrId;
+        /**
+         * 시군구 코드
+         */
+        private String signguCode;
+        /**
+         * 과태료 코드
+         */
+        private String ffnlgCode;
+        /**
+         * 템플릿 ID
+         */
+        private String tmplatId;
+        /**
+         * 발송 유형 코드
+         */
+        private String sndngTyCode;
+        /**
+         * 발송 건수
+         */
+        private int sndngCo;
+        /**
+         * 발송 처리 상태
+         */
+        //private String sndngProcessSttus;
+
+        /**
+         * ci
+         */
+        private String ci;
+
+        /**
+         * 마감 일시
+         */
+        private String closDt;
+    }
+
 
     @Data
     @NoArgsConstructor
@@ -393,6 +445,110 @@ public class EnsDTO {
 
     }
 
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @SuperBuilder
+    @EqualsAndHashCode(callSuper = false)
+    public static class KakaotalkD10 extends AuditFields implements Serializable {
+
+        /**
+         * 발송 상세 id
+         */
+        private String sndngDetailId;
+        /**
+         * 통합 발송 상세 id
+         */
+        private String unitySndngDetailId;
+        /**
+         * 발송 마스터 id
+         */
+        private String sndngMastrId;
+        /**
+         * 시군구 코드
+         */
+        private String signguCode;
+        /**
+         * 과태료 코드
+         */
+        private String ffnlgCode;
+
+        /**
+         * 발송할 문서의 제목 : 필수
+         */
+        private String title;
+
+        /**
+         * 최초 열람 만료 일시 - 카카오톡 메시지를 수신한 사용자가 전자문서를 열람을 할 수 있는 시간
+         * 요청 일시로부터 6개월 이내
+         */
+        private String readExpiresAt;
+
+        /**
+         * 재열람 만료 일시 - 권장값: 최대값은 요청 일시로부터 6개월 이내
+         * 9999-12-31T23:59:59, null로 설정 시 무제한
+         */
+        private String reviewExpiresAt;
+
+        /**
+         * 문서 원문(열람정보)에 대한 hash 값 - 공인전자문서 유통정보 등록 시 필수
+         */
+        private String hash;
+
+        /**
+         * 받는이에 대한 정보 - 필수
+         */
+
+        /**
+         * 받는이 CI
+         */
+        private String ci;
+
+        /**
+         * 받는이 전화번호
+         * ci 미전송시 필수
+         */
+        private String phoneNumber;
+
+        /**
+         * 받는 이 이름
+         * ci 미전송시 필수
+         */
+        private String name;
+
+        /**
+         * 받는 이 생년월일 (YYYYMMDD 형식)
+         * ci 미전송시 필수
+         */
+        private String birthday;
+
+        /**
+         * 이용기관에서 해당 값을 다시 받고자 할 내용의 값
+         */
+        private String payload;
+
+        /**
+         * 이용기관에서 해당 값을 다시 받고자 할 내용의 값
+         */
+        private Boolean useNonPersonalizedNotification;
+
+        /**
+         * 이용기관에서 해당 값을 다시 받고자 할 내용의 값
+         */
+        private String externalId;
+
+        /**
+         * 메세지 - 사용자에게 전송하는 문서에 대한 설명
+         * 노출위치 : 문서수신 메시지(알림톡)가 도착했음을 알리는 카카오톡 메시지 내부
+         */
+        private String guide;
+
+        /**
+         * 본인인증 후 사용자에게 보여줄 웹페이지 주소 : 필수
+         */
+        private String contentLink;
+    }
+
     @Data
     @NoArgsConstructor
     @AllArgsConstructor
diff --git a/mens-batch/src/main/java/kr/xit/biz/ens/service/EnsBatchExtractService.java b/mens-batch/src/main/java/kr/xit/biz/ens/service/EnsBatchExtractService.java
index f95c927..9f6c1da 100644
--- a/mens-batch/src/main/java/kr/xit/biz/ens/service/EnsBatchExtractService.java
+++ b/mens-batch/src/main/java/kr/xit/biz/ens/service/EnsBatchExtractService.java
@@ -21,6 +21,7 @@ import kr.xit.biz.ens.model.EnsDTO;
 import kr.xit.biz.ens.model.cmm.SndngMssageParam;
 import kr.xit.biz.ens.model.cntc.CntcDTO;
 import kr.xit.biz.ens.model.kakao.v1.KkopayDocBulkDTO;
+import kr.xit.biz.ens.model.kakao.v2.KkotalkDTO;
 import kr.xit.biz.ens.model.kt.KtMmsSendDTO.KtMainSendReqData;
 import kr.xit.core.exception.BizRuntimeException;
 import kr.xit.core.service.AbstractService;
@@ -77,17 +78,17 @@ public class EnsBatchExtractService extends AbstractService implements
     @Override
     @Transactional(propagation = Propagation.REQUIRES_NEW)
     // FIXME: kakao v1 or v2
-    public void saveKkoSendResult(final String mstId, String unitySndMstId, final List resList) {
+    public void saveKkopaySendResult(final String mstId, String unitySndMstId, final List resList) {
         // 결과 반영
         resList.forEach(o ->
             o.getDocuments().forEach(
                 t -> {
                     // 카카오페이 문서요청 결과 반영
-                    mapper.updateKakaoSendBulksResult(t);
+                    mapper.updateKakaopaySendBulksResult(t);
                     String code = null;
                     // 모바일 페이지 컨텐트 생성
                     if (Checks.isNotEmpty(t.getDocument_binder_uuid())) {
-                        mapper.insertMobilePageManage(t.getExternal_document_uuid());
+                        mapper.insertKkopayMobilePageManage(t.getExternal_document_uuid());
                         code = ApiConstants.KkopayDocStatus.SENT.getCode();
                     }else{
                         code = t.getError_code();
@@ -102,6 +103,47 @@ public class EnsBatchExtractService extends AbstractService implements
         updateSendSndngMstStatus(mstId, unitySndMstId, SndngSeCode.KAKAO, "카카오 문서 발송요청 실패(발송마스터 데이타 오류)");
     }
 
+    /**
+     * 
+     * 카카오문서 요청 결과 반영
+     * 1. 카카오페이 문서요청 결과 반영 : tb_ens_kakao_my_doc
+     * 2. 모바일 페이지 생성 : tb_ens_mobile_page_manage
+     * 3. 연계발송결과 생성 : tb_cntc_sndng_result
+     *    -> 성공시 'SENT' 로 코드값 생성
+     * @param mstId         발송마스터 ID
+     * @param resList       List 카카오내문서함 발송요청 결과 목록
+     * @param unitySndMstId String 통합발송 마스터 ID
+     * 
+ */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void saveKkotalkSendResult(final String mstId, String unitySndMstId, final List resList) { + resList.get(0).getEnvelopeIds(); + // 결과 반영 + resList.forEach(o -> + o.getEnvelopeIds().forEach( + t -> { + // 카카오톡 전자고지 요청 결과 반영 + mapper.updateKakaotalkSendBulksResult(t); + String code = null; + // 모바일 페이지 컨텐트 생성 + if (Checks.isNotEmpty(t.getEnvelopeId())) { + mapper.insertKkotalkMobilePageManage(t.getExternalId()); + // FIXME: 코드값 확인후 지정 + code = ApiConstants.KkotalkDocStatus.READ.getCode(); + }else{ + code = t.getErrorCode(); + } + // 연계발송결과 생성 + insertCntcSndngResult(SndngSeCode.KAKAO_NEW.getCode(), + t.getExternalId(), code, t.getErrorMessage()); + }) + ); + + // 마스터 상태 변경 + updateSendSndngMstStatus(mstId, unitySndMstId, SndngSeCode.KAKAO_NEW, "카카오톡 전자고지 발송요청 실패(발송마스터 데이타 오류)"); + } + @Override @Transactional(propagation = Propagation.REQUIRES_NEW) public void saveKtBcResult(final SndngMssageParam dto, final List sendReqs) { diff --git a/mens-batch/src/main/java/kr/xit/biz/ens/service/EnsBatchMakeService.java b/mens-batch/src/main/java/kr/xit/biz/ens/service/EnsBatchMakeService.java index 284ec5d..33fc577 100644 --- a/mens-batch/src/main/java/kr/xit/biz/ens/service/EnsBatchMakeService.java +++ b/mens-batch/src/main/java/kr/xit/biz/ens/service/EnsBatchMakeService.java @@ -40,8 +40,10 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Service public class EnsBatchMakeService extends AbstractService implements IEnsBatchMakeService { - @Value("${app.contract.kt.api.dp-callback-url}") - private String DP_CALLBACK_URL; + // FIXME: KT callback url 확인 적용 + @Value("${app.contract.kt.api.chuncheon-callback-url}") + private String CHUNCHEON_CALLBACK_URL; + // FIXME: KT callback url 확인 적용 @Value("${app.contract.kt.api.me-callback-url}") private String ME_CALLBACK_URL; @@ -75,11 +77,12 @@ public class EnsBatchMakeService extends AbstractService implements IEnsBatchMak @Transactional(readOnly = true) public Map> findMakes(final EnsDTO.BatchEnsRequest reqDTO) { final Map> tgtMap = new HashMap<>(); - final String sndngProcessSttus2 = ApiConstants.SndngProcessStatus.SENDING1.getCode(); - final String sndngProcessSttus3 = ApiConstants.SndngProcessStatus.SENDING2.getCode(); + // FIXME :: 순차 발송 값 바인딩 잘못함 순차발송이 필요한 경우 수정 필요 + // final String sndngProcessSttus2 = ApiConstants.SndngProcessStatus.SENDING1.getCode(); + // final String sndngProcessSttus3 = ApiConstants.SndngProcessStatus.SENDING2.getCode(); tgtMap.put("tty1", mapper.selectMakeTgts(reqDTO)); - tgtMap.put("tty2", mapper.selectMakeTgts(sndngProcessSttus2)); + //tgtMap.put("tty2", mapper.selectMakeTgts(sndngProcessSttus2)); //tgtMap.put("tty3", mapper.selectMakeTgts(sndngProcessSttus3)); return tgtMap; } @@ -201,10 +204,13 @@ public class EnsBatchMakeService extends AbstractService implements IEnsBatchMak return switch (SndngSeCode.compare(seCode)) { case KAKAO -> mapper.insertKakaoMyDocs(dto); + case KAKAO_NEW -> mapper.insertKakaoD10(dto); case KT_BC -> { - if(SignguCode.TRAFFIC.getCode().equals(dto.getSignguCode())){ - dto.setUrl(DP_CALLBACK_URL); + // FIXME: KT callback url 확인 적용 + if(SignguCode.CHUNCHEON.getCode().equals(dto.getSignguCode())){ + dto.setUrl(CHUNCHEON_CALLBACK_URL); } + // FIXME: KT callback url 확인 적용 if(SignguCode.FUNERAL.getCode().equals(dto.getSignguCode())){ dto.setUrl(ME_CALLBACK_URL); } diff --git a/mens-batch/src/main/java/kr/xit/biz/ens/service/EnsBatchSendService.java b/mens-batch/src/main/java/kr/xit/biz/ens/service/EnsBatchSendService.java index 381403b..6b06737 100644 --- a/mens-batch/src/main/java/kr/xit/biz/ens/service/EnsBatchSendService.java +++ b/mens-batch/src/main/java/kr/xit/biz/ens/service/EnsBatchSendService.java @@ -2,9 +2,12 @@ package kr.xit.biz.ens.service; import static kr.xit.core.support.utils.JsonUtils.*; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -32,6 +35,8 @@ import kr.xit.biz.ens.model.EnsKtBcDTO; import kr.xit.biz.ens.model.cmm.SndngMssageParam; import kr.xit.biz.ens.model.kakao.v1.KkopayDocAttrDTO; import kr.xit.biz.ens.model.kakao.v1.KkopayDocBulkDTO; +import kr.xit.biz.ens.model.kakao.v2.KkotalkDTO; +import kr.xit.biz.ens.model.kakao.v2.KkotalkDocDTO; import kr.xit.biz.ens.model.kt.KtCommonDTO.ErrorMsg; import kr.xit.biz.ens.model.kt.KtCommonDTO.KtCommonResponse; import kr.xit.biz.ens.model.kt.KtMmsSendDTO.KtMainSendReqData; @@ -66,8 +71,13 @@ import lombok.extern.slf4j.Slf4j; public class EnsBatchSendService extends AbstractService implements IEnsBatchSendService { @Value("${app.contract.host}") private String apiHost; + @Value("${app.contract.kakao.api.pay.bulksend}") - private String apiKkoBulkSend; + private String apiKkopayBulkSend; + + @Value("${app.contract.kakao.api.talk.bulksend}") + private String apiKkotalkBulkSend; + @Value("${app.contract.kt.api.bulksend}") private String apiKtBcBulkSend; @@ -145,7 +155,8 @@ public class EnsBatchSendService extends AbstractService implements IEnsBatchSen * 모바일 페이지 생성 : tb_ens_mobile_page_manage * 연계발송결과 생성 : tb_cntc_sndng_result */ - case KAKAO -> sendBulkKakaoMyDocs(dto); + case KAKAO -> sendBulkKakaopay(dto); + case KAKAO_NEW -> sendBulkKakaotalk(dto); case KT_BC -> sendBulkKtBc(dto); default -> throw BizRuntimeException.create(String.format("정의 되지 않은 문서 중개자[%s] 입니다", seCode)); } @@ -161,32 +172,32 @@ public class EnsBatchSendService extends AbstractService implements IEnsBatchSen * 1. 카카오페이 문서요청 대상 조회 * - {@link IEnsBatchMapper#selectKakaoSendTgts(Object) selectKakaoSendTgts} * 2. 요청 대상 파라메터 set, validtion check - * - {@link #setKkoMyDocSendBulks} - * - {@link #validatedKkoMyDocSendBulks} + * - {@link #setKkopaySendBulks} + * - {@link #validatedKkopaySendBulks} * 3. 카카오페이 문서요청 API 호출 * -> 결과 목록 획득 * 4. 카카오페이 문서요청 결과 반영 * - bulk 전송 기준 모든건이 실패인 경우만 실패 처리 * - - * -> {@link EnsBatchExtractService#saveKkoSendResult(String, String, List) saveKkoMyDocResult} + * -> {@link EnsBatchExtractService#saveKkopaySendResult(String, String, List) saveKkoMyDocResult} * - 카카오페이 연계 결과 반영 : tb_ens_kakao_my_doc * - 모바일 페이지 생성 : tb_ens_mobile_page_manage * - 연계발송결과 생성 : tb_cntc_sndng_result * @param dto SndngMssageParam *
*/ - private void sendBulkKakaoMyDocs(final SndngMssageParam dto) { - final String url = apiHost + apiKkoBulkSend; + private void sendBulkKakaopay(final SndngMssageParam dto) { + final String url = apiHost + apiKkopayBulkSend; - final List list = mapper.selectKakaoSendTgts(dto); + final List list = mapper.selectKakaopaySendTgts(dto); if(list.isEmpty()) return; final String mstId = list.get(0).getSndngMastrId(); - final List bulkList = setKkoMyDocSendBulks(list); + final List bulkList = setKkopaySendBulks(list); // validation check try { - validatedKkoMyDocSendBulks(bulkList); + validatedKkopaySendBulks(bulkList); } catch (Exception e) { extractService.updateSndngMstFailStatus(mstId, SndngSeCode.KAKAO, "", e.getMessage(), "[send]카카오 문서 발송(bulks)요청 실패(파라메터 오류)"); throw e; @@ -224,7 +235,79 @@ public class EnsBatchSendService extends AbstractService implements IEnsBatchSen if(!isSuccess){ extractService.updateSndngMstFailStatus(mstId, SndngSeCode.KAKAO, "", errMsg, errMsg); } - extractService.saveKkoSendResult(mstId, dto.getUnitySndngMastrId(), resList); + extractService.saveKkopaySendResult(mstId, dto.getUnitySndngMastrId(), resList); + } + + /** + *
+     * 카카오톡 전자고지 send
+     * 1. 카카오톡 전자고지 요청 대상 조회
+     *    - {@link IEnsBatchMapper#selectKakaoSendTgts(Object) selectKakaoSendTgts}
+     * 2. 요청 대상 파라메터 set, validtion check
+     *    - {@link #setKkoNewSendBulks}
+     *    - {@link #validatedKkoNewSendBulks}
+     * 3. 카카오페이 문서요청  API 호출
+     *    -> 결과 목록 획득
+     * 4. 카카오페이 문서요청 결과 반영
+     *    - bulk 전송 기준 모든건이 실패인 경우만 실패 처리
+     *    -
+     *    -> {@link EnsBatchExtractService#saveKkopaySendResult(String, String, List) saveKkoNewSendResult}
+     *       - 카카오페이 연계 결과 반영 : tb_ens_kakao_my_doc
+     *       - 모바일 페이지 생성 : tb_ens_mobile_page_manage
+     *       - 연계발송결과 생성 : tb_cntc_sndng_result
+     * @param dto SndngMssageParam
+     * 
+ */ + private void sendBulkKakaotalk(final SndngMssageParam dto) { + final String url = apiHost + apiKkotalkBulkSend; + + final List list = mapper.selectKakaotalkSendTgts(dto); + if(list.isEmpty()) return; + + final String mstId = list.get(0).getSndngMastrId(); + final List bulkList = setKkotalkSendBulks(list); + + // validation check + try { + validatedKkotalkSendBulks(bulkList); + } catch (Exception e) { + extractService.updateSndngMstFailStatus(mstId, SndngSeCode.KAKAO_NEW, "", e.getMessage(), "[send]카카오톡 전자고지 발송(bulks)요청 실패(파라메터 오류)"); + throw e; + } + + final List> partitions = ListUtils.partition(bulkList, bulkKkoMaxCnt); + //noinspection rawtypes + final List apiResults = partitions.stream() + .map(bulkSendList -> apiWebClient.exchange( + url, + HttpMethod.POST, + KkotalkDTO.BulkSendRequest.builder() + .signguCode(dto.getSignguCode()) + .ffnlgCode(dto.getFfnlgCode()) + .envelopes(bulkSendList) + .build(), + ApiResponseDTO.class, + CmmEnsBizUtils.getHeadeMap()) + ) + .toList(); + + final List resList = new ArrayList<>(); + boolean isSuccess = false; + String errMsg = null; + //noinspection rawtypes + for(ApiResponseDTO apiResult : apiResults) { + if(apiResult.getData() != null) { + resList.add(toObjByObj(apiResult.getData(), KkotalkDTO.BulkSendResponse.class)); + isSuccess = true; + continue; + } + errMsg = apiResult.getMessage(); + } + // 카카오 send 결과 반영 + if(!isSuccess){ + extractService.updateSndngMstFailStatus(mstId, SndngSeCode.KAKAO_NEW, "", errMsg, errMsg); + } + extractService.saveKkoNewSendResult(mstId, dto.getUnitySndngMastrId(), resList); } /** @@ -233,7 +316,7 @@ public class EnsBatchSendService extends AbstractService implements IEnsBatchSen * @param list List 문서발송요청 대상 목록 * @return List */ - private static List setKkoMyDocSendBulks(List list) { + private static List setKkopaySendBulks(List list) { final List bulkList = new ArrayList<>(); for (SendKakaoTgt sendTgtDTO : list) { @@ -283,12 +366,54 @@ public class EnsBatchSendService extends AbstractService implements IEnsBatchSen return bulkList; } + /** + * GET 카카오톡 전자고지 발송요청 파라메터 목록 + * - CI 인증인 경우 개인 정보 삭제 + * @param list List 문서발송요청 대상 목록 + * @return List + */ + private static List setKkotalkSendBulks(List list) { + final List bulkList = new ArrayList<>(); + + for (EnsDTO.SendKakaotalkTgt sendTgtDTO : list) { + /* + 방어 코드 추가 : CI 인증인 경우 개인정보 삭제 + */ + KkotalkDocDTO.Envelope bulkReqDTO = null; + if(StringUtils.isNotEmpty(sendTgtDTO.getCi())){ + bulkReqDTO = KkotalkDocDTO.Envelope.builder() + .ci(sendTgtDTO.getCi()) + .build(); + }else{ + bulkReqDTO = KkotalkDocDTO.Envelope.builder() + .build(); + } + + final KkotalkDocDTO.Content content = KkotalkDocDTO.Content.builder() + .link(sendTgtDTO.getContentLink()) + .build(); + + + bulkReqDTO.setExternalId(sendTgtDTO.getUnitySndngDetailId()); + bulkReqDTO.setTitle(sendTgtDTO.getTitle()); + bulkReqDTO.setPayload(sendTgtDTO.getPayload()); + bulkReqDTO.setReadExpiresAt(sendTgtDTO.getReadExpiresAt()); + bulkReqDTO.setReviewExpiresAt(sendTgtDTO.getReviewExpiresAt()); + bulkReqDTO.setHash(sendTgtDTO.getHash()); + bulkReqDTO.setGuide(sendTgtDTO.getGuide()); + bulkReqDTO.setContent(content); + + bulkList.add(bulkReqDTO); + } + return bulkList; + } + /** * 카카오문서 발송요청 파라메터 유효성 체크 * * @param bulkList List 카카오내문서함 발송요청 파라메터 목록 */ - private void validatedKkoMyDocSendBulks(List bulkList) { + private void validatedKkopaySendBulks(List bulkList) { List errors = new ArrayList<>(); int idx = 0; @@ -334,6 +459,59 @@ public class EnsBatchSendService extends AbstractService implements IEnsBatchSen } } + /** + * 카카오톡 전자고지 발송요청 파라메터 유효성 체크 + * + * @param bulkList List 카카오톡 전자고지 발송요청 파라메터 목록 + */ + private void validatedKkotalkSendBulks(List bulkList) { + List errors = new ArrayList<>(); + int idx = 0; + + for (KkotalkDocDTO.Envelope dto : bulkList) { + final Set> errList = validator.validate(dto); + + if(!errList.isEmpty()) { + int finalIdx = idx; + errors.addAll(errList.stream() + .map(row -> String.format("%s[%d]=%s", row.getPropertyPath(), finalIdx + 1, + row.getMessageTemplate())) + .toList() + ); + } + + if(dto.getReadExpiresAt() == null){ + Objects.requireNonNull(errors).add("최초 열람 만료 일시는 필수입니다."); + } + if(dto.getReadExpiresAt() != null && dto.getReviewExpiresAt() != null){ + DateTimeFormatter pattern1 = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); + LocalDateTime parse1 = LocalDateTime.parse(dto.getReadExpiresAt(), pattern1); + LocalDateTime parse2 = LocalDateTime.parse(dto.getReviewExpiresAt(), pattern1); + if(parse1.isAfter(parse2)) Objects.requireNonNull(errors).add("재열람 만료 일시는 최초 열람 만료 일시보다 이전일 수 없습니다."); + } + + if (Checks.isEmpty(dto.getCi())) { + // if (Checks.isEmpty(dto.getName())) { + // errors.add( + // String.format("받는이 이름은 필수입니다(receiver.name[%d] 번째 오류)", idx + 1)); + // } + // if (Checks.isEmpty(dto.getPhoneNumber())) { + // errors.add(String.format("받는이 전화번호는 필수입니다(receiver.phone_number[%d] 번째 오류)", + // idx + 1)); + // } + // if (Checks.isEmpty(dto.getBirthday())) { + // errors.add( + // String.format("받는이 생년월일은 필수입니다(receiver.birthday[%d] 번째 오류)", idx + 1)); + // } + } + idx++; + } + + if (!errors.isEmpty()) { + throw BizRuntimeException.create(errors.toString()); + } + } + /** *
      * KT BC 문서 send
diff --git a/mens-batch/src/main/java/kr/xit/biz/ens/service/IEnsBatchExtractService.java b/mens-batch/src/main/java/kr/xit/biz/ens/service/IEnsBatchExtractService.java
index 8f703b9..ed5da9b 100644
--- a/mens-batch/src/main/java/kr/xit/biz/ens/service/IEnsBatchExtractService.java
+++ b/mens-batch/src/main/java/kr/xit/biz/ens/service/IEnsBatchExtractService.java
@@ -5,6 +5,7 @@ import java.util.List;
 import kr.xit.biz.common.ApiConstants.SndngSeCode;
 import kr.xit.biz.ens.model.cmm.SndngMssageParam;
 import kr.xit.biz.ens.model.kakao.v1.KkopayDocBulkDTO;
+import kr.xit.biz.ens.model.kakao.v2.KkotalkDTO;
 import kr.xit.biz.ens.model.kt.KtMmsSendDTO.KtMainSendReqData;
 
 /**
@@ -29,7 +30,8 @@ public interface IEnsBatchExtractService {
     //-----------------------------------------------------------------------------------------------------------------
     // REQUIRES_NEW service method
     //-----------------------------------------------------------------------------------------------------------------
-    void saveKkoSendResult(final String mstId, String unitySndMstId, final List resList);
+    void saveKkopaySendResult(final String mstId, String unitySndMstId, final List resList);
+    void saveKkotalkSendResult(final String mstId, String unitySndMstId, final List resList);
 
     void saveKtBcResult(final SndngMssageParam dto, final List sendReqs);
 
diff --git a/mens-batch/src/main/resources/config/application-ens.yml b/mens-batch/src/main/resources/config/application-ens.yml
index c4b054b..1d7ff5f 100644
--- a/mens-batch/src/main/resources/config/application-ens.yml
+++ b/mens-batch/src/main/resources/config/application-ens.yml
@@ -24,8 +24,12 @@ app:
     kakao:
       bulk-max-cnt: 10
       api:
-        bulksend: /api/ens/kakao/v1/documents/bulk
-        bulkstatus: /api/ens/kakao/v1/documents/bulk/status
+        pay:
+          bulksend: /api/ens/kakao/v1/documents/bulk
+          bulkstatus: /api/ens/kakao/v1/documents/bulk/status
+        talk:
+          bulksend: /api/ens/kakao/v2//envelopes/bulk
+          bulkstatus: /api/ens/kakao/v2/envelopes/bulk/status
     kt:
       bulk-max-cnt: 10
       api:
diff --git a/mens-batch/src/main/resources/egovframework/mapper/biz/ens-mysql-mapper.xml b/mens-batch/src/main/resources/egovframework/mapper/biz/ens-mysql-mapper.xml
index 1b820a8..173ccd6 100644
--- a/mens-batch/src/main/resources/egovframework/mapper/biz/ens-mysql-mapper.xml
+++ b/mens-batch/src/main/resources/egovframework/mapper/biz/ens-mysql-mapper.xml
@@ -541,6 +541,58 @@
 			 	 , updusr = 'batch'
 		 WHERE unity_sndng_mastr_id = #{unitySndngMastrId}
 	
+
+	
+		/** ens-mysql-mapper|insertKakaoD10-카카오톡 D10_2 생성|julim  */
+		INSERT
+		INTO tb_ens_kakao_d10 (
+			sndng_detail_id,					/* 발송상세ID */
+			unity_sndng_detail_id,				/* 통합발송상세ID */
+			sndng_mastr_id,						/* 발송마스터ID */
+			signgu_code,						/* 시군구코드 */
+			ffnlg_code,							/* 과태료코드 */
+			title,								/* 제목 */
+			link,
+			hash,
+			guide,								/* 메세지 */
+			payload,
+			read_expires_at,					/* 최초 열람 만료 일시 */
+			review_expires_at,					/* 재열람 만료 일시 */
+			ci,									/* 받는이 ci */
+			phone_number,					    /* 수신인 전화번호 */
+			name,								/* 수신인 이름 */
+			birthday,							/* 수신인 생년월일 */
+			external_id,                        /* 문서 매핑 식별 ID */
+			regist_dt,
+			register
+		)
+		SELECT LPAD(NEXTVAL(sndng_detail_id_seq), 20, '0')
+			 , teusd.unity_sndng_detail_id
+			 , #{sndngMastrId}
+			 , teusm.signgu_code
+			 , teusm.ffnlg_code
+			 , tetm.tmplat_sj
+			 , tetm.redirect_url
+			 , SHA2(teusd.unity_sndng_detail_id, 256)
+		     , tetm.tmplat_cn
+			 , ''
+			 , DATE_FORMAT(teusm.clos_dt, '%Y-%m-%dT%H:%i:%s')
+			 , DATE_FORMAT(DATE_ADD(teusm.clos_dt, INTERVAL 1 DAY), '%Y-%m-%dT%H:%i:%s')
+			 , ''
+			 , teusd.moblphon_no
+			 , teusd.nm
+			 , ''
+			 , teusd.unity_sndng_detail_id
+			 , now()
+			 , 'batch'
+		FROM tb_ens_unity_sndng_mastr teusm
+		LEFT JOIN tb_ens_tmplat_manage tetm
+		  ON teusm.tmplat_id = tetm.tmplat_id
+		LEFT JOIN tb_ens_unity_sndng_detail teusd
+		  ON teusm.unity_sndng_mastr_id = teusd.unity_sndng_mastr_id
+	   WHERE teusm.unity_sndng_mastr_id = #{unitySndngMastrId}
+		 AND teusm.sndng_process_sttus = #{sndngProcessSttus}
+	
 	
 	
 	
@@ -591,42 +643,76 @@
 		 
 	
 
-	
+		/** ens-mysql-mapper|selectKakaopaySendTgts-카카오 문서요청 대상 목록 조회|julim  */
 		SELECT tesm.sndng_mastr_id							/* 발송마스터 ID */
 		     , tesm.unity_sndng_mastr_id				/* 통합발송마스터 ID */
-				 , tesm.signgu_code									/* 시군구 코드 */
-				 , tesm.ffnlg_code									/* 과태료 코드 */
-				 , tesm.tmplat_id										/* 템플릿 Id */
-				 , tesm.sndng_ty_code								/* 발송유형 코드 */
-				 , tesm.sndng_co										/* 발송건수 */
-				 , unix_timestamp(tesm.clos_dt) AS closDt   /* 마감일시 */
-				 , tekmd.sndng_detail_id						/* 발송상세 ID */
-				 , tekmd.unity_sndng_detail_id			/* 통합발송상세 ID */
+			 , tesm.signgu_code									/* 시군구 코드 */
+			 , tesm.ffnlg_code									/* 과태료 코드 */
+			 , tesm.tmplat_id										/* 템플릿 Id */
+			 , tesm.sndng_ty_code								/* 발송유형 코드 */
+			 , tesm.sndng_co										/* 발송건수 */
+			 , unix_timestamp(tesm.clos_dt) AS closDt   /* 마감일시 */
+			 , tekmd.sndng_detail_id						/* 발송상세 ID */
+			 , tekmd.unity_sndng_detail_id			/* 통합발송상세 ID */
 		     , tekmd.title                      /* 제목 */
 		     , tekmd.hash
 		     , tekmd.common_categories
-         , tekmd.recv_phone_number          /* 받는이 전화번호 */
-         , tekmd.recv_name     	 						/* 받는이 이름 */
-         , tekmd.recv_birthday   						/* 받는이 생년월일 */
+             , tekmd.recv_phone_number          /* 받는이 전화번호 */
+             , tekmd.recv_name     	 						/* 받는이 이름 */
+             , tekmd.recv_birthday   						/* 받는이 생년월일 */
 		     , tekmd.prop_link 									/* redirect url */
 		     , tekmd.prop_payload
 		     , tekmd.prop_message
 		     , tekmd.prop_cs_name 							/* 콜센터 명 */
 		     , tekmd.prop_cs_number         		/* 콜센터 전화번호 */
-			   , tec.ci                           /* ci */
+			 , tec.ci                           /* ci */
 		  FROM tb_ens_sndng_mastr tesm
 		  JOIN tb_ens_kakao_my_doc tekmd
 		    ON tesm.sndng_mastr_id = tekmd.sndng_mastr_id
 		  LEFT JOIN tb_ens_ci tec
 		    ON tekmd.unity_sndng_detail_id = tec.unity_sndng_detail_id
 		 WHERE tesm.sndng_mastr_id = #{sndngMastrId}
-			 AND tesm.signgu_code = #{signguCode}
-			 AND tesm.ffnlg_code = #{ffnlgCode}
+		   AND tesm.signgu_code = #{signguCode}
+		   AND tesm.ffnlg_code = #{ffnlgCode}
 		 ORDER BY tesm.unity_sndng_mastr_id
 			   , tekmd.unity_sndng_detail_id
 	
 
+	
+
 	
 
-	
-		/** ens-mysql-mapper|updateKakaoSendBulksResult-카카오페이 문서요청 결과 반영|julim  */
+	
+		/** ens-mysql-mapper|updateKakaopaySendBulksResult-카카오페이 문서요청 결과 반영|julim  */
 		UPDATE tb_ens_kakao_my_doc
 		   SET external_document_uuid = #{external_document_uuid}
 		     , document_binder_uuid = #{document_binder_uuid}
@@ -801,25 +887,58 @@
 		 WHERE unity_sndng_detail_id = #{external_document_uuid}
 	
 
-	
-		/** ens-mysql-mapper|insertMobilePageManage-모바일페이지관리 데이타 생성|julim  */
+	
+		/** ens-mysql-mapper|updateKakaotalkSendBulksResult-카카오톡 문서요청 결과 반영|jhseo  */
+		UPDATE tb_ens_kakao_d10
+		SET external_id = #{externalId}
+		  , envelope_id = #{envelopeId}
+		  , error_code = #{error_code}
+		  , error_message = #{error_message}
+		  , updt_dt = now()
+		  , updusr = 'batch'
+		WHERE unity_sndng_detail_id = #{externalId}
+	
+
+	
+		/** ens-mysql-mapper|insertKkopayMobilePageManage-카카오페이모바일페이지관리 데이타 생성|julim  */
 		INSERT
 		  INTO tb_ens_mobile_page_manage (
-				sndng_detail_id, /* 발송상세 ID*/
-				sndng_se_code, /* 발송 구분 코드 */
-				mobile_page_cn, /* 모바일 페이지 내용 */
-				regist_dt,
-				register
+			sndng_detail_id, /* 발송상세 ID*/
+			sndng_se_code, /* 발송 구분 코드 */
+			mobile_page_cn, /* 모바일 페이지 내용 */
+			regist_dt,
+			register
 		)
 		SELECT tekmd.sndng_detail_id
-				 , 'KKO-MY-DOC'
-				 , teusd.mobile_page_cn
-				 , date_format(now(), '%Y%m%d%H%i%s')
-				 , 'batch'
+			 , 'KKO-MY-DOC'
+			 , teusd.mobile_page_cn
+			 , date_format(now(), '%Y%m%d%H%i%s')
+			 , 'batch'
 		  FROM tb_ens_kakao_my_doc tekmd
 		  JOIN tb_ens_unity_sndng_detail teusd
 		    ON tekmd.unity_sndng_detail_id = teusd.unity_sndng_detail_id
-	   WHERE teusd.unity_sndng_detail_id = #{unitySndngDetailId}
+	     WHERE teusd.unity_sndng_detail_id = #{unitySndngDetailId}
+	
+
+	
+		/** ens-oracle-mapper|insertKkotalkMobilePageManage-카카오톡모바일페이지관리 데이타 생성|jhseo  */
+		INSERT
+		INTO tb_ens_mobile_page_manage (
+			sndng_detail_id, /* 발송상세 ID*/
+			sndng_se_code, /* 발송 구분 코드 */
+			mobile_page_cn, /* 모바일 페이지 내용 */
+			regist_dt,
+			register
+		)
+		SELECT tekmd.sndng_detail_id
+			 , 'KKO-NEW'
+			 , teusd.mobile_page_cn
+			 , date_format(now(), '%Y%m%d%H%i%s')
+			 , 'batch'
+		FROM tb_ens_kakao_d10 tekmd
+		JOIN tb_ens_unity_sndng_detail teusd
+		  ON tekmd.unity_sndng_detail_id = teusd.unity_sndng_detail_id
+		WHERE teusd.unity_sndng_detail_id = #{unitySndngDetailId}
 	
 
 	
diff --git a/mens-core/src/main/java/kr/xit/biz/common/ApiConstants.java b/mens-core/src/main/java/kr/xit/biz/common/ApiConstants.java
index 42ffcab..19c9193 100644
--- a/mens-core/src/main/java/kr/xit/biz/common/ApiConstants.java
+++ b/mens-core/src/main/java/kr/xit/biz/common/ApiConstants.java
@@ -211,9 +211,9 @@ public class ApiConstants {
     @Getter
     public enum SignguCode {
         /**
-         * 교통시설운영처
+         * 춘천
          */
-        TRAFFIC("88328"),
+        CHUNCHEON("51110"),
         /**
          * 승화원 : NICE CI는 교통시설운영처와 동일한 코드 사용
          */
diff --git a/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/v2/KkotalkDTO.java b/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/v2/KkotalkDTO.java
index 6d7f2da..c0cd5c4 100644
--- a/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/v2/KkotalkDTO.java
+++ b/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/v2/KkotalkDTO.java
@@ -87,7 +87,7 @@ public class KkotalkDTO extends KkotalkDocDTO {
     @AllArgsConstructor
     @SuperBuilder
     @EqualsAndHashCode(callSuper = false)
-    public static class BulkSendResponse extends KkotalkErrorDTO {
+    public static class BulkSendResponse {
         private List envelopeIds;
     }
 
diff --git a/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/v2/KkotalkDocDTO.java b/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/v2/KkotalkDocDTO.java
index 7904213..20bdeba 100644
--- a/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/v2/KkotalkDocDTO.java
+++ b/mens-core/src/main/java/kr/xit/biz/ens/model/kakao/v2/KkotalkDocDTO.java
@@ -348,7 +348,7 @@ public class KkotalkDocDTO {
     @AllArgsConstructor
     @SuperBuilder
     //@JsonInclude(JsonInclude.Include.NON_EMPTY)
-    public static class EnvelopeRes {
+    public static class EnvelopeRes extends KkotalkErrorDTO{
         /**
          * 문서 고유 ID, 34자로 고정
          */