diff --git a/src/main/java/cokr/xit/ens/modules/kkotalk/domain/SendDetailKkoTalk.java b/src/main/java/cokr/xit/ens/modules/kkotalk/domain/SendDetailKkoTalk.java index c03bc6a..304e1b6 100644 --- a/src/main/java/cokr/xit/ens/modules/kkotalk/domain/SendDetailKkoTalk.java +++ b/src/main/java/cokr/xit/ens/modules/kkotalk/domain/SendDetailKkoTalk.java @@ -53,6 +53,7 @@ public class SendDetailKkoTalk extends BaseEntity { @Column(name = "review_expires_at", nullable = true) private String reviewExpiresAt; + @Setter @Column(name = "guide", nullable = true) private String guide; @@ -109,36 +110,46 @@ public class SendDetailKkoTalk extends BaseEntity { * 문서매핑용 식별자 - 최대 40자 * */ + @Setter @Column(name = "external_id", nullable = true) private String externalId; + @Setter @Column(name = "envelope_id", nullable = true) private String envelopeId; // // @Column(name = "status", nullable = true) // private String status; + @Setter @Column(name = "sent_at", nullable = true) private String sentAt; + @Setter @Column(name = "received_at", nullable = true) private String receivedAt; + @Setter @Column(name = "read_at", nullable = true) private String readAt; + @Setter @Column(name = "authenticated_at", nullable = true) private String authenticatedAt; + @Setter @Column(name = "ott_verified_at", nullable = true) private String ottVerifiedAt; + @Setter @Column(name = "is_notification_unavailable", nullable = true) private String isNotificationUnavailable; + @Setter @Column(name = "user_notified_at", nullable = true) private String userNotifiedAt; + @Setter @Column(name = "distribution_received_at", nullable = true) private String distributionReceivedAt; diff --git a/src/main/java/cokr/xit/ens/modules/kkotalk/model/KkoTalkApiRespVO.java b/src/main/java/cokr/xit/ens/modules/kkotalk/model/KkoTalkApiRespVO.java new file mode 100644 index 0000000..9c5c2b5 --- /dev/null +++ b/src/main/java/cokr/xit/ens/modules/kkotalk/model/KkoTalkApiRespVO.java @@ -0,0 +1,21 @@ +package cokr.xit.ens.modules.kkotalk.model; + +import io.swagger.v3.oas.annotations.media.*; +import lombok.*; + +@Getter +@ToString +@Builder +@EqualsAndHashCode +@Schema(name = "KkoTalkApiRespVO") +public class KkoTalkApiRespVO { + + @Schema(title = "응답코드", example = " ") + private String errorCode; + + @Schema(title = "응답메시지", example = " ") + private String errorMessage; + + @Schema(title = "응답데이터", example = " ") + private Object data; +} diff --git a/src/main/java/cokr/xit/ens/modules/kkotalk/model/KkotalkDTO.java b/src/main/java/cokr/xit/ens/modules/kkotalk/model/KkotalkDTO.java index 0207c86..1dce06f 100644 --- a/src/main/java/cokr/xit/ens/modules/kkotalk/model/KkotalkDTO.java +++ b/src/main/java/cokr/xit/ens/modules/kkotalk/model/KkotalkDTO.java @@ -7,6 +7,7 @@ import javax.validation.*; import javax.validation.constraints.*; import cokr.xit.ens.core.model.*; +import cokr.xit.ens.modules.kkotalk.code.*; import cokr.xit.ens.modules.kkotalk.model.config.*; import io.swagger.v3.oas.annotations.media.*; import lombok.*; @@ -130,7 +131,7 @@ public class KkotalkDTO extends KkotalkApiDTO { public static class SendDetailKkoTalkDTO extends Envelope { private String envelopeId; private String link; - private String status; + private KkoTalkStatusCd status; private String sentAt; private String receivedAt; private String readAt; diff --git a/src/main/java/cokr/xit/ens/modules/kkotalk/service/support/KkoTalkApiService.java b/src/main/java/cokr/xit/ens/modules/kkotalk/service/support/KkoTalkApiService.java index 21949c3..98e4096 100644 --- a/src/main/java/cokr/xit/ens/modules/kkotalk/service/support/KkoTalkApiService.java +++ b/src/main/java/cokr/xit/ens/modules/kkotalk/service/support/KkoTalkApiService.java @@ -1,31 +1,20 @@ package cokr.xit.ens.modules.kkotalk.service.support; -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; - -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; - -import org.apache.commons.lang3.StringUtils; +import java.util.*; +import java.util.stream.*; + +import javax.validation.*; + +import org.apache.commons.lang3.*; import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpMethod; -import org.springframework.stereotype.Component; - -import cokr.xit.ens.core.exception.BizRuntimeException; -import cokr.xit.ens.core.utils.ApiWebClientUtil; -import cokr.xit.ens.core.utils.Checks; -import cokr.xit.ens.core.utils.JsonUtils; -import cokr.xit.ens.modules.kkotalk.model.CmmEnsRequestDTO; -import cokr.xit.ens.modules.kkotalk.model.CmmEnsRlaybsnmDTO; -import cokr.xit.ens.modules.kkotalk.model.KkotalkApiDTO; -import cokr.xit.ens.modules.kkotalk.model.KkotalkDTO; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; +import org.springframework.http.*; +import org.springframework.stereotype.*; + +import cokr.xit.ens.core.exception.*; +import cokr.xit.ens.core.utils.*; +import cokr.xit.ens.modules.kkotalk.model.*; +import lombok.*; +import lombok.extern.slf4j.*; /** *
@@ -177,7 +166,7 @@ public class KkoTalkApiService {
      * @param reqDTO KkotalkDTO.BulkSendRequest
      * @return KkotalkDTO.BulkSendResponse
      */
-    public KkotalkDTO.BulkSendResponse requestSendBulk(final KkotalkDTO.BulkSendRequest reqDTO) {
+    public KkotalkDTO.BulkSendResponse requestSendBulk2(final KkotalkDTO.BulkSendRequest reqDTO) {
         if(Checks.isEmpty(reqDTO.getProductCode())){
             throw BizRuntimeException.create("상품 코드는 필수 입니다.");
         }
@@ -232,6 +221,69 @@ public class KkoTalkApiService {
             getRlaybsnmInfo(reqDTO));
     }
 
+    /**
+     * 
+     * 모바일웹 연계 문서발송 요청 : POST
+     * -.이용기관 서버에서 전자문서 서버로 문서발송 처리를 요청합니다.
+     * 
+ * @param reqDTO KkotalkDTO.BulkSendRequest + * @return KkotalkDTO.BulkSendResponse + */ + public String requestSendBulk(final KkotalkDTO.BulkSendRequest reqDTO) { + if(Checks.isEmpty(reqDTO.getProductCode())){ + throw BizRuntimeException.create("상품 코드는 필수 입니다."); + } + + List errors = new ArrayList<>(); + + List envelopes = reqDTO.getEnvelopes(); + for(int idx = 0; idx < envelopes.size(); idx++) { + final Set> list = validator.validate(envelopes.get(idx)); + if (!list.isEmpty()) { + int finalIdx = idx; + errors.addAll(list.stream() + .map(row -> String.format("%s[%d]=%s", row.getPropertyPath(), finalIdx +1, row.getMessageTemplate())) + .collect(Collectors.toList()) + ); + } + } + + for(int idx = 0; idx < envelopes.size(); idx++) { + final KkotalkApiDTO.Envelope envelope = envelopes.get(idx); + + if(envelope.getReviewExpiresAt() != null){ + if(envelope.getReviewExpiresAt().compareTo(envelope.getReadExpiresAt()) < 0){ + errors.add("reviewExpiresAt=재열람 만료일시를 최조 열람 만료일시 보다 큰 날짜로 입력해주세요."); + } + } + + if (Checks.isEmpty(envelope.getCi())) { + if (Checks.isEmpty(envelope.getName())) errors.add(String.format("받는이 이름은 필수입니다(name[%d] 번째 오류)", idx+1)); + if (Checks.isEmpty(envelope.getPhoneNumber())) errors.add(String.format("받는이 전화번호는 필수입니다(phoneNumber[%d] 번째 오류)", idx+1)); + if (Checks.isEmpty(envelope.getBirthday())) errors.add(String.format("받는이 생년월일은 필수입니다(birthday[%d] 번째 오류)", idx+1)); + } else { + final StringBuilder sb = new StringBuilder() + .append(StringUtils.defaultString(envelope.getName(), StringUtils.EMPTY)) + .append(StringUtils.defaultString(envelope.getPhoneNumber(), StringUtils.EMPTY)) + .append(StringUtils.defaultString(envelope.getBirthday(), StringUtils.EMPTY)); + + if(Checks.isNotEmpty(sb.toString())){ + errors.add(String.format("CI가 지정 되었습니다(받는이 정보 불필요:[%d] 번째 오류) .", idx+1)); + } + } + } + if(!errors.isEmpty()){ + throw BizRuntimeException.create(errors.toString()); + } + String param = "{\"envelopes\":" + JsonUtils.toJson(envelopes) + "}"; + return webClient.exchangeKkotalk( + HOST + API_BULKSEND[0].replace("{PRODUCT_CODE}", reqDTO.getProductCode()), + HttpMethod.valueOf(API_BULKSEND[1]), + param, + String.class, + getRlaybsnmInfo(reqDTO)); + } + /** *
      * 대량(bulk) 문서 상태 조회 API : POST
diff --git a/src/main/java/cokr/xit/ens/modules/kkotalk/service/support/KkoTalkSender.java b/src/main/java/cokr/xit/ens/modules/kkotalk/service/support/KkoTalkSender.java
index 0ae1b06..d491c01 100644
--- a/src/main/java/cokr/xit/ens/modules/kkotalk/service/support/KkoTalkSender.java
+++ b/src/main/java/cokr/xit/ens/modules/kkotalk/service/support/KkoTalkSender.java
@@ -1,49 +1,38 @@
 package cokr.xit.ens.modules.kkotalk.service.support;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import org.apache.commons.lang3.StringUtils;
+import java.util.*;
+import java.util.stream.*;
+
+import org.apache.commons.lang3.*;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Propagation;
-import org.springframework.transaction.annotation.Transactional;
-
-import com.google.common.collect.Lists;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-
-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.core.utils.MapDeserailizer;
-import cokr.xit.ens.modules.common.biztmplt.SendProcTemplate;
-import cokr.xit.ens.modules.common.code.PostSeCd;
-import cokr.xit.ens.modules.common.code.StatCd;
-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.domain.SendMast;
-import cokr.xit.ens.modules.common.domain.repository.SendMastRepository;
-import cokr.xit.ens.modules.common.domain.support.FieldError;
-import cokr.xit.ens.modules.common.event.SendMastStatUpdateEvent;
-import cokr.xit.ens.modules.common.monitor.MessageByPhase;
-import cokr.xit.ens.modules.kkomydoc.code.KkoMydocStatusCd;
-import cokr.xit.ens.modules.kkomydoc.domain.SendDetailKkoMydoc;
-import cokr.xit.ens.modules.kkomydoc.domain.SendDetailKkoMydocReqHist;
-import cokr.xit.ens.modules.kkomydoc.domain.repository.SendDetailKkoMydocReqHistRepository;
-import cokr.xit.ens.modules.kkomydoc.model.KkoMydocApiRespVO;
-import cokr.xit.ens.modules.kkotalk.mapper.IKkoTalkMapper;
-import cokr.xit.ens.modules.kkotalk.model.KkotalkApiDTO;
-import cokr.xit.ens.modules.kkotalk.model.KkotalkDTO;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.*;
+import org.springframework.stereotype.*;
+import org.springframework.transaction.annotation.*;
+
+import com.google.common.collect.*;
+import com.google.gson.*;
+
+import cokr.xit.ens.core.aop.*;
+import cokr.xit.ens.core.exception.*;
+import cokr.xit.ens.core.exception.code.*;
+import cokr.xit.ens.core.monitor.slack.event.*;
+import cokr.xit.ens.core.utils.*;
+import cokr.xit.ens.modules.common.biztmplt.*;
+import cokr.xit.ens.modules.common.code.*;
+import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.*;
+import cokr.xit.ens.modules.common.ctgy.sys.mng.service.*;
+import cokr.xit.ens.modules.common.domain.*;
+import cokr.xit.ens.modules.common.domain.repository.*;
+import cokr.xit.ens.modules.common.domain.support.*;
+import cokr.xit.ens.modules.common.event.*;
+import cokr.xit.ens.modules.common.monitor.*;
+import cokr.xit.ens.modules.kkotalk.code.*;
+import cokr.xit.ens.modules.kkotalk.domain.*;
+import cokr.xit.ens.modules.kkotalk.domain.repository.*;
+import cokr.xit.ens.modules.kkotalk.mapper.*;
+import cokr.xit.ens.modules.kkotalk.model.*;
+import lombok.*;
+import lombok.extern.slf4j.*;
 
 // FIXME: 카카오톡 신규 추가
 @Slf4j
@@ -53,13 +42,12 @@ public class KkoTalkSender extends SendProcTemplate {
 
     private final ApplicationEventPublisher applicationEventPublisher;
     private final SendMastRepository sendMastRepository;
-    //private final SendDetailKkoMydocRepository sendDetailKkoMydocRepository;
     private final IKkoTalkMapper talkMapper;
-    private final SendDetailKkoMydocReqHistRepository sendDetailKkoMydocReqHistRepository;
+    private final SendDetailKkoTalkReqHistRepository sendDetailKkoTalkReqHistRepository;
     private final OrgMngService orgMngService;
-    //private final KkoMydocApiSpec kkoMydocApi;
     private final KkoTalkApiService kkoTalkApi;
-    @Value("${contract.kakao.pay.mydoc.api.bulksend-batch-unit}")
+
+    @Value("${contract.kakao.talk.bulksend-batch-unit}")
     private int SEND_BATCH_UNIT;
 
     private Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).disableHtmlEscaping().create();
@@ -84,12 +72,13 @@ public class KkoTalkSender extends SendProcTemplate {
             Lists.partition(sendDetails, SEND_BATCH_UNIT).stream()
                     .forEach(list -> {
 
-                        String sendRespBody = null;
-                        String jsonStr = null;
+                        String resp = null;
+                        List envelopes = null;
+
                         try {
 
-                            List envelopes = this.makeMessage(list);
-                            KkotalkDTO.BulkSendResponse resp = kkoTalkApi.requestSendBulk(
+                            envelopes = this.makeMessage(list);
+                            resp = kkoTalkApi.requestSendBulk(
                                 KkotalkDTO.BulkSendRequest.builder()
                                     .envelopes(envelopes)
                                     .signguCode(orgMng.getOrgCd())
@@ -98,69 +87,37 @@ public class KkoTalkSender extends SendProcTemplate {
                                     .build()
                             );
 
-/*
-                            EnsResponseVO message = this.makeMessage(list);
-                            if (!(EnsErrCd.OK.equals(message.getErrCode()) || null == message.getErrCode()))
-                                throw new EnsException(message.getErrCode(), message.getErrMsg());
-                            jsonStr = String.valueOf(message.getResultInfo());
-
-                            ResponseEntity resp = kkoMydocApi.bulkSend(orgMng.getKkoMdAccessToken(), orgMng.getKkoMdContractUuid(), jsonStr);
-                            if (log.isDebugEnabled()) {
-                                StringBuffer sb = new StringBuffer();
-                                sb.append("\n==============================================================================")
-                                        .append("\n[ Kakao Mydoc - Sending ]")
-                                        .append("\n### Request Info...")
-                                        .append("\n" + jsonStr)
-                                        .append("\n### Response Info...")
-                                        .append("\n" + resp.getBody())
-                                        .append("\n==============================================================================");
-                                log.debug(sb.toString());
-                            }
-
-                            sendRespBody = resp.getBody();
-                            if (resp.getStatusCode() != HttpStatus.OK)
-                                throw new EnsException(EnsErrCd.SEND620, String.format("전송요청 중.. %s %s", resp.getStatusCode().toString(), resp.getBody()));
-                            EnsResponseVO mResponse = this.respMsgToMap(resp.getBody());
+                            EnsResponseVO mResponse = this.respMsgToMap(resp);
                             if (!EnsErrCd.OK.equals(mResponse.getErrCode()))
                                 throw new EnsException(mResponse.getErrCode(), mResponse.getErrMsg());
-                            List> documents = (List>) ((Map) mResponse.getResultInfo()).get("documents");
-
-
+                            List> documents = (List>) ((Map) mResponse.getResultInfo()).get("envelopeIds");
 
-
-                            Map mApiRespVOByExtDocUuid = documents.stream()
-                                    .map(row -> this.toApiRespVOMap(row))
-                                    .collect(Collectors.toMap(m -> String.valueOf(m.get("key")), m -> (KkoMydocApiRespVO) m.get("value"), (k1, k2) -> k1));
+                            Map mApiResp = documents.stream()
+                                .map(this::toApiRespVOMap)
+                                .collect(Collectors.toMap(m -> String.valueOf(m.get("key")), m -> (KkoTalkApiRespVO) m.get("value"), (k1, k2) -> k1));
 
                             list.stream()
-                                    .forEach(row -> this.modifyDocSendRsltByExtDocUuid(row, mApiRespVOByExtDocUuid));
-
-
+                                .forEach(row -> this.modifyTalkSendRsltByExtDocUuid(row, mApiResp));
 
                         } catch (EnsException e) {
 
                             list.stream()
                                     .forEach(row -> {
-                                        row.set(KkoMydocStatusCd.SENT_FAIL);
-                                        row.setError(FieldError.initBuilder()
-                                                .errorCode(e.getErrCd().getCode())
-                                                .errorMessage(e.getMessage())
-                                                .build());
+                                        row.setStatus(KkoTalkStatusCd.SENT_FAIL);
+                                        row.setErrorCode(e.getErrCd().getCode());
+                                        row.setErrorMessage(e.getMessage());
                                     });
                         } catch (Exception e) {
 
                             list.stream()
                                     .forEach(row -> {
-                                        row.setKkoDocStat(KkoMydocStatusCd.SENT_FAIL);
-                                        row.setError(FieldError.initBuilder()
-                                                .errorCode(EnsErrCd.SEND500.getCode())
-                                                .errorMessage(e.getMessage())
-                                                .build());
+                                        row.setStatus(KkoTalkStatusCd.SENT_FAIL);
+                                        row.setErrorCode(EnsErrCd.SEND500.getCode());
+                                        row.setErrorMessage(e.getMessage());
                                     });
-*/
                         } finally {
-//                            if (!CmmnUtil.isEmpty(jsonStr))
-//                                sendDetailKkoMydocReqHistRepository.saveAll(this.toSendDetailReqHist(list, jsonStr, sendRespBody));
+                            if (!CmmnUtil.isEmpty(envelopes))
+                                sendDetailKkoTalkReqHistRepository.saveAll(this.toSendDetailReqHist(list, JsonUtils.toJson(envelopes), resp));
                         }
 
                     });
@@ -172,7 +129,7 @@ public class KkoTalkSender extends SendProcTemplate {
             if (cntSuccess.get() > 0)
                 respVO = EnsResponseVO.okBuilder()
                         .resultInfo(sendDetails.stream()
-//                                .map(row -> this.toResultInfo(row))
+                                .map(row -> this.toResultInfo(row))
                                 .collect(Collectors.toList()))
                         .build();
             else
@@ -199,7 +156,7 @@ public class KkoTalkSender extends SendProcTemplate {
                     applicationEventPublisher.publishEvent(MonitorEvent.builder()
                             .message(MessageByPhase.builder()
                                     .oClass(getClass().getSimpleName() + "." + new Throwable().getStackTrace()[0].getMethodName())
-                                    .postSeCd(PostSeCd.kkoMydoc)
+                                    .postSeCd(PostSeCd.kkoTalk)
                                     .statCd(StatCd.sendfail)
                                     .errCd(respVO.getErrCode())
                                     .message("-.SendMastId: " + sendMastId + "\n" + respVO.getErrMsg())
@@ -268,14 +225,14 @@ public class KkoTalkSender extends SendProcTemplate {
      * @return
      */
     private Map toApiRespVOMap(Map row) {
-        KkoMydocApiRespVO apiRespVO = KkoMydocApiRespVO.builder()
-                .error_code(row.containsKey("error_code") ? String.valueOf(row.get("error_code")) : null)
-                .error_message(row.containsKey("error_message") ? String.valueOf(row.get("error_message")) : null)
-                .data(row.containsKey("document_binder_uuid") ? String.valueOf(row.get("document_binder_uuid")) : null)
+        KkoTalkApiRespVO apiRespVO = KkoTalkApiRespVO.builder()
+                .errorCode(row.containsKey("errorCode") ? String.valueOf(row.get("errorCode")) : null)
+                .errorMessage(row.containsKey("errorMessage") ? String.valueOf(row.get("errorMessage")) : null)
+                .data(row.containsKey("envelopeId") ? String.valueOf(row.get("envelopeId")) : null)
                 .build();
 
         Map m = new HashMap<>();
-        m.put("key", row.get("external_document_uuid"));
+        m.put("key", row.get("externalId"));
         m.put("value", apiRespVO);
         return m;
     }
@@ -284,34 +241,31 @@ public class KkoTalkSender extends SendProcTemplate {
      * 전송요청결과 갱신(update)
      * -. 성공/실패 여부에 따라 문서식별번호(document_binder_uuid) 및 Error 필드 갱신
      *
-     * @param row
-     * @param mApiRespVOByExtDocUuid
+     * @param row SendDetailKkoTalkDTO
+     * @param map Map
      */
-    private void modifyDocSendRsltByExtDocUuid(SendDetailKkoMydoc row, Map mApiRespVOByExtDocUuid) {
-        KkoMydocApiRespVO apiRespVO = mApiRespVOByExtDocUuid.get(row.getPropExternalDocumentUuid());
-        if (CmmnUtil.isEmpty(apiRespVO.getError_code())) {
-            row.setKkoDocStat(KkoMydocStatusCd.SENT);
-            row.setDocumentBinderUuid(String.valueOf(apiRespVO.getData()));
-            row.setError(FieldError.initBuilder().build());
+    private void modifyTalkSendRsltByExtDocUuid(KkotalkDTO.SendDetailKkoTalkDTO row, Map map) {
+        KkoTalkApiRespVO apiRespVO = map.get(row.getExternalId());
+        if (CmmnUtil.isEmpty(apiRespVO.getErrorCode())) {
+            row.setStatus(KkoTalkStatusCd.SENT);
+            row.setEnvelopeId(String.valueOf(apiRespVO.getData()));
+            //row.setErrorCode(FieldError.initBuilder().build());
         } else {
-            row.setKkoDocStat(KkoMydocStatusCd.valueOfEnum(apiRespVO.getError_code()));
-            row.setError(FieldError.initBuilder()
-                    .errorCode(EnsErrCd.SEND630.getCode())
-                    .errorMessage(String.format("%s %s", apiRespVO.getError_code(), apiRespVO.getError_message()))
-                    .build());
+            row.setStatus(KkoTalkStatusCd.valueOfEnum(apiRespVO.getErrorCode()));
+            row.setErrorCode(EnsErrCd.SEND630.getCode());
+            row.setErrorMessage(String.format("%s %s", apiRespVO.getErrorCode(), apiRespVO.getErrorMessage()));
         }
 
     }
 
 
-    private Map toResultInfo(SendDetailKkoMydoc row) {
+    private Map toResultInfo(KkotalkDTO.SendDetailKkoTalkDTO row) {
         Map m = new HashMap<>();
-//        m.put("msgIdx", row.getMsgIdx());
-        m.put("documentBinderUuid", row.getDocumentBinderUuid());
-        m.put("externalDocumentUuid", row.getPropExternalDocumentUuid());
-        if (!CmmnUtil.isEmpty(row.getError())) {
-            m.put("errCd", row.getError().getErrorCode());
-            m.put("errMsg", row.getError().getErrorMessage());
+        m.put("envelopeId", row.getEnvelopeId());
+        m.put("externalId", row.getExternalId());
+        if (!CmmnUtil.isEmpty(row.getErrorCode())) {
+            m.put("errCd", row.getErrorCode());
+            m.put("errMsg", row.getErrorMessage());
         }
         return m;
     }
@@ -324,14 +278,14 @@ public class KkoTalkSender extends SendProcTemplate {
      * @param respMsg
      * @return
      */
-    private List toSendDetailReqHist(List list, String sendMsg, String respMsg) {
+    private List toSendDetailReqHist(List list, String sendMsg, String respMsg) {
 
 
-        List> sendMsgList = (List>) gson.fromJson(sendMsg, Map.class).get("documents");
+        List> sendMsgList = (List>) gson.fromJson(sendMsg, Map.class).get("envelopes");
         Map mSendDetailIds = list.stream()
                 .map(row -> {
                     Map m = new HashMap<>();
-                    m.put("key", row.getPropExternalDocumentUuid());
+                    m.put("key", row.getExternalId());
                     m.put("value", row.getSendDetailId());
                     return m;
                 })
@@ -342,15 +296,15 @@ public class KkoTalkSender extends SendProcTemplate {
 
         if (EnsErrCd.OK.equals(respVO.getErrCode())) {
             Map mRespBody = (Map) respVO.getResultInfo();
-            List> documents = (List>) mRespBody.get("documents");
+            List> documents = (List>) mRespBody.get("envelopeIds");
             Map> mRespMsg = documents.stream()
                     .map(row -> {
                         Map m = new HashMap<>();
-                        m.put("key", String.valueOf(row.get("external_document_uuid")));
+                        m.put("key", String.valueOf(row.get("externalId")));
                         Map mValue = new HashMap<>();
-                        mValue.put("document_binder_uuid", row.get("document_binder_uuid"));
-                        mValue.put("error_code", row.get("error_code"));
-                        mValue.put("error_message", row.get("error_message"));
+                        mValue.put("envelopeId", row.get("envelopeId"));
+                        mValue.put("errorCode", row.get("errorCode"));
+                        mValue.put("errorMessage", row.get("errorMessage"));
                         mValue.put("rawMsg", gson.toJson(row));
                         m.put("value", mValue);
                         return m;
@@ -359,21 +313,22 @@ public class KkoTalkSender extends SendProcTemplate {
 
             return sendMsgList.stream()
                     .map(row -> {
-                        Map property = (Map) row.get("property");
-                        String externalDocumentUuid = property.get("external_document_uuid");
-                        boolean isSuccess = CmmnUtil.isEmpty(mRespMsg.get(externalDocumentUuid).get("error_code"));
+                        //
+                        //Map property = (Map) row.get("property");
+                        String externalId = (String)row.get("externalId");
+                        boolean isSuccess = CmmnUtil.isEmpty(mRespMsg.get(externalId).get("errorCode"));
 
-                        return SendDetailKkoMydocReqHist.builder()
-                                .sendDetailId(mSendDetailIds.get(externalDocumentUuid))
+                        return SendDetailKkoTalkReqHist.builder()
+                                .sendDetailId(mSendDetailIds.get(externalId))
                                 .sendRawMsg(gson.toJson(row))
-                                .externalDocumentUuid(externalDocumentUuid)
-                                .documentBinderUuid(mRespMsg.get(externalDocumentUuid).get("document_binder_uuid"))
-                                .respRawMsg(mRespMsg.get(externalDocumentUuid).get("rawMsg"))
+                                .externalId(externalId)
+                                .envelopeId(mRespMsg.get(externalId).get("envelopeId"))
+                                .respRawMsg(mRespMsg.get(externalId).get("rawMsg"))
                                 .error(FieldError.initBuilder()
                                         .errorCode(isSuccess ? null : EnsErrCd.SEND620.getCode())
                                         .errorMessage(isSuccess ? null : String.format("%s %s"
-                                                , mRespMsg.get(externalDocumentUuid).get("error_code")
-                                                , mRespMsg.get(externalDocumentUuid).get("error_message")
+                                                , mRespMsg.get(externalId).get("errorCode")
+                                                , mRespMsg.get(externalId).get("errorMessage")
                                         ))
                                         .build())
                                 .build();
@@ -383,12 +338,13 @@ public class KkoTalkSender extends SendProcTemplate {
         } else {
             return sendMsgList.stream()
                     .map(row -> {
-                        Map property = (Map) row.get("property");
-                        String externalDocumentUuid = property.get("external_document_uuid");
-                        return SendDetailKkoMydocReqHist.builder()
-                                .sendDetailId(mSendDetailIds.get(externalDocumentUuid))
+                        //Map property = (Map) row.get("property");
+                        String externalId = (String)row.get("externalId");
+
+                        return SendDetailKkoTalkReqHist.builder()
+                                .sendDetailId(mSendDetailIds.get(externalId))
                                 .sendRawMsg(gson.toJson(row))
-                                .externalDocumentUuid(externalDocumentUuid)
+                                .externalId(externalId)
                                 .respRawMsg(respMsg)
                                 .error(FieldError.initBuilder()
                                         .errorCode(respVO.getErrCode().getCode())
@@ -400,13 +356,13 @@ public class KkoTalkSender extends SendProcTemplate {
         }
     }
 
-    private EnsResponseVO respMsgToMap(String respMsg) {
+    private EnsResponseVO respMsgToMap(String respMsg) {
         EnsErrCd errCode = EnsErrCd.OK;
         String errMsg = EnsErrCd.OK.getCodeNm();
         Map mResp = null;
         try {
             mResp = gson.fromJson(respMsg, Map.class);
-            if (CmmnUtil.isEmpty(mResp.get("documents")))
+            if (CmmnUtil.isEmpty(mResp.get("envelopeIds")))
                 throw new EnsException(EnsErrCd.SEND620, String.format("전송요청API 오류. documents 키값이 없습니다. %s", respMsg));
         } catch (EnsException e) {
             errCode = e.getErrCd();
diff --git a/src/main/resources/config/conf-contract.yml b/src/main/resources/config/conf-contract.yml
index bbb64bf..14d0a34 100644
--- a/src/main/resources/config/conf-contract.yml
+++ b/src/main/resources/config/conf-contract.yml
@@ -29,6 +29,7 @@ contract:
               payresult: /iup/kakao/pay-result
     talk:
       host: https://edoc-gw.kakao.com
+      bulksend-batch-unit: 100
       send: /v1/envelopes/{PRODUCT_CODE};POST
       bulksend: /v1/bulk/envelopes/{PRODUCT_CODE};POST
       validToken: /v1/envelopes/{ENVELOPE_ID}/tokens/{TOKEN}/verify;GET