feat: 카카오톡 추가 반영 - send, status

main
Jonguk. Lim 2 months ago
parent 379653e497
commit 11eb6238fa

@ -1,21 +1,17 @@
package cokr.xit.ens.core.aop; package cokr.xit.ens.core.aop;
import com.fasterxml.jackson.annotation.JsonAlias; import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.annotation.JsonProperty; import com.google.gson.annotations.*;
import com.google.gson.annotations.SerializedName;
import cokr.xit.ens.core.exception.code.EnsErrCd; import cokr.xit.ens.core.exception.code.*;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.*;
import lombok.Builder; import lombok.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Getter @Getter
@ToString @ToString
@Schema(name = "EnsResponseVO") @Schema(name = "EnsResponseVO")
@NoArgsConstructor @NoArgsConstructor
public class EnsResponseVO<T> implements IApiResponse { public class EnsResponseVO<T> {
@Schema(required = true, title = "에러 코드", example = " ") @Schema(required = true, title = "에러 코드", example = " ")
@JsonProperty("errCode") @JsonProperty("errCode")
@ -34,7 +30,7 @@ public class EnsResponseVO<T> implements IApiResponse {
@JsonAlias({"result_info"}) @JsonAlias({"result_info"})
@SerializedName(value = "resultInfo", alternate = {"result_info"}) @SerializedName(value = "resultInfo", alternate = {"result_info"})
private T resultInfo; private T resultInfo;
@Builder(builderClassName = "okBuilder" ,builderMethodName = "okBuilder") @Builder(builderClassName = "okBuilder" ,builderMethodName = "okBuilder")
EnsResponseVO(T resultInfo) { EnsResponseVO(T resultInfo) {
this.errCode = EnsErrCd.OK; this.errCode = EnsErrCd.OK;

@ -1,9 +1,9 @@
package cokr.xit.ens.modules.kkotalk; package cokr.xit.ens.modules.kkotalk;
import java.util.Arrays; import java.util.*;
import cokr.xit.ens.core.exception.BizRuntimeException; import cokr.xit.ens.core.exception.*;
import lombok.Getter; import lombok.*;
/** /**
* <pre> * <pre>
@ -29,7 +29,7 @@ public class ApiConstants {
/** /**
* profile : local * profile : local
*/ */
public static final boolean IS_PROFILE_LOCAL = PROFILE.matches("local-.*"); public static final boolean IS_PROFILE_LOCAL = PROFILE.matches("local.*");
/** /**
* profile : * profile :

@ -66,20 +66,22 @@ public class SendDetailKkoTalkStatHist {
private String authenticatedAt; private String authenticatedAt;
@Column(name = "token_used_at", nullable = true) @Column(name = "ott_verified_at", nullable = true)
private Long tokenUsedAt; private String ottVerifiedAt;
@Column(name = "read_at", nullable = true) @Column(name = "read_at", nullable = true)
private String readAt; private String readAt;
@Column(name = "read_expired_at", nullable = true)
private String readExpiredAt;
@Column(name = "user_notified_at", nullable = true) @Column(name = "user_notified_at", nullable = true)
private Long userNotifiedAt; private String userNotifiedAt;
@Column(name = "distribution_received_at", nullable = true) @Column(name = "distribution_received_at", nullable = true)
private String docDistributionReceivedAt;//??? private String distributionReceivedAt;//???
@Column(name = "payload", nullable = true) @Column(name = "payload", nullable = true)

@ -5,7 +5,6 @@ import java.util.*;
import org.apache.ibatis.annotations.*; import org.apache.ibatis.annotations.*;
import cokr.xit.ens.modules.common.domain.*; import cokr.xit.ens.modules.common.domain.*;
import cokr.xit.ens.modules.kkomydoc.domain.*;
import cokr.xit.ens.modules.kkotalk.model.*; import cokr.xit.ens.modules.kkotalk.model.*;
/** /**
@ -29,6 +28,8 @@ public interface IKkoTalkMapper {
void updateSndDtlKkoTalk(SendDetailKkoTalkDTO sendDetailKkoTalk); void updateSndDtlKkoTalk(SendDetailKkoTalkDTO sendDetailKkoTalk);
void updateKakaotalkSendBulksResult(SendDetailKkoTalkDTO sendDetailKkoTalk); void updateKakaotalkSendBulksResult(SendDetailKkoTalkDTO sendDetailKkoTalk);
void updateKakaotalkStatusBulksResult(SendDetailKkoTalkDTO sendDetailKkoTalkDTO);
List<SendDetailKkoTalkDTO> findAllBySendMastId(Long sendMastId); List<SendDetailKkoTalkDTO> findAllBySendMastId(Long sendMastId);
@ -37,5 +38,6 @@ public interface IKkoTalkMapper {
List<SendDetailKkoTalkDTO> findAllBySendMastAndEnvlopeIdIsNotNull(SendMast sendMast); List<SendDetailKkoTalkDTO> findAllBySendMastAndEnvlopeIdIsNotNull(SendMast sendMast);
Optional<SendDetailKkoMydoc> findByExternalId(String externalId); //Optional<SendDetailKkoMydoc> findByExternalId(String externalId);
} }

@ -7,7 +7,6 @@ import org.hibernate.validator.constraints.NotEmpty;
import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.annotation.*;
import cokr.xit.ens.core.aop.*;
import cokr.xit.ens.modules.kkotalk.*; import cokr.xit.ens.modules.kkotalk.*;
import io.swagger.v3.oas.annotations.media.*; import io.swagger.v3.oas.annotations.media.*;
import lombok.*; import lombok.*;
@ -190,7 +189,7 @@ public class KkotalkApiDTO {
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public static class ValidTokenRequest extends CmmEnsRequestDTO { public static class ValidTokenRequest {
/** /**
* ID, 34 * ID, 34
*/ */
@ -212,7 +211,7 @@ public class KkotalkApiDTO {
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public static class ValidTokenResponse extends KkotalkErrorDTO implements IApiResponse { public static class ValidTokenResponse extends KkotalkErrorDTO {
/** /**
* ID, 34 * ID, 34
*/ */
@ -231,7 +230,6 @@ public class KkotalkApiDTO {
* ,|| * ,||
* RECEIVE|READ|EXPIRED * RECEIVE|READ|EXPIRED
* </pre> * </pre>
* @see ApiConstants.KkotalkDocStatus
*/ */
private ApiConstants.KkotalkDocStatus status; private ApiConstants.KkotalkDocStatus status;
@ -305,7 +303,7 @@ public class KkotalkApiDTO {
@AllArgsConstructor @AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonInclude(JsonInclude.Include.NON_EMPTY)
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public static class EnvelopeStatusResponse extends ValidTokenResponse implements IApiResponse { public static class EnvelopeStatusResponse extends ValidTokenResponse {
/** /** /** /**
* <pre> * <pre>
* *
@ -401,7 +399,7 @@ public class KkotalkApiDTO {
@AllArgsConstructor @AllArgsConstructor
@SuperBuilder @SuperBuilder
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public static class EnvelopeId extends CmmEnsRequestDTO{ public static class EnvelopeId {
/** /**
* ID, 34 * ID, 34
*/ */

@ -36,7 +36,7 @@ public class KkotalkDTO extends KkotalkApiDTO {
@AllArgsConstructor @AllArgsConstructor
@SuperBuilder @SuperBuilder
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public static class SendRequest extends CmmEnsRequestDTO { public static class SendRequest {
/** /**
* <pre> * <pre>
* - * -
@ -60,7 +60,7 @@ public class KkotalkDTO extends KkotalkApiDTO {
@AllArgsConstructor @AllArgsConstructor
@SuperBuilder @SuperBuilder
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public static class BulkSendRequest extends CmmEnsRequestDTO { public static class BulkSendRequest {
/** /**
* <pre> * <pre>
* - * -
@ -92,7 +92,7 @@ public class KkotalkDTO extends KkotalkApiDTO {
@AllArgsConstructor @AllArgsConstructor
@SuperBuilder @SuperBuilder
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public static class BulkStatusRequest extends CmmEnsRequestDTO { public static class BulkStatusRequest {
@Schema(requiredMode = Schema.RequiredMode.REQUIRED) @Schema(requiredMode = Schema.RequiredMode.REQUIRED)
@Valid @Valid
private List<String> envelopes; private List<String> envelopes;

@ -4,10 +4,12 @@ import java.time.*;
import java.util.*; import java.util.*;
import java.util.stream.*; import java.util.stream.*;
import org.apache.commons.lang.*; import org.springframework.http.*;
import org.springframework.stereotype.*; import org.springframework.stereotype.*;
import org.springframework.transaction.annotation.*; import org.springframework.transaction.annotation.*;
import com.google.gson.*;
import cokr.xit.ens.core.aop.*; import cokr.xit.ens.core.aop.*;
import cokr.xit.ens.core.exception.*; import cokr.xit.ens.core.exception.*;
import cokr.xit.ens.core.exception.code.*; import cokr.xit.ens.core.exception.code.*;
@ -305,54 +307,40 @@ public class KkoTalkService {
OrgMng orgMng = orgMngService.find(orgCd).getResultInfo(); OrgMng orgMng = orgMngService.find(orgCd).getResultInfo();
// FIXME: 카카오톡 토큰검증 API 처리 // FIXME: 카카오톡 토큰검증 API 처리
KkotalkApiDTO.ValidTokenResponse resp = kkoTalkApi.validToken( ResponseEntity<String> resp = kkoTalkApi.validToken(
orgMng,
KkotalkApiDTO.ValidTokenRequest.builder() KkotalkApiDTO.ValidTokenRequest.builder()
.signguCode(orgMng.getOrgCd())
.ffnlgCode("11")
.envelopeId(envelopId) .envelopeId(envelopId)
.token(token) .token(token)
.build() .build()
); );
if (!StringUtils.isEmpty(resp.getErrorCode())){ if (resp.getStatusCode() != HttpStatus.OK)
responseVO = EnsResponseVO.errRsltBuilder() throw new EnsException(EnsErrCd.ERR620, String.format("토큰검증 실패. 실패사유: %s %s", resp.getStatusCode().toString(), resp.getBody()));
.errCode(EnsErrCd.ERR600)
.errMsg(String.format("%s %s", resp.getErrorCode(), resp.getErrorMessage()))
.resultInfo(resp)
.build();
}else {
responseVO = EnsResponseVO.okBuilder() Map<String, Object> mResponse = null;
.resultInfo(resp) try {
.build(); Gson gson = new GsonBuilder().disableHtmlEscaping().registerTypeAdapter(Map.class, new MapDeserailizer()).serializeNulls().create();
mResponse = gson.fromJson(resp.getBody(), Map.class);
} catch (Exception e) {
throw new EnsException(EnsErrCd.ERR505, String.format("토큰검증 응답데이터 파싱 실패. %s", resp.getBody()));
} }
// ResponseEntity<String> resp = kkoMydocApi.token(orgMng.getKkoMdAccessToken(), documentBinderUuid, token); // FIXME: 카카오톡 적용 확인
// if (resp.getStatusCode() != HttpStatus.OK) String envelopeStatus = (String) mResponse.get("envelopeStatus");
// throw new EnsException(EnsErrCd.ERR620, String.format("토큰검증 실패. 실패사유: %s %s", resp.getStatusCode().toString(), resp.getBody())); if (!CmmnUtil.isEmpty(envelopeStatus)) {
responseVO = EnsResponseVO.okBuilder()
// Map<String, Object> mResponse = null; .resultInfo(mResponse)
// try { .build();
// Gson gson = new GsonBuilder().disableHtmlEscaping().registerTypeAdapter(Map.class, new MapDeserailizer()).serializeNulls().create(); } else {
// mResponse = gson.fromJson(resp.getBody(), Map.class); String errorCode = (String) mResponse.get("errorCode");
// } catch (Exception e) { String errorMessage = (String) mResponse.get("errorMessage");
// throw new EnsException(EnsErrCd.ERR505, String.format("토큰검증 응답데이터 파싱 실패. %s", resp.getBody())); responseVO = EnsResponseVO.errRsltBuilder()
// } .errCode(EnsErrCd.ERR600)
.errMsg(String.format("%s %s", errorCode, errorMessage))
// String tokenUsedAt = (String) mResponse.get("token_status"); .resultInfo(mResponse)
// if ("USED".equals(tokenUsedAt)) { .build();
// responseVO = EnsResponseVO.okBuilder() }
// .resultInfo(mResponse)
// .build();
// } else {
// String errorCode = (String) mResponse.get("error_code");
// String errorMessage = (String) mResponse.get("error_message");
// responseVO = EnsResponseVO.errRsltBuilder()
// .errCode(EnsErrCd.ERR600)
// .errMsg(String.format("%s %s", errorCode, errorMessage))
// .resultInfo(mResponse)
// .build();
// }
} catch (EnsException e) { } catch (EnsException e) {
@ -368,6 +356,7 @@ public class KkoTalkService {
} finally { } finally {
if (EnsErrCd.OK.equals(responseVO.getErrCode())) { if (EnsErrCd.OK.equals(responseVO.getErrCode())) {
Map<String, Object> resultInfo = (Map<String, Object>) responseVO.getResultInfo(); Map<String, Object> resultInfo = (Map<String, Object>) responseVO.getResultInfo();
// FIXME: 카카오톡 적용 확인 필요??
sendDetailKkoTalkTokenHistRepository.save(SendDetailKkoTalkTokenHist.builder() sendDetailKkoTalkTokenHistRepository.save(SendDetailKkoTalkTokenHist.builder()
.envelopeId(envelopId) .envelopeId(envelopId)
.envelopeId(externalId) .envelopeId(externalId)
@ -417,21 +406,28 @@ public class KkoTalkService {
OrgMng orgMng = orgMngService.find(orgCd).getResultInfo(); OrgMng orgMng = orgMngService.find(orgCd).getResultInfo();
// FIXME: 카카오툭 토큰 확인 API 호출 처리 // FIXME: 카카오툭 토큰 확인 API 호출 처리
KkotalkApiDTO.KkotalkErrorDTO resp = kkoTalkApi.modifyStatus( ResponseEntity<String> resp = kkoTalkApi.modifyStatus(
orgMng,
KkotalkDTO.EnvelopeId.builder() KkotalkDTO.EnvelopeId.builder()
.envelopeId(envelopeId) .envelopeId(envelopeId)
.signguCode(orgMng.getOrgCd())
.ffnlgCode("11")
.build() .build()
); );
if (StringUtils.isEmpty(resp.getErrorCode())){ if (resp.getStatusCode().equals(HttpStatus.NO_CONTENT)) {
responseVO = EnsResponseVO.okBuilder().build(); responseVO = EnsResponseVO.okBuilder().build();
}else{ } else {
Map<String, Object> mResponse = null;
try {
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
mResponse = gson.fromJson(resp.getBody(), Map.class);
} catch (Exception e) {
throw new EnsException(EnsErrCd.ERR505, String.format("문서상태변경 응답데이터 파싱 실패. %s", resp.getBody()));
}
String errorCode = (String) mResponse.get("error_code");
String errorMessage = (String) mResponse.get("error_message");
responseVO = EnsResponseVO.errBuilder() responseVO = EnsResponseVO.errBuilder()
.errCode(EnsErrCd.ERR600) .errCode(EnsErrCd.ERR600)
.errMsg(String.format("%s %s", resp.getErrorCode(), resp.getErrorMessage())) .errMsg(String.format("%s %s", errorCode, errorMessage))
.build(); .build();
} }

@ -18,6 +18,7 @@ import org.springframework.web.util.*;
import cokr.xit.ens.core.exception.*; import cokr.xit.ens.core.exception.*;
import cokr.xit.ens.core.exception.code.*; import cokr.xit.ens.core.exception.code.*;
import cokr.xit.ens.core.utils.*; import cokr.xit.ens.core.utils.*;
import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.*;
import cokr.xit.ens.modules.kkotalk.model.*; import cokr.xit.ens.modules.kkotalk.model.*;
import lombok.*; import lombok.*;
import lombok.extern.slf4j.*; import lombok.extern.slf4j.*;
@ -42,6 +43,14 @@ import lombok.extern.slf4j.*;
@Component @Component
public class KkoTalkApiService { public class KkoTalkApiService {
private static final String PROFILE = System.getProperty("spring.profiles.active");
/**
* profile : local
*/
private static final boolean IS_PROFILE_LOCAL = PROFILE.matches("local.*");
private static final String PRODUCT_CD = IS_PROFILE_LOCAL ? "D10_1T" : "D10_2";
@Value("${contract.kakao.talk.host}") @Value("${contract.kakao.talk.host}")
private String HOST; private String HOST;
@ -61,7 +70,6 @@ public class KkoTalkApiService {
@Value("#{'${contract.kakao.talk.bulkstatus}'.split(';')}") @Value("#{'${contract.kakao.talk.bulkstatus}'.split(';')}")
private String[] API_BULKSTATUS; private String[] API_BULKSTATUS;
private final ApiWebClientUtil webClient;
private static final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); private static final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
private static final CharSequence ENVELOPE_ID = "{ENVELOPE_ID}"; private static final CharSequence ENVELOPE_ID = "{ENVELOPE_ID}";
@ -74,10 +82,7 @@ public class KkoTalkApiService {
* @param reqDTO KkoPayEltrDocDTO.RequestSendReq * @param reqDTO KkoPayEltrDocDTO.RequestSendReq
* @return KkotalkDTO.SendResponse * @return KkotalkDTO.SendResponse
*/ */
public KkotalkDTO.SendResponse requestSend(final KkotalkDTO.SendRequest reqDTO) { public ResponseEntity<String> requestSend(final OrgMng orgMng, final KkotalkDTO.SendRequest reqDTO) {
if(Checks.isEmpty(reqDTO.getProductCode())){
throw BizRuntimeException.create("상품 코드는 필수 입니다.");
}
List<String> errors = new ArrayList<>(); List<String> errors = new ArrayList<>();
errors = validate(reqDTO.getEnvelope(), errors); errors = validate(reqDTO.getEnvelope(), errors);
@ -93,13 +98,15 @@ public class KkoTalkApiService {
if(Checks.isEmpty(envelope.getPhoneNumber())) Objects.requireNonNull(errors).add("phoneNumber=받는이 전화번호는 필수입니다."); if(Checks.isEmpty(envelope.getPhoneNumber())) Objects.requireNonNull(errors).add("phoneNumber=받는이 전화번호는 필수입니다.");
if(Checks.isEmpty(envelope.getBirthday())) Objects.requireNonNull(errors).add("birthday=받는이 생년월일은 필수입니다."); if(Checks.isEmpty(envelope.getBirthday())) Objects.requireNonNull(errors).add("birthday=받는이 생년월일은 필수입니다.");
} }
if(!Objects.requireNonNull(errors).isEmpty()) throw BizRuntimeException.create(errors.toString()); if(!Objects.requireNonNull(errors).isEmpty()){
return webClient.exchangeKkotalk( return new ResponseEntity<String>("{\""+EnsErrCd.SEND405.getCode() +"\":" + errors.toString() +"}", HttpStatus.BAD_REQUEST);
HOST + API_SEND[0].replace("{PRODUCT_CODE}", reqDTO.getProductCode()), }
return callApi(
HttpMethod.valueOf(API_SEND[1]), HttpMethod.valueOf(API_SEND[1]),
HOST + API_SEND[0].replace("{PRODUCT_CODE}", reqDTO.getProductCode()),
JsonUtils.toJson(envelope), JsonUtils.toJson(envelope),
KkotalkDTO.SendResponse.class, getHeaders(orgMng));
getRlaybsnmInfo(reqDTO));
} }
/** /**
@ -109,17 +116,14 @@ public class KkoTalkApiService {
* @param reqDTO KkopayDocDTO.ValidTokenRequest * @param reqDTO KkopayDocDTO.ValidTokenRequest
* @return KkotalkApiDTO.ValidTokenResponse * @return KkotalkApiDTO.ValidTokenResponse
*/ */
public KkotalkApiDTO.ValidTokenResponse validToken(final KkotalkApiDTO.ValidTokenRequest reqDTO) { public ResponseEntity<String> validToken(final OrgMng orgMng, final KkotalkApiDTO.ValidTokenRequest reqDTO) {
validate(reqDTO, null); validate(reqDTO, null);
return webClient.exchangeKkotalk( return callApi(
HOST
+ API_VALID_TOKEN[0].replace(ENVELOPE_ID, reqDTO.getEnvelopeId())
.replace("{TOKEN}", reqDTO.getToken()),
HttpMethod.valueOf(API_VALID_TOKEN[1]), HttpMethod.valueOf(API_VALID_TOKEN[1]),
HOST + API_VALID_TOKEN[0].replace(ENVELOPE_ID, reqDTO.getEnvelopeId()),
null, null,
KkotalkApiDTO.ValidTokenResponse.class, getHeaders(orgMng));
getRlaybsnmInfo(reqDTO));
} }
/** /**
@ -132,12 +136,16 @@ public class KkoTalkApiService {
* </pre> * </pre>
* @param reqDTO KkopayDocAttrDTO.EnvelopeId * @param reqDTO KkopayDocAttrDTO.EnvelopeId
*/ */
public KkotalkApiDTO.KkotalkErrorDTO modifyStatus(final KkotalkDTO.EnvelopeId reqDTO){ public ResponseEntity<String> modifyStatus(final OrgMng orgMng, final KkotalkDTO.EnvelopeId reqDTO){
validate(reqDTO.getEnvelopeId(), null); validate(reqDTO.getEnvelopeId(), null);
final String url = HOST + API_MODIFY_STATUS[0].replace(ENVELOPE_ID, reqDTO.getEnvelopeId()); final String url = HOST + API_MODIFY_STATUS[0].replace(ENVELOPE_ID, reqDTO.getEnvelopeId());
return webClient.exchangeKkotalk(url, HttpMethod.valueOf(API_MODIFY_STATUS[1]), null, KkotalkApiDTO.KkotalkErrorDTO.class, getRlaybsnmInfo(reqDTO)); return callApi(
HttpMethod.valueOf(API_MODIFY_STATUS[1]),
url,
null,
getHeaders(orgMng));
} }
/** /**
@ -151,80 +159,24 @@ public class KkoTalkApiService {
* @param reqDTO KkotalkDTO.EnvelopeId * @param reqDTO KkotalkDTO.EnvelopeId
* @return KkotalkApiDTO.EnvelopeStatusResponse * @return KkotalkApiDTO.EnvelopeStatusResponse
*/ */
public KkotalkApiDTO.EnvelopeStatusResponse findStatus(final KkotalkApiDTO.EnvelopeId reqDTO){ public ResponseEntity<String> findStatus(final OrgMng orgMng, final KkotalkApiDTO.EnvelopeId reqDTO){
validate(reqDTO, null); validate(reqDTO, null);
String param = "{\"envelopeIds\":" + JsonUtils.toJson(Collections.singletonList(reqDTO.getEnvelopeId())) + "}"; String param = "{\"envelopeIds\":" + JsonUtils.toJson(Collections.singletonList(reqDTO.getEnvelopeId())) + "}";
KkotalkDTO.BulkStatusResponse res = webClient.exchangeKkotalk(
HOST + API_BULKSTATUS[0],
HttpMethod.valueOf(API_BULKSTATUS[1]),
param,
KkotalkDTO.BulkStatusResponse.class,
getRlaybsnmInfo(reqDTO));
return res.getEnvelopeStatus().get(0);
}
/** return callApi(
* <pre> HttpMethod.valueOf(API_BULKSTATUS[1]),
* : POST HOST + API_BULKSTATUS[0],
* -. .
* </pre>
* @param reqDTO KkotalkDTO.BulkSendRequest
* @return KkotalkDTO.BulkSendResponse
*/
public KkotalkDTO.BulkSendResponse requestSendBulk(final KkotalkDTO.BulkSendRequest reqDTO) {
if(Checks.isEmpty(reqDTO.getProductCode())){
throw BizRuntimeException.create("상품 코드는 필수 입니다.");
}
List<String> errors = new ArrayList<>();
List<KkotalkApiDTO.Envelope> envelopes = reqDTO.getEnvelopes();
for(int idx = 0; idx < envelopes.size(); idx++) {
final Set<ConstraintViolation<KkotalkApiDTO.Envelope>> 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, param,
KkotalkDTO.BulkSendResponse.class, getHeaders(orgMng));
getRlaybsnmInfo(reqDTO));
// KkotalkDTO.BulkStatusResponse res = webClient.exchangeKkotalk(
// HOST + API_BULKSTATUS[0],
// HttpMethod.valueOf(API_BULKSTATUS[1]),
// param,
// KkotalkDTO.BulkStatusResponse.class,
// getRlaybsnmInfo(reqDTO));
// return res.getEnvelopeStatus().get(0);
} }
/** /**
@ -235,12 +187,9 @@ public class KkoTalkApiService {
* @param reqDTO KkotalkDTO.BulkSendRequest * @param reqDTO KkotalkDTO.BulkSendRequest
* @return KkotalkDTO.BulkSendResponse * @return KkotalkDTO.BulkSendResponse
*/ */
public ResponseEntity<String> requestSendBulk2(final KkotalkDTO.BulkSendRequest reqDTO) { public ResponseEntity<String> requestSendBulk(final OrgMng orgMng, final KkotalkDTO.BulkSendRequest reqDTO) {
ResponseEntity<String> resEntity = null; ResponseEntity<String> resEntity = null;
reqDTO.setProductCode(PRODUCT_CD);
if(Checks.isEmpty(reqDTO.getProductCode())){
return new ResponseEntity<String>("{\""+EnsErrCd.SEND405.getCode() +"\":\"상품 코드는 필수 입니다\"}", HttpStatus.BAD_REQUEST);
}
List<String> errors = new ArrayList<>(); List<String> errors = new ArrayList<>();
@ -289,7 +238,7 @@ public class KkoTalkApiService {
HttpMethod.valueOf(API_BULKSEND[1]), HttpMethod.valueOf(API_BULKSEND[1]),
HOST + API_BULKSEND[0].replace("{PRODUCT_CODE}", reqDTO.getProductCode()), HOST + API_BULKSEND[0].replace("{PRODUCT_CODE}", reqDTO.getProductCode()),
param, param,
getHeaders()); getHeaders(orgMng));
} }
/** /**
@ -303,7 +252,7 @@ public class KkoTalkApiService {
* @param reqDTO KkotalkDTO.BulkStatusRequest * @param reqDTO KkotalkDTO.BulkStatusRequest
* @return KkotalkDTO.BulkStatusResponse * @return KkotalkDTO.BulkStatusResponse
*/ */
public KkotalkDTO.BulkStatusResponse findBulkStatus(final KkotalkDTO.BulkStatusRequest reqDTO) { public ResponseEntity<String> findBulkStatus(final OrgMng orgMng, final KkotalkDTO.BulkStatusRequest reqDTO) {
List<String> errors = new ArrayList<>(); List<String> errors = new ArrayList<>();
List<String> envelopes = reqDTO.getEnvelopes(); List<String> envelopes = reqDTO.getEnvelopes();
@ -314,15 +263,15 @@ public class KkoTalkApiService {
} }
} }
if(!errors.isEmpty()) { if(!errors.isEmpty()) {
throw BizRuntimeException.create(errors.toString()); return new ResponseEntity<String>("{\""+EnsErrCd.SEND405.getCode() +"\":" + errors.toString() +"}", HttpStatus.BAD_REQUEST);
} }
String param = "{\"envelopeIds\":" + JsonUtils.toJson(envelopes) + "}"; String param = "{\"envelopeIds\":" + JsonUtils.toJson(envelopes) + "}";
return webClient.exchangeKkotalk(
HOST + API_BULKSTATUS[0], return callApi(
HttpMethod.valueOf(API_BULKSTATUS[1]), HttpMethod.valueOf(API_BULKSTATUS[1]),
HOST + API_BULKSTATUS[0],
param, param,
KkotalkDTO.BulkStatusResponse.class, getHeaders(orgMng));
getRlaybsnmInfo(reqDTO));
} }
//------------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------------
@ -336,7 +285,9 @@ public class KkoTalkApiService {
// 추가적인 유효성 검증이 필요 없는 경우 // 추가적인 유효성 검증이 필요 없는 경우
if(errList == null){ if(errList == null){
if(!errors.isEmpty()) throw BizRuntimeException.create(errors.toString()); if(!errors.isEmpty()){
throw BizRuntimeException.create(errors.toString());
}
return null; return null;
} }
errList.addAll(errors); errList.addAll(errors);
@ -344,16 +295,6 @@ public class KkoTalkApiService {
return errList; return errList;
} }
// FIXME: 카카오톡 API 호출 시 API 호출 정보 추가 필요
private CmmEnsRlaybsnmDTO getRlaybsnmInfo(final CmmEnsRequestDTO request){
//return null;//CmmEnsUtils.getRlaybsnmInfo(request.getSignguCode(), request.getFfnlgCode(), SndngSeCode.KAKAO);
return CmmEnsRlaybsnmDTO.builder()
.kakaoDealerRestApiKey("kakaoDealerRestApiKey")
.kakaoPartnerRestApiKey("kakaoPartnerRestApiKey")
.kakaoSettleId("kakaoSettleId")
.build();
}
/** /**
* <pre> : API * <pre> : API
* </pre> * </pre>
@ -435,13 +376,12 @@ public class KkoTalkApiService {
} }
// FIXME: 카카오톡 API 호출 시 API 호출 정보 추가 필요 // FIXME: 카카오톡 API 호출 시 API 호출 정보 추가 필요
private HttpHeaders getHeaders(){ private HttpHeaders getHeaders(final OrgMng orgMng){
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
// headers.setContentType(MediaType.APPLICATION_JSON);
headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8"))); headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8")));
headers.set(HttpHeaders.AUTHORIZATION, String.format("KakaoAK %s", "KakaoDealerRestApiKey")); headers.set(HttpHeaders.AUTHORIZATION, String.format("KakaoAK %s", orgMng.getKakaoDealerRestApiKey()));
headers.set("Target-Authorization", "KakaoPartnerRestApiKey"); headers.set("Target-Authorization", orgMng.getKakaoPartnerRestApiKey());
headers.set("settle-Id", "KakaoSettleId"); headers.set("settle-Id", IS_PROFILE_LOCAL ? orgMng.getKakaoDevSettleId() : orgMng.getKakaoProdSettleId());
return headers; return headers;
} }

@ -5,6 +5,7 @@ import java.util.stream.*;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.*; import org.springframework.context.*;
import org.springframework.http.*;
import org.springframework.stereotype.*; import org.springframework.stereotype.*;
import org.springframework.transaction.annotation.*; import org.springframework.transaction.annotation.*;
@ -23,9 +24,9 @@ import cokr.xit.ens.modules.common.domain.*;
import cokr.xit.ens.modules.common.domain.repository.*; import cokr.xit.ens.modules.common.domain.repository.*;
import cokr.xit.ens.modules.common.domain.support.*; import cokr.xit.ens.modules.common.domain.support.*;
import cokr.xit.ens.modules.common.event.*; import cokr.xit.ens.modules.common.event.*;
import cokr.xit.ens.modules.kkomydoc.domain.repository.*;
import cokr.xit.ens.modules.kkotalk.code.*; import cokr.xit.ens.modules.kkotalk.code.*;
import cokr.xit.ens.modules.kkotalk.domain.*; 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.mapper.*;
import cokr.xit.ens.modules.kkotalk.model.*; import cokr.xit.ens.modules.kkotalk.model.*;
import lombok.*; import lombok.*;
@ -41,11 +42,10 @@ public class KkoTalkRsltFetcher extends ResultProcTemplate {
private final SendMastRepository sendMastRepository; private final SendMastRepository sendMastRepository;
private final IKkoTalkMapper talkMapper; private final IKkoTalkMapper talkMapper;
private final SendDetailKkoMydocStatHistRepository sendDetailKkoMydocStatHistRepository; private final SendDetailKkoTalkStatHistRepository sendDetailKkoTalkStatHistRepository;
private final OrgMngService orgMngService; private final OrgMngService orgMngService;
private final KkoTalkApiService kkoTalkApi; private final KkoTalkApiService kkoTalkApi;
//private final KkoMydocApiSpec kkoMydocApi; @Value("${contract.kakao.talk.bulksend-batch-unit}")
@Value("${contract.kakao.pay.mydoc.api.bulksend-batch-unit}")
private int SEND_BATCH_UNIT; private int SEND_BATCH_UNIT;
@Override @Override
@ -68,100 +68,61 @@ public class KkoTalkRsltFetcher extends ResultProcTemplate {
Lists.partition(sendDetails, SEND_BATCH_UNIT).stream() Lists.partition(sendDetails, SEND_BATCH_UNIT).stream()
.forEach(list -> { .forEach(list -> {
List<String> envelopeIds = null;
String sendRespBody = null; String sendRespBody = null;
String jsonStr = null;
try { try {
List<String> envelopeIds = this.makeMessage(list); envelopeIds = this.makeMessage(list);
KkotalkDTO.BulkStatusResponse resp = kkoTalkApi.findBulkStatus( ResponseEntity<String> resp = kkoTalkApi.findBulkStatus(
orgMng,
KkotalkDTO.BulkStatusRequest.builder() KkotalkDTO.BulkStatusRequest.builder()
.envelopes(envelopeIds) .envelopes(envelopeIds)
.signguCode(orgMng.getOrgCd())
.ffnlgCode("11")
.build() .build()
); );
resp.getEnvelopeStatus().forEach(t -> {}
);
/*
list.stream().forEach(row ->
this.modifyStatInfoByDocumentBinderUuid(row, resp.getEnvelopeStatus())
);
List<Map<String, Object>> documents = (List<Map<String, Object>>) ((Map<String, Object>) mResponse.getResultInfo()).get("documents");
Map<String, KkoMydocApiRespVO> mApiRespVOByDocumentBinderUuid = documents.stream()
.map(row -> this.toApiRespVOMap(row))
.collect(Collectors.toMap(m -> String.valueOf(m.get("key")), m -> (KkoMydocApiRespVO) m.get("value"), (k1, k2) -> k1));
list.stream().forEach(row -> this.modifyStatInfoByDocumentBinderUuid(row, mApiRespVOByDocumentBinderUuid));
*/
/*
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<String> resp = kkoMydocApi.bulkStatus(orgMng.getKkoMdAccessToken(), orgMng.getKkoMdContractUuid(), jsonStr);
if (log.isDebugEnabled()) {
StringBuffer sb = new StringBuffer();
sb.append("\n==============================================================================")
.append("\n[ Kakao Mydoc - StatFetch ]")
.append("\n### Request Info...")
.append("\n" + jsonStr)
.append("\n### Response Info...")
.append("\n" + resp.getBody())
.append("\n==============================================================================");
log.debug(sb.toString());
}
sendRespBody = resp.getBody(); sendRespBody = resp.getBody();
if (resp.getStatusCode() != HttpStatus.OK) if (resp.getStatusCode() != HttpStatus.OK)
throw new EnsException(EnsErrCd.RSLT620, String.format("문서상태조회 중.. %s %s", resp.getStatusCode().toString(), resp.getBody())); throw new EnsException(EnsErrCd.SEND620, String.format("카카오톡 상태 조회 중.. %s %s", resp.getStatusCode().toString(), resp.getBody()));
EnsResponseVO mResponse = this.respMsgToMap(resp.getBody()); EnsResponseVO<?> mResponse = this.respMsgToMap(sendRespBody);
if (!EnsErrCd.OK.equals(mResponse.getErrCode())) if (!EnsErrCd.OK.equals(mResponse.getErrCode()))
throw new EnsException(mResponse.getErrCode(), mResponse.getErrMsg()); throw new EnsException(mResponse.getErrCode(), mResponse.getErrMsg());
List<Map<String, Object>> documents = (List<Map<String, Object>>) ((Map<String, Object>) mResponse.getResultInfo()).get("documents");
List<Map<String, Object>> envelopeStatus = (List<Map<String, Object>>) ((Map<String, Object>) mResponse.getResultInfo()).get("envelopeStatus");
Map<String, KkoMydocApiRespVO> mApiRespVOByDocumentBinderUuid = documents.stream() Map<String, KkoTalkApiRespVO> mApiRespVO = envelopeStatus.stream()
.map(row -> this.toApiRespVOMap(row)) .map(row -> this.toApiRespVOMap(row))
.collect(Collectors.toMap(m -> String.valueOf(m.get("key")), m -> (KkoMydocApiRespVO) m.get("value"), (k1, k2) -> k1)); .collect(Collectors.toMap(m -> String.valueOf(m.get("key")), m -> (KkoTalkApiRespVO) m.get("value"), (k1, k2) -> k1));
list.stream().forEach(row -> this.modifyStatInfoByDocumentBinderUuid(row, mApiRespVOByDocumentBinderUuid)); list.stream().forEach(row -> this.modifyStatInfoByEnvelopeId(row, mApiRespVO));
} catch (EnsException e) { } catch (EnsException e) {
list.stream() list.forEach(row -> row.setError(FieldError.initBuilder()
.forEach(row -> row.setError(FieldError.initBuilder() .errorCode(e.getErrCd().getCode())
.errorCode(e.getErrCd().getCode()) .errorMessage(e.getMessage())
.errorMessage(e.getMessage()) .build())
.build()) );
);
} catch (Exception e) { } catch (Exception e) {
list.forEach(row -> row.setError(FieldError.initBuilder()
.errorCode(EnsErrCd.RSLT500.getCode())
.errorMessage(e.getMessage())
.build())
);
} finally {
// FIXME: 카카오톡 추가 - 카카오톡 테이블 업데이트
list.stream() list.stream()
.forEach(row -> row.setError(FieldError.initBuilder() .forEach(talkMapper::updateKakaotalkStatusBulksResult);
.errorCode(EnsErrCd.RSLT500.getCode())
.errorMessage(e.getMessage())
.build())
);
*/ if (!CmmnUtil.isEmpty(envelopeIds))
} finally { sendDetailKkoTalkStatHistRepository.saveAll(this.toSendDetailStatHist(list, sendRespBody));
// if (!CmmnUtil.isEmpty(jsonStr))
// sendDetailKkoMydocStatHistRepository.saveAll(this.toSendDetailStatHist(list, sendRespBody));
} }
}); });
respVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build(); respVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build();
} catch (EnsException e) { } catch (EnsException e) {
@ -245,40 +206,46 @@ public class KkoTalkRsltFetcher extends ResultProcTemplate {
* -. / Error * -. / Error
* *
*/ */
private void modifyStatInfoByDocumentBinderUuid(SendDetailKkoTalkDTO row, List<KkotalkDTO.BulkStatusResponse> resList) { private void modifyStatInfoByEnvelopeId(SendDetailKkoTalkDTO row, Map<String, KkoTalkApiRespVO> resMap) {
/* KkoTalkApiRespVO apiRespVO = resMap.get(row.getEnvelopeId());
List<KkotalkApiDTO.EnvelopeStatusResponse> resList = response.getEnvelopeStatus();
if (CmmnUtil.isEmpty(envelopeStatus..getError_code())) { if (CmmnUtil.isEmpty(apiRespVO.getErrorCode())) {
Map<String, Object> statusData = (Map<String, Object>) apiRespVO.getData(); Map<String, Object> statusData = (Map<String, Object>) apiRespVO.getData();
String docBoxStatus = statusData.containsKey("doc_box_status") ? (String) statusData.get("doc_box_status") : null; String status = statusData.containsKey("status") ? (String) statusData.get("status") : null;
Long docBoxSentAt = statusData.containsKey("doc_box_sent_at") ? (Long) statusData.get("doc_box_sent_at") : null; String sentAt = statusData.containsKey("sentAt") ? (String) statusData.get("sentAt") : null;
Long docBoxReceivedAt = statusData.containsKey("doc_box_received_at") ? (Long) statusData.get("doc_box_received_at") : null; String receivedAt = statusData.containsKey("receivedAt") ? (String) statusData.get("receivedAt") : null;
Long authenticatedAt = statusData.containsKey("authenticated_at") ? (Long) statusData.get("authenticated_at") : null; String readAt = statusData.containsKey("readAt") ? (String) statusData.get("readAt") : null;
Long tokenUsedAt = statusData.containsKey("token_used_at") ? (Long) statusData.get("token_used_at") : null; String readExpiredAt = statusData.containsKey("readExpiredAt") ? (String) statusData.get("readExpiredAt") : null;
Long docBoxReadAt = statusData.containsKey("doc_box_read_at") ? (Long) statusData.get("doc_box_read_at") : null; String authenticatedAt = statusData.containsKey("authenticatedAt") ? (String) statusData.get("authenticatedAt") : null;
Long userNotifiedAt = statusData.containsKey("user_notified_at") ? (Long) statusData.get("user_notified_at") : null; String ottVerifiedAt = statusData.containsKey("ottVerifiedAt") ? (String) statusData.get("ottVerifiedAt") : null;
String userNotifiedAt = statusData.containsKey("userNotifiedAt") ? (String) statusData.get("userNotifiedAt") : null;
row.setKkoDocStat(CmmnUtil.isEmpty(docBoxStatus) ? row.getKkoDocStat() : KkoMydocStatusCd.valueOfEnum(docBoxStatus)); String distributionReceivedAt = statusData.containsKey("distributionReceivedAt") ? (String) statusData.get("distributionReceivedAt") : null;
row.setKkoDocSentDt(CmmnUtil.isEmpty(row.getKkoDocSentDt()) ? DateUtil.absTimeSecToDate(docBoxSentAt, "yyyyMMddHHmmss") : row.getKkoDocSentDt()); String payload = statusData.containsKey("payload") ? (String) statusData.get("payload") : null;
row.setKkoDocReceivedDt(CmmnUtil.isEmpty(row.getKkoDocReceivedDt()) ? DateUtil.absTimeSecToDate(docBoxReceivedAt, "yyyyMMddHHmmss") : row.getKkoDocReceivedDt());
row.setKkoDocAuthFrstDt(CmmnUtil.isEmpty(row.getKkoDocAuthFrstDt()) ? DateUtil.absTimeSecToDate(authenticatedAt, "yyyyMMddHHmmss") : row.getKkoDocAuthFrstDt()); row.setStatus(CmmnUtil.isEmpty(status) ? row.getStatus() : KkoTalkStatusCd.valueOfEnum(status));
row.setKkoDocTokenVrfyFrstDt(CmmnUtil.isEmpty(row.getKkoDocTokenVrfyFrstDt()) ? DateUtil.absTimeSecToDate(tokenUsedAt, "yyyyMMddHHmmss") : row.getKkoDocTokenVrfyFrstDt()); row.setSentAt(CmmnUtil.isEmpty(row.getSentAt()) ? sentAt : row.getSentAt());
row.setKkoDocReadFrstDt(CmmnUtil.isEmpty(row.getKkoDocReadFrstDt()) ? DateUtil.absTimeSecToDate(docBoxReadAt, "yyyyMMddHHmmss") : row.getKkoDocReadFrstDt()); row.setReceivedAt(CmmnUtil.isEmpty(row.getReceivedAt()) ? receivedAt : row.getReceivedAt());
row.setKkoDocUserNotiedDt(CmmnUtil.isEmpty(row.getKkoDocUserNotiedDt()) ? DateUtil.absTimeSecToDate(userNotifiedAt, "yyyyMMddHHmmss") : row.getKkoDocUserNotiedDt()); row.setReadAt(CmmnUtil.isEmpty(row.getReadAt()) ? readAt : row.getReadAt());
row.setReadExpiresAt(CmmnUtil.isEmpty(row.getReadExpiresAt()) ? readExpiredAt : row.getReadExpiresAt());
row.setAuthenticatedAt(CmmnUtil.isEmpty(row.getAuthenticatedAt()) ? authenticatedAt : row.getAuthenticatedAt());
row.setOttVerifiedAt(CmmnUtil.isEmpty(row.getOttVerifiedAt()) ? ottVerifiedAt : row.getOttVerifiedAt());
row.setUserNotifiedAt(CmmnUtil.isEmpty(row.getUserNotifiedAt()) ? userNotifiedAt : row.getUserNotifiedAt());
row.setDistributionReceivedAt(CmmnUtil.isEmpty(row.getDistributionReceivedAt()) ? distributionReceivedAt : row.getDistributionReceivedAt());
row.setPayload(CmmnUtil.isEmpty(row.getPayload()) ? payload : row.getPayload());
row.setError(FieldError.initBuilder().build()); row.setError(FieldError.initBuilder().build());
} else { } else {
if ("NOT_FOUND".equals(apiRespVO.getError_code()) && "documentBinder를 찾을 수 없습니다.".equals(apiRespVO.getError_message())) if ("NOT_FOUND".equals(apiRespVO.getErrorCode()) && "envelopeStatus를 찾을 수 없습니다.".equals(apiRespVO.getErrorMessage()))
row.setKkoDocStat(KkoMydocStatusCd.INTERNAL_SENT_ERR); row.setStatus(KkoTalkStatusCd.INTERNAL_SENT_ERR);
row.setError(FieldError.initBuilder() row.setError(FieldError.initBuilder()
.errorCode(EnsErrCd.RSLT630.getCode()) .errorCode(EnsErrCd.RSLT630.getCode())
.errorMessage(String.format("%s %s", apiRespVO.getError_code(), apiRespVO.getError_message())) .errorMessage(String.format("%s %s", apiRespVO.getErrorCode(), apiRespVO.getErrorMessage()))
.build()); .build());
} }
*/
} }
/** /**
@ -288,7 +255,7 @@ public class KkoTalkRsltFetcher extends ResultProcTemplate {
* @param respMsg * @param respMsg
* @return * @return
*/ */
private List<SendDetailKkoTalkStatHist> toSendDetailStatHist(List<SendDetailKkoTalk> list, String respMsg) { private List<SendDetailKkoTalkStatHist> toSendDetailStatHist(List<SendDetailKkoTalkDTO> list, String respMsg) {
// Map<String, KkoMydocApiRespVO> mMydocApiRespVOByExtDocUuid = // Map<String, KkoMydocApiRespVO> mMydocApiRespVOByExtDocUuid =
@ -297,8 +264,8 @@ public class KkoTalkRsltFetcher extends ResultProcTemplate {
if (EnsErrCd.OK.equals(respVO.getErrCode())) { if (EnsErrCd.OK.equals(respVO.getErrCode())) {
List<Map<String, Object>> documents = (List<Map<String, Object>>) ((Map<String, Object>) respVO.getResultInfo()).get("envelopes"); List<Map<String, Object>> envelopeStatus = (List<Map<String, Object>>) ((Map<String, Object>) respVO.getResultInfo()).get("envelopeStatus");
Map<String, KkoTalkApiRespVO> mRespVOByExtDocUuid = documents.stream() Map<String, KkoTalkApiRespVO> mRespVO = envelopeStatus.stream()
.map(row -> this.toApiRespVOMap(row)) .map(row -> this.toApiRespVOMap(row))
.collect(Collectors.toMap(m -> String.valueOf(m.get("key")), m -> (KkoTalkApiRespVO) m.get("value"), (k1, k2) -> k1)); .collect(Collectors.toMap(m -> String.valueOf(m.get("key")), m -> (KkoTalkApiRespVO) m.get("value"), (k1, k2) -> k1));
@ -306,21 +273,21 @@ public class KkoTalkRsltFetcher extends ResultProcTemplate {
return list.stream() return list.stream()
.map(row -> { .map(row -> {
KkoTalkApiRespVO apiRespVO = mRespVOByExtDocUuid.get(row.getEnvelopeId()); KkoTalkApiRespVO apiRespVO = mRespVO.get(row.getEnvelopeId());
Map<String, Object> statusData = (Map<String, Object>) apiRespVO.getData(); Map<String, Object> statusData = (Map<String, Object>) apiRespVO.getData();
return SendDetailKkoTalkStatHist.builder() return SendDetailKkoTalkStatHist.builder()
.sendDetailId(row.getSendDetailId()) .sendDetailId(row.getSendDetailId())
.envelopeId(row.getEnvelopeId()) .envelopeId(row.getEnvelopeId())
.externalId(row.getExternalId()) .externalId(row.getExternalId())
// .respRawMsg(gson.toJson(statusData)) .status(statusData.containsKey("status") ? (String) statusData.get("status") : null)
.status(statusData.containsKey("doc_box_status") ? (String) statusData.get("doc_box_status") : null) .sentAt(statusData.containsKey("sentAt") ? (String) statusData.get("sentAt") : null)
// .sentAt(statusData.containsKey("doc_box_sent_at") ? (Long) statusData.get("doc_box_sent_at") : null) .receivedAt(statusData.containsKey("receivedAt") ? (String) statusData.get("receivedAt") : null)
// .receivedAt(statusData.containsKey("doc_box_received_at") ? (Long) statusData.get("doc_box_received_at") : null) .readAt(statusData.containsKey("readAt") ? (String) statusData.get("readAt") : null)
// .authenticatedAt(statusData.containsKey("authenticated_at") ? (Long) statusData.get("authenticated_at") : null) .readExpiredAt(statusData.containsKey("readExpiredAt") ? (String) statusData.get("readExpiredAt") : null)
// .tokenUsedAt(statusData.containsKey("token_used_at") ? (Long) statusData.get("token_used_at") : null) .authenticatedAt(statusData.containsKey("authenticatedAt") ? (String) statusData.get("authenticatedAt") : null)
// .readAt(statusData.containsKey("doc_box_read_at") ? (Long) statusData.get("doc_box_read_at") : null) .ottVerifiedAt(statusData.containsKey("ottVerifiedAt") ? (String) statusData.get("ottVerifiedAt") : null)
// .userNotifiedAt(statusData.containsKey("user_notified_at") ? (Long) statusData.get("user_notified_at") : null) .userNotifiedAt(statusData.containsKey("userNotifiedAt") ? (String) statusData.get("userNotifiedAt") : null)
// .docDistributionReceivedAt(statusData.containsKey("doc_distribution_received_at") ? (Long) statusData.get("doc_distribution_received_at") : null) .distributionReceivedAt(statusData.containsKey("distributionReceivedAt") ? (String) statusData.get("distributionReceivedAt") : null)
.payload(statusData.containsKey("payload") ? (String) statusData.get("payload") : null) .payload(statusData.containsKey("payload") ? (String) statusData.get("payload") : null)
.error(FieldError.initBuilder() .error(FieldError.initBuilder()
.errorCode(apiRespVO.getErrorCode()) .errorCode(apiRespVO.getErrorCode())
@ -348,21 +315,21 @@ public class KkoTalkRsltFetcher extends ResultProcTemplate {
} }
private EnsResponseVO respMsgToMap(String respMsg) { private EnsResponseVO<?> respMsgToMap(String respMsg) {
Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).serializeNulls().create(); Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).serializeNulls().create();
EnsErrCd errCode = EnsErrCd.OK; EnsErrCd errCode = EnsErrCd.OK;
String errMsg = EnsErrCd.OK.getCodeNm(); String errMsg = EnsErrCd.OK.getCodeNm();
Map<String, Object> mResp = null; Map<String, Object> mResp = null;
try { try {
mResp = gson.fromJson(respMsg, Map.class); mResp = gson.fromJson(respMsg, Map.class);
if (CmmnUtil.isEmpty(mResp.get("documents"))) if (CmmnUtil.isEmpty(mResp.get("envelopeStatus")))
throw new EnsException(EnsErrCd.RSLT620, String.format("문서상태조회API 오류. documents 키값이 없습니다. %s", respMsg)); throw new EnsException(EnsErrCd.RSLT620, String.format("카카오톡 상태조회API 오류. envelopeStatus 키값이 없습니다. %s", respMsg));
} catch (EnsException e) { } catch (EnsException e) {
errCode = e.getErrCd(); errCode = e.getErrCd();
errMsg = e.getMessage(); errMsg = e.getMessage();
} catch (Exception e) { } catch (Exception e) {
errCode = EnsErrCd.RSLT511; errCode = EnsErrCd.RSLT511;
errMsg = String.format("문서상태조회API 응답 데이터 JSON 객체 변환 실패. %s", respMsg); errMsg = String.format("카카오톡 상태조회API 응답 데이터 JSON 객체 변환 실패. %s", respMsg);
} }
return EnsErrCd.OK.equals(errCode) ? return EnsErrCd.OK.equals(errCode) ?
EnsResponseVO.okBuilder().resultInfo(mResp).build() EnsResponseVO.okBuilder().resultInfo(mResp).build()

@ -77,38 +77,33 @@ public class KkoTalkSender extends SendProcTemplate {
String sendRespBody = null; String sendRespBody = null;
try { try {
envelopes = this.makeMessage(list); envelopes = this.makeMessage(list);
ResponseEntity<String> resp = kkoTalkApi.requestSendBulk2( ResponseEntity<String> resp = kkoTalkApi.requestSendBulk(
orgMng,
KkotalkDTO.BulkSendRequest.builder() KkotalkDTO.BulkSendRequest.builder()
// FIXME: 카카오톡 신규 추가 - 테스트를 위해 임시로 넣음
.productCode("D10_2")
.envelopes(envelopes) .envelopes(envelopes)
.signguCode(orgMng.getOrgCd())
.ffnlgCode("11")
.build() .build()
); );
sendRespBody = resp.getBody(); sendRespBody = resp.getBody();
if (resp.getStatusCode() != HttpStatus.OK) if (resp.getStatusCode() != HttpStatus.OK)
throw new EnsException(EnsErrCd.SEND620, String.format("전송요청 중.. %s %s", resp.getStatusCode().toString(), resp.getBody())); throw new EnsException(EnsErrCd.SEND620, String.format("전송요청 중.. %s %s", resp.getStatusCode().toString(), resp.getBody()));
EnsResponseVO mResponse = this.respMsgToMap(sendRespBody); EnsResponseVO<?> mResponse = this.respMsgToMap(sendRespBody);
if (!EnsErrCd.OK.equals(mResponse.getErrCode())) if (!EnsErrCd.OK.equals(mResponse.getErrCode()))
throw new EnsException(mResponse.getErrCode(), mResponse.getErrMsg()); throw new EnsException(mResponse.getErrCode(), mResponse.getErrMsg());
List<Map<String, Object>> documents = (List<Map<String, Object>>)((Map<String, Object>)mResponse.getResultInfo()).get( List<Map<String, Object>> envelopeIds = (List<Map<String, Object>>)((Map<String, Object>)mResponse.getResultInfo()).get(
"envelopeIds"); "envelopeIds");
Map<String, KkoTalkApiRespVO> mApiResp = documents.stream() Map<String, KkoTalkApiRespVO> mApiResp = envelopeIds.stream()
.map(this::toApiRespVOMap) .map(this::toApiRespVOMap)
.collect(Collectors.toMap(m -> String.valueOf(m.get("key")), .collect(Collectors.toMap(m -> String.valueOf(m.get("key")),
m -> (KkoTalkApiRespVO)m.get("value"), (k1, k2) -> k1)); m -> (KkoTalkApiRespVO)m.get("value"), (k1, k2) -> k1));
list.stream() list.stream()
.forEach(row -> { .forEach(row -> {
this.modifyTalkSendRsltByExtDocUuid(row, mApiResp); this.modifyTalkSendRsltByExternalId(row, mApiResp);
}); });
@ -164,12 +159,6 @@ public class KkoTalkSender extends SendProcTemplate {
else else
throw new EnsException(EnsErrCd.SEND500, String.format("전체건수 전송 실패(총 %d 건)", sendDetails.size())); throw new EnsException(EnsErrCd.SEND500, String.format("전체건수 전송 실패(총 %d 건)", sendDetails.size()));
} catch (BizRuntimeException be){
respVO = EnsResponseVO.errBuilder()
.errCode(EnsErrCd.SEND500)
.errMsg(be.getMessage())
.build();
} catch (EnsException e) { } catch (EnsException e) {
respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build(); respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build();
@ -199,13 +188,7 @@ public class KkoTalkSender extends SendProcTemplate {
.build()); .build());
} }
} }
// if (respVO != null && EnsErrCd.OK.equals(respVO.getErrCode())) {
// applicationEventPublisher.publishEvent(KkoMydocSentEvent.builder().sendMastId(sendMastId).build());
// } else {
applicationEventPublisher.publishEvent(SendMastStatUpdateEvent.builder().sendMastId(sendMastId).build()); applicationEventPublisher.publishEvent(SendMastStatUpdateEvent.builder().sendMastId(sendMastId).build());
// }
} }
@ -279,7 +262,7 @@ public class KkoTalkSender extends SendProcTemplate {
* @param row SendDetailKkoTalkDTO * @param row SendDetailKkoTalkDTO
* @param map Map<String, KkoTalkApiRespVO> * @param map Map<String, KkoTalkApiRespVO>
*/ */
private void modifyTalkSendRsltByExtDocUuid(SendDetailKkoTalkDTO row, Map<String, KkoTalkApiRespVO> map) { private void modifyTalkSendRsltByExternalId(SendDetailKkoTalkDTO row, Map<String, KkoTalkApiRespVO> map) {
KkoTalkApiRespVO apiRespVO = map.get(row.getExternalId()); KkoTalkApiRespVO apiRespVO = map.get(row.getExternalId());
if (CmmnUtil.isEmpty(apiRespVO.getErrorCode())) { if (CmmnUtil.isEmpty(apiRespVO.getErrorCode())) {
row.setStatus(KkoTalkStatusCd.SENT); row.setStatus(KkoTalkStatusCd.SENT);
@ -421,7 +404,7 @@ public class KkoTalkSender extends SendProcTemplate {
try { try {
mResp = gson.fromJson(respMsg, Map.class); mResp = gson.fromJson(respMsg, Map.class);
if (CmmnUtil.isEmpty(mResp.get("envelopeIds"))) if (CmmnUtil.isEmpty(mResp.get("envelopeIds")))
throw new EnsException(EnsErrCd.SEND620, String.format("전송요청API 오류. envelopeId 키값이 없습니다. %s", respMsg)); throw new EnsException(EnsErrCd.SEND620, String.format("전송요청API 오류. envelopeIds 키값이 없습니다. %s", respMsg));
} catch (EnsException e) { } catch (EnsException e) {
errCode = e.getErrCd(); errCode = e.getErrCd();
errMsg = e.getMessage(); errMsg = e.getMessage();

@ -1,250 +1,250 @@
package cokr.xit.ens.modules.kkotalk.web; // package cokr.xit.ens.modules.kkotalk.web;
//
import org.springframework.http.*; // import org.springframework.http.*;
import org.springframework.web.bind.annotation.*; // import org.springframework.web.bind.annotation.*;
//
import cokr.xit.ens.core.aop.*; // import cokr.xit.ens.core.aop.*;
import cokr.xit.ens.modules.kkotalk.model.*; // import cokr.xit.ens.modules.kkotalk.model.*;
import cokr.xit.ens.modules.kkotalk.service.support.*; // import cokr.xit.ens.modules.kkotalk.service.support.*;
import io.swagger.v3.oas.annotations.*; // import io.swagger.v3.oas.annotations.*;
import io.swagger.v3.oas.annotations.media.*; // import io.swagger.v3.oas.annotations.media.*;
import io.swagger.v3.oas.annotations.tags.*; // import io.swagger.v3.oas.annotations.tags.*;
import lombok.*; // import lombok.*;
import lombok.extern.slf4j.*; // import lombok.extern.slf4j.*;
//
/** // /**
* <pre> // * <pre>
* description : controller // * description : 카카오톡 전자 문서 발송 controller
* packageName : kr.xit.ens.kakao.talk.web // * packageName : kr.xit.ens.kakao.talk.web
* fileName : KkotalkEltrcDocController // * fileName : KkotalkEltrcDocController
* author : julim // * author : julim
* date : 2024-08-12 // * date : 2024-08-12
* ====================================================================== // * ======================================================================
* // * 변경일 변경자 변경 내용
* ---------------------------------------------------------------------- // * ----------------------------------------------------------------------
* 2024-08-12 julim // * 2024-08-12 julim 최초 생성
* // *
* </pre> // * </pre>
*/ // */
@Tag(name = "KkotalkApiController", description = "카카오톡 인증톡 API") // @Tag(name = "KkotalkApiController", description = "카카오톡 인증톡 API")
@Slf4j // @Slf4j
@RequiredArgsConstructor // @RequiredArgsConstructor
@RestController // @RestController
@RequestMapping(value = "/kko/talk/api") // @RequestMapping(value = "/kko/talk/api")
public class KkotalkApiController { // public class KkotalkApiController {
private final KkoTalkApiService service; // private final KkoTalkApiService service;
//
/** // /**
* <pre> // * <pre>
* // * 모바일웹 연계 문서발송 요청
* -. . // * -.이용기관 서버에서 전자문서 서버로 문서발송 처리를 요청합니다.
* </pre> // * </pre>
* @param reqDTO KkopayDocDTO.SendRequest // * @param reqDTO KkopayDocDTO.SendRequest
* @return ApiResponseDTO<KkopayDocDTO.SendResponse> // * @return ApiResponseDTO<KkopayDocDTO.SendResponse>
*/ // */
@Operation(summary = "문서발송 요청", description = "카카오톡 전자문서 서버로 문서발송 처리를 요청") // @Operation(summary = "문서발송 요청", description = "카카오톡 전자문서 서버로 문서발송 처리를 요청")
@io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { // @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = {
@Content(mediaType = "application/json", examples = { // @Content(mediaType = "application/json", examples = {
@ExampleObject( // @ExampleObject(
name = "D10", // name = "D10",
value = "{\n" + // value = "{\n" +
" \"productCode\": \"D10_1\",\n" + // " \"productCode\": \"D10_1\",\n" +
" \"envelope\": {\n" + // " \"envelope\": {\n" +
" \"title\": \"전자문서\",\n" + // " \"title\": \"전자문서\",\n" +
" \"content\": {\n" + // " \"content\": {\n" +
" \"link\": \"https://nps.or.kr\"\n" + // " \"link\": \"https://nps.or.kr\"\n" +
" },\n" + // " },\n" +
" \"guide\": \"국민연금 공단에서 보내는 문서입니다.\",\n" + // " \"guide\": \"국민연금 공단에서 보내는 문서입니다.\",\n" +
" \"payload\": \"이용기관 페이로드\",\n" + // " \"payload\": \"이용기관 페이로드\",\n" +
" \"readExpiresAt\": \"2023-12-31T10:00:00\",\n" + // " \"readExpiresAt\": \"2023-12-31T10:00:00\",\n" +
" \"reviewExpiresAt\": \"2023-12-31T13:00:00\",\n" + // " \"reviewExpiresAt\": \"2023-12-31T13:00:00\",\n" +
" \"useNonPersonalizedNotification\": true,\n" + // " \"useNonPersonalizedNotification\": true,\n" +
" \"phoneNumber\": \"01099999999\",\n" + // " \"phoneNumber\": \"01099999999\",\n" +
" \"name\": \"홍길동\",\n" + // " \"name\": \"홍길동\",\n" +
" \"birthday\": \"20000303\",\n" + // " \"birthday\": \"20000303\",\n" +
" \"externalId\": \"external_id1\"\n" + // " \"externalId\": \"external_id1\"\n" +
" },\n" + // " },\n" +
" \"signguCode\": \"51110\",\n" + // " \"signguCode\": \"51110\",\n" +
" \"ffnlgCode\": \"11\"\n" + // " \"ffnlgCode\": \"11\"\n" +
"}" // "}"
), // ),
@ExampleObject( // @ExampleObject(
name = "D11", // name = "D11",
value = "{\n" + // value = "{\n" +
" \"productCode\": \"D11_1\",\n" + // " \"productCode\": \"D11_1\",\n" +
" \"envelope\": {\n" + // " \"envelope\": {\n" +
" \"title\": \"전자문서\",\n" + // " \"title\": \"전자문서\",\n" +
" \"content\": {\n" + // " \"content\": {\n" +
" \"html\": \"<!DOCTYPEhtml><html><body><h1>MyFirstHeading</h1><p>Myfirstparagraph.</p></body></html>\"\n" + // " \"html\": \"<!DOCTYPEhtml><html><body><h1>MyFirstHeading</h1><p>Myfirstparagraph.</p></body></html>\"\n" +
" },\n" + // " },\n" +
" \"guide\": \"국민연금 공단에서 보내는 문서입니다.\",\n" + // " \"guide\": \"국민연금 공단에서 보내는 문서입니다.\",\n" +
" \"readExpiresAt\": \"2023-12-31T10:00:00\",\n" + // " \"readExpiresAt\": \"2023-12-31T10:00:00\",\n" +
" \"reviewExpiresAt\": \"2023-12-31T13:00:00\",\n" + // " \"reviewExpiresAt\": \"2023-12-31T13:00:00\",\n" +
" \"ci\": \"${CI}\"\n" + // " \"ci\": \"${CI}\"\n" +
" },\n" + // " },\n" +
" \"signguCode\": \"51110\",\n" + // " \"signguCode\": \"51110\",\n" +
" \"ffnlgCode\": \"11\"\n" + // " \"ffnlgCode\": \"11\"\n" +
"}" // "}"
) // )
}) // })
}) @PostMapping(value = "/envelopes", produces = MediaType.APPLICATION_JSON_VALUE) // }) @PostMapping(value = "/envelopes", produces = MediaType.APPLICATION_JSON_VALUE)
public IApiResponse requestSend( // public IApiResponse requestSend(
@RequestBody final KkotalkDTO.SendRequest reqDTO // @RequestBody final KkotalkDTO.SendRequest reqDTO
) { // ) {
return ApiResponseDTO.success(service.requestSend(reqDTO)); // return ApiResponseDTO.success(service.requestSend(reqDTO));
} // }
//
/** // /**
* <pre> // * <pre>
* (Redirect URL /) // * 토큰 유효성 검증(Redirect URL 접속 허용/불허)
* </pre> // * </pre>
* @param reqDTO KkopayDocDTO.ValidTokenRequest // * @param reqDTO KkopayDocDTO.ValidTokenRequest
* @return ApiResponseDTO<KkopayDocDTO.ValidTokenResponse> // * @return ApiResponseDTO<KkopayDocDTO.ValidTokenResponse>
*/ // */
@Operation(summary = "토큰 유효성 검증", description = "Redirect URL 접속 허용/불허") // @Operation(summary = "토큰 유효성 검증", description = "Redirect URL 접속 허용/불허")
@PostMapping(value = "/validToken", produces = MediaType.APPLICATION_JSON_VALUE) // @PostMapping(value = "/validToken", produces = MediaType.APPLICATION_JSON_VALUE)
public IApiResponse validToken( // public IApiResponse validToken(
@RequestBody final KkotalkDTO.ValidTokenRequest reqDTO // @RequestBody final KkotalkDTO.ValidTokenRequest reqDTO
) { // ) {
return ApiResponseDTO.success(service.validToken(reqDTO)); // return ApiResponseDTO.success(service.validToken(reqDTO));
} // }
//
/** // /**
* <pre> // * <pre>
* API // * 문서 열람처리 API
* -. . (OTT ) API . // * -.문서에 대해서 열람 상태로 변경. 사용자가 문서열람 시(OTT 검증 완료 후 페이지 로딩 완료 시점) 반드시 문서 열람 상태 변경 API를 호출해야 함.
* -. // * -.미 호출 시 아래와 같은 문제 발생
* 1) API . // * 1)유통증명시스템을 사용하는 경우 해당 API를 호출한 시점으로 열람정보가 등록되어 미 호출 시 열람정보가 등록 되지 않음.
* 2) API(/v1/envelopes/${ENVELOPE_ID}/read) read_at ) . // * 2)문서상태조회 API(/v1/envelopes/${ENVELOPE_ID}/read) 호출 시 read_at최초 열람시간) 데이터가 내려가지 않음.
* </pre> // * </pre>
* @param reqDTO KkotalkApiDTO.EnvelopeStatusResponse // * @param reqDTO KkotalkApiDTO.EnvelopeStatusResponse
* @return ApiResponseDTO<Void> // * @return ApiResponseDTO<Void>
*/ // */
@Operation(summary = "문서열람처리(문서 상태 변경)", description = "문서열람처리(문서 상태 변경)") // @Operation(summary = "문서열람처리(문서 상태 변경)", description = "문서열람처리(문서 상태 변경)")
@PostMapping(value = "/modifyStatus", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) // @PostMapping(value = "/modifyStatus", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public IApiResponse modifyStatus( // public IApiResponse modifyStatus(
@RequestBody final KkotalkApiDTO.EnvelopeId reqDTO // @RequestBody final KkotalkApiDTO.EnvelopeId reqDTO
) { // ) {
service.modifyStatus(reqDTO); // service.modifyStatus(reqDTO);
return ApiResponseDTO.empty(); // return ApiResponseDTO.empty();
} // }
//
/** // /**
* <pre> // * <pre>
* API // * 문서 상태 조회 API
* -. . // * -.이용기관 서버에서 카카오페이 전자문서 서버로 문서 상태에 대한 조회를 요청 합니다.
* : , flow // * : 발송된 문서의 진행상태를 알고 싶은 경우, flow와 상관없이 요청 가능
* : polling , 5 . // * : polling 방식으로 호출할 경우, 호출 간격은 5초를 권장.
* -.doc_box_status // * -.doc_box_status 상태변경순서
* : SENT() > RECEIVED() > READ()/EXPIRED( ) // * : SENT(송신) > RECEIVED(수신) > READ(열람)/EXPIRED(미열람자료의 기한만료)
* </pre> // * </pre>
* @param reqDTO KkotalkDTO.EnvelopeId // * @param reqDTO KkotalkDTO.EnvelopeId
* @return ApiResponseDTO<KkotalkApiDTO.EnvelopeStatusResponse> // * @return ApiResponseDTO<KkotalkApiDTO.EnvelopeStatusResponse>
*/ // */
@Operation(summary = "문서 상태 조회", description = "문서 상태 조회") // @Operation(summary = "문서 상태 조회", description = "문서 상태 조회")
@PostMapping(value = "/findStatus", produces = MediaType.APPLICATION_JSON_VALUE) // @PostMapping(value = "/findStatus", produces = MediaType.APPLICATION_JSON_VALUE)
public IApiResponse findStatus( // public IApiResponse findStatus(
@RequestBody final KkotalkApiDTO.EnvelopeId reqDTO // @RequestBody final KkotalkApiDTO.EnvelopeId reqDTO
) { // ) {
return ApiResponseDTO.success(service.findStatus(reqDTO)); // return ApiResponseDTO.success(service.findStatus(reqDTO));
} // }
//
@Operation(summary = "대량 문서발송 요청 -> batch sendBulks 에서 호출", description = "카카오페이 전자문서 서버로 대량 문서발송 처리를 요청 -> batch sendBulks 에서 호출") // @Operation(summary = "대량 문서발송 요청 -> batch sendBulks 에서 호출", description = "카카오페이 전자문서 서버로 대량 문서발송 처리를 요청 -> batch sendBulks 에서 호출")
@io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = { // @io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = {
@Content(mediaType = "application/json", examples = { // @Content(mediaType = "application/json", examples = {
@ExampleObject( // @ExampleObject(
name = "D10", // name = "D10",
value = "{\n" + // value = "{\n" +
" \"productCode\": \"D10_1\",\n" + // " \"productCode\": \"D10_1\",\n" +
" \"signguCode\": \"51110\",\n" + // " \"signguCode\": \"51110\",\n" +
" \"ffnlgCode\": \"11\",\n" + // " \"ffnlgCode\": \"11\",\n" +
" \"envelopes\": [\n" + // " \"envelopes\": [\n" +
" {\n" + // " {\n" +
" \"title\": \"전자문서\",\n" + // " \"title\": \"전자문서\",\n" +
" \"content\": {\n" + // " \"content\": {\n" +
" \"html\": \"<!DOCTYPEhtml><html><body><h1>MyFirstHeading</h1><p>Myfirstparagraph.</p></body></html>\"\n" + // " \"html\": \"<!DOCTYPEhtml><html><body><h1>MyFirstHeading</h1><p>Myfirstparagraph.</p></body></html>\"\n" +
" },\n" + // " },\n" +
" \"guide\": \"국민연금 공단에서 보내는 문서입니다.\",\n" + // " \"guide\": \"국민연금 공단에서 보내는 문서입니다.\",\n" +
" \"readExpiresAt\": \"2024-12-31T10:00:00\",\n" + // " \"readExpiresAt\": \"2024-12-31T10:00:00\",\n" +
" \"reviewExpiresAt\": \"2025-03-31T13:00:00\",\n" + // " \"reviewExpiresAt\": \"2025-03-31T13:00:00\",\n" +
" \"phoneNumber\": \"01099999999\",\n" + // " \"phoneNumber\": \"01099999999\",\n" +
" \"name\": \"홍길동\",\n" + // " \"name\": \"홍길동\",\n" +
" \"birthday\": \"20000303\",\n" + // " \"birthday\": \"20000303\",\n" +
" \"externalId\": \"external_id1\"\n" + // " \"externalId\": \"external_id1\"\n" +
" },\n" + // " },\n" +
" {\n" + // " {\n" +
" \"title\": \"전자문서\",\n" + // " \"title\": \"전자문서\",\n" +
" \"content\": {\n" + // " \"content\": {\n" +
" \"html\": \"<!DOCTYPEhtml><html><body><h1>MyFirstHeading</h1><p>Myfirstparagraph.</p></body></html>\"\n" + // " \"html\": \"<!DOCTYPEhtml><html><body><h1>MyFirstHeading</h1><p>Myfirstparagraph.</p></body></html>\"\n" +
" },\n" + // " },\n" +
" \"guide\": \"국민연금 공단에서 보내는 문서입니다.\",\n" + // " \"guide\": \"국민연금 공단에서 보내는 문서입니다.\",\n" +
" \"readExpiresAt\": \"2024-12-31T10:00:00\",\n" + // " \"readExpiresAt\": \"2024-12-31T10:00:00\",\n" +
" \"reviewExpiresAt\": \"2025-03-31T13:00:00\",\n" + // " \"reviewExpiresAt\": \"2025-03-31T13:00:00\",\n" +
" \"hash\": \"b0c34fdc5e2ecb0335919fdad3b2ada28fa3ab90ec16e9055c3e9e05c431c6e8\",\n" + // " \"hash\": \"b0c34fdc5e2ecb0335919fdad3b2ada28fa3ab90ec16e9055c3e9e05c431c6e8\",\n" +
" \"ci\": \"vMtqVxJX56lBgbf9heK3QTc+jVndTfK77i/UJKAzPmBG4n9CazCdd/8YytlFZnN4qofIqgxHpSoiG0yYzgEpJg==\",\n" + // " \"ci\": \"vMtqVxJX56lBgbf9heK3QTc+jVndTfK77i/UJKAzPmBG4n9CazCdd/8YytlFZnN4qofIqgxHpSoiG0yYzgEpJg==\",\n" +
" \"externalId\": \"external_id2\"\n" + // " \"externalId\": \"external_id2\"\n" +
" }\n" + // " }\n" +
" ]\n" + // " ]\n" +
"}" // "}"
), // ),
@ExampleObject( // @ExampleObject(
name = "D11", // name = "D11",
value = "{\n" + // value = "{\n" +
" \"productCode\": \"D11_1\",\n" + // " \"productCode\": \"D11_1\",\n" +
" \"signguCode\": \"51110\",\n" + // " \"signguCode\": \"51110\",\n" +
" \"ffnlgCode\": \"11\",\n" + // " \"ffnlgCode\": \"11\",\n" +
" \"envelopes\": [\n" + // " \"envelopes\": [\n" +
" {\n" + // " {\n" +
" \"title\": \"전자문서\",\n" + // " \"title\": \"전자문서\",\n" +
" \"content\": {\n" + // " \"content\": {\n" +
" \"link\": \"https://nps.or.kr\"\n" + // " \"link\": \"https://nps.or.kr\"\n" +
" },\n" + // " },\n" +
" \"guide\": \"국민연금 공단에서 보내는 문서입니다.\",\n" + // " \"guide\": \"국민연금 공단에서 보내는 문서입니다.\",\n" +
" \"payload\": \"이용기관 페이로드\",\n" + // " \"payload\": \"이용기관 페이로드\",\n" +
" \"readExpiresAt\": \"2024-12-31T10:00:00\",\n" + // " \"readExpiresAt\": \"2024-12-31T10:00:00\",\n" +
" \"reviewExpiresAt\": \"2025-03-31T13:00:00\",\n" + // " \"reviewExpiresAt\": \"2025-03-31T13:00:00\",\n" +
" \"phoneNumber\": \"01099999999\",\n" + // " \"phoneNumber\": \"01099999999\",\n" +
" \"name\": \"홍길동\",\n" + // " \"name\": \"홍길동\",\n" +
" \"birthday\": \"20000303\",\n" + // " \"birthday\": \"20000303\",\n" +
" \"externalId\": \"external_id1\"\n" + // " \"externalId\": \"external_id1\"\n" +
" },\n" + // " },\n" +
" {\n" + // " {\n" +
" \"title\": \"전자문서\",\n" + // " \"title\": \"전자문서\",\n" +
" \"content\": {\n" + // " \"content\": {\n" +
" \"link\": \"https://nps.or.kr\"\n" + // " \"link\": \"https://nps.or.kr\"\n" +
" },\n" + // " },\n" +
" \"guide\": \"국민연금 공단에서 보내는 문서입니다.\",\n" + // " \"guide\": \"국민연금 공단에서 보내는 문서입니다.\",\n" +
" \"payload\": \"이용기관 페이로드\",\n" + // " \"payload\": \"이용기관 페이로드\",\n" +
" \"readExpiresAt\": \"2024-12-31T10:00:00\",\n" + // " \"readExpiresAt\": \"2024-12-31T10:00:00\",\n" +
" \"reviewExpiresAt\": \"2025-03-31T13:00:00\",\n" + // " \"reviewExpiresAt\": \"2025-03-31T13:00:00\",\n" +
" \"ci\": \"${CI}\",\n" + // " \"ci\": \"${CI}\",\n" +
" \"externalId\": \"external_id2\"\n" + // " \"externalId\": \"external_id2\"\n" +
" }\n" + // " }\n" +
" ]\n" + // " ]\n" +
"}" // "}"
) // )
}) // })
}) // })
@PostMapping(value = "/envelopes/bulk", produces = MediaType.APPLICATION_JSON_VALUE) // @PostMapping(value = "/envelopes/bulk", produces = MediaType.APPLICATION_JSON_VALUE)
public IApiResponse requestSendBulk( // public IApiResponse requestSendBulk(
@RequestBody final KkotalkDTO.BulkSendRequest reqDTO // @RequestBody final KkotalkDTO.BulkSendRequest reqDTO
) { // ) {
return ApiResponseDTO.success(service.requestSendBulk(reqDTO)); // return ApiResponseDTO.success(service.requestSendBulk(reqDTO));
} // }
//
/** // /**
* <pre> // * <pre>
* // * 모바일웹 연계 문서발송 요청
* -. . // * -.이용기관 서버에서 전자문서 서버로 문서발송 처리를 요청합니다.
* </pre> // * </pre>
* @param reqDTO KkotalkApiDTO.BulkStatusRequest // * @param reqDTO KkotalkApiDTO.BulkStatusRequest
* @return KkotalkApiDTO.BulkStatusResponse // * @return KkotalkApiDTO.BulkStatusResponse
*/ // */
@Operation(summary = "대량 문서 상태 조회 요청 -> batch statusBulks 에서 호출", description = "카카오페이 전자문서 서버로 대량 문서 상태 조회 요청 -> batch statusBulks 에서 호출") // @Operation(summary = "대량 문서 상태 조회 요청 -> batch statusBulks 에서 호출", description = "카카오페이 전자문서 서버로 대량 문서 상태 조회 요청 -> batch statusBulks 에서 호출")
@PostMapping(value = "/envelopes/bulk/status", produces = MediaType.APPLICATION_JSON_VALUE) // @PostMapping(value = "/envelopes/bulk/status", produces = MediaType.APPLICATION_JSON_VALUE)
public IApiResponse findBulkStatus( // public IApiResponse findBulkStatus(
@RequestBody final KkotalkDTO.BulkStatusRequest reqDTO // @RequestBody final KkotalkDTO.BulkStatusRequest reqDTO
) { // ) {
return ApiResponseDTO.success(service.findBulkStatus(reqDTO)); // return ApiResponseDTO.success(service.findBulkStatus(reqDTO));
} // }
} // }

@ -88,15 +88,25 @@
WHERE send_detail_id = #{sendDetailId} WHERE send_detail_id = #{sendDetailId}
</update> </update>
<!-- <update id="updateKakaotalkStatusBulksResult" parameterType="cokr.xit.ens.modules.kkotalk.model.SendDetailKkoTalkDTO">
, link = #{link} /** iup-kkotalk-mapper|updateKakaotalkStatusBulksResult-카카오톡 문서 상태조회 결과 반영|limju */
, read_expires_at = #{readExpiresAt}, UPDATE ens_snd_dtl_kko_talk
, review_expires_at = #{reviewExpiresAt} SET status = #{status}
, mk_jid = #{mkJid} , sent_at = #{sentAt}
, mk_tmplt_msg_json_data = #{mkTmpltMsgJsonData} , received_at = #{receivedAt}
, bill_uid = #{billUid} , read_at = #{readAt}
, send_mast_id = #{sendMastId} , read_expires_at = #{readExpiredAt}
--> , authenticated_at = #{authenticatedAt}
, ott_verified_at = #{ottVerifiedAt}
, user_notified_at = #{userNotifiedAt}
, distribution_received_at = #{distributionReceivedAt}
, payload = #{payload}
, error_code = #{errorCode}
, error_message = #{errorMessage}
, last_updt_dt = sysdate
WHERE send_detail_id = #{sendDetailId}
</update>
<select id="findAllBySendMastId" parameterType="long" resultType="cokr.xit.ens.modules.kkotalk.model.SendDetailKkoTalkDTO"> <select id="findAllBySendMastId" parameterType="long" resultType="cokr.xit.ens.modules.kkotalk.model.SendDetailKkoTalkDTO">
/** iup-kkotalk-mapper|findAllBySendMastId-카카오톡발송대상 조회|julim */ /** iup-kkotalk-mapper|findAllBySendMastId-카카오톡발송대상 조회|julim */
<include refid="sqlSelectSendDetailKkoTalk"/> <include refid="sqlSelectSendDetailKkoTalk"/>

Loading…
Cancel
Save