feat: 카카오톡 반영

main
Jonguk. Lim 2 months ago
parent 9196e6f3c4
commit 8484377f7a

@ -133,6 +133,15 @@ public class SpringDocConfig {
.build();
}
@Profile({"local", "prod", "dev"})
@Bean
public GroupedOpenApi kkoTalkApiDoc() {
return GroupedOpenApi.builder()
.group("CMPT. 전자고지-kakaotalk 인증톡 API")
.pathsToMatch("/kko/talk/**")
.build();
}
@Profile({"local", "prod", "dev"})
@Bean
public GroupedOpenApi nvSigntalkApiDoc() {

@ -28,8 +28,8 @@ import cokr.xit.ens.modules.kkomydoc.domain.SendDetailKkoMydocTokenHist;
import cokr.xit.ens.modules.kkomydoc.domain.repository.SendDetailKkoMydocTokenHistRepository;
import cokr.xit.ens.modules.kkotalk.model.KkotalkApiDTO;
import cokr.xit.ens.modules.kkotalk.model.KkotalkDTO;
import cokr.xit.ens.modules.kkotalk.service.support.IKkoTalkApiService;
import cokr.xit.ens.modules.kkotalk.service.support.KkoTalkAcceptor;
import cokr.xit.ens.modules.kkotalk.service.support.KkoTalkApiService;
import cokr.xit.ens.modules.kkotalk.service.support.KkoTalkMaker;
import cokr.xit.ens.modules.kkotalk.service.support.KkoTalkRsltFetcher;
import cokr.xit.ens.modules.kkotalk.service.support.KkoTalkRsltProvider;
@ -49,7 +49,7 @@ public class KkoTalkService {
private final KkoTalkRsltFetcher kkoTalkRsltFetcher;
private final KkoTalkRsltProvider kkoTalkRsltProvider;
private final IKkoTalkApiService kkoTalkApi;
private final KkoTalkApiService kkoTalkApi;
private final SendMastRepository sendMastRepository;
private final SendDetailKkoMydocTokenHistRepository sendDetailKkoMydocTokenHistRepository;

@ -0,0 +1,77 @@
package cokr.xit.ens.modules.kkotalk.service.event;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
import cokr.xit.ens.core.aop.EnsResponseVO;
import cokr.xit.ens.core.exception.code.EnsErrCd;
import cokr.xit.ens.modules.kkotalk.service.KkoTalkService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
@RequiredArgsConstructor
public class KkoTalkSendEventListener {
private final KkoTalkService kkoTalkService;
@Order(1)
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void sendRealtime(KkoTalkSendRealtimeEvent event) {
event.getSendMastIds().stream()
.forEach(sendMastId -> {
StringBuffer sb = new StringBuffer();
sb.append("\n=======================================================")
.append("\n[ENS] 카카오톡 인증톡 실시간전송")
.append("\n요청ID: " + sendMastId);
EnsResponseVO responseVO = kkoTalkService.remake(sendMastId);
sb.append("\n제작 결과: " + responseVO.toString());
if (!EnsErrCd.OK.equals(responseVO.getErrCode())) {
sb.append("\n=======================================================");
log.info(sb.toString());
return;
}
responseVO = kkoTalkService.sendBulk(sendMastId);
sb.append("\n전송요청 결과: " + responseVO.toString());
if (!EnsErrCd.OK.equals(responseVO.getErrCode())) {
sb.append("\n=======================================================");
log.info(sb.toString());
return;
}
responseVO = kkoTalkService.statBulk(sendMastId);
sb.append("\n상태갱신 결과: " + responseVO.toString())
.append("\n=======================================================");
log.info(sb.toString());
if (event.getCallback() != null)
event.getCallback().execute();
});
}
@Async
@Order(1)
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void sendReserve(KkoTalkSendReserveEvent event) {
event.getSendMastIds().stream()
.forEach(sendMastId -> {
StringBuffer sb = new StringBuffer();
EnsResponseVO responseVO = kkoTalkService.remake(sendMastId);
sb.append("\n=======================================================")
.append("\n[ENS] 카카오톡 인증톡 예약전송")
.append("\n요청ID: " + sendMastId)
.append("\n제작 결과: " + responseVO.toString())
.append("\n=======================================================");
log.info(sb.toString());
if (event.getCallback() != null)
event.getCallback().execute();
});
}
}

@ -0,0 +1,17 @@
package cokr.xit.ens.modules.kkotalk.service.event;
import java.util.List;
import cokr.xit.ens.core.eventlistner.adaptor.EnsAMSCallbackAdaptor;
import lombok.Builder;
import lombok.Getter;
@Builder
@Getter
public class KkoTalkSendRealtimeEvent {
private List<Long> sendMastIds;
private EnsAMSCallbackAdaptor callback;
}

@ -0,0 +1,17 @@
package cokr.xit.ens.modules.kkotalk.service.event;
import java.util.List;
import cokr.xit.ens.core.eventlistner.adaptor.EnsAMSCallbackAdaptor;
import lombok.Builder;
import lombok.Getter;
@Builder
@Getter
public class KkoTalkSendReserveEvent {
private List<Long> sendMastIds;
private EnsAMSCallbackAdaptor callback;
}

@ -1,93 +0,0 @@
package cokr.xit.ens.modules.kkotalk.service.support;
import cokr.xit.ens.modules.kkotalk.model.KkotalkApiDTO;
import cokr.xit.ens.modules.kkotalk.model.KkotalkDTO;
/**
* <pre>
* description :
* packageName : kr.xit.ens.kakao.talk.service
* fileName : IKkopayEltrcDocService
* author : julim
* date : 2023-04-28
* ======================================================================
*
* ----------------------------------------------------------------------
* 2023-04-28 julim
*
* </pre>
*/
public interface IKkoTalkApiService {
/**
* <pre>
*
* -. .
* </pre>
* @param reqDTO KkotalkApiDTO.SendRequest
* @return KkotalkApiDTO.SendResponse
*/
KkotalkDTO.SendResponse requestSend(final KkotalkDTO.SendRequest reqDTO);
/**
* <pre>
* (Redirect URL /)
* </pre>
* @param reqDTO KkotalkApiDTO.ValidTokenRequest
* @return KkotalkApiDTO.ValidTokenResponse>
*/
KkotalkApiDTO.ValidTokenResponse validToken(final KkotalkApiDTO.ValidTokenRequest reqDTO);
/**
* <pre>
* API
* -. . (OTT ) API .
* -.
* 1) API .
* 2) API(/v1/envelopes/${ENVELOPE_ID}/read) read_at ) .
* </pre>
* @param reqDTO KkotalkDTO.EnvelopeId
*/
KkotalkApiDTO.KkotalkErrorDTO modifyStatus(final KkotalkDTO.EnvelopeId reqDTO);
/**
* <pre>
* API
* -. .
* : , flow
* : polling , 5 .
* -.doc_box_status
* : RECEIVE(, ) > READ()/EXPIRED
* </pre>
* @param reqDTO KkotalkDTO.EnvelopeId
* @return KkotalkApiDTO.EnvelopeStatusResponse
*/
KkotalkApiDTO.EnvelopeStatusResponse findStatus(final KkotalkApiDTO.EnvelopeId reqDTO);
/**
* <pre>
* (bulk)
* -. (bulk) .
* </pre>
* @param reqDTO KkopayDocBulkDTO.BulkSendRequests
* @return KkopayDocBulkDTO.BulkSendResponses
*/
KkotalkDTO.BulkSendResponse requestSendBulk(final KkotalkDTO.BulkSendRequest reqDTO);
/**
* <pre>
* (bulk) API
* -. .
* : , flow
* : polling , 5 .
* : RECEIVED(,) > READ()/EXPIRED
* </pre>
* @param reqDTO KkotalkDTO.BulkStatusRequest
* @return KkotalkDTO.BulkStatusResponse
*/
KkotalkDTO.BulkStatusResponse findBulkStatus(final KkotalkDTO.BulkStatusRequest reqDTO);
//KkotalkApiDTO.ValidTokenResponse findKkotalkReadyAndMblPage(KkotalkApiDTO.ValidTokenRequest reqDTO);
}

@ -45,8 +45,7 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
@RequiredArgsConstructor
@Component
public class KkoTalkApiService implements
IKkoTalkApiService {
public class KkoTalkApiService {
@Value("${contract.kakao.talk.host}")
private String HOST;
@ -78,9 +77,8 @@ public class KkoTalkApiService implements
* -.
* </pre>
* @param reqDTO KkoPayEltrDocDTO.RequestSendReq
* @return ApiResponseDTO<KkopayDocDTO.SendResponse>
* @return KkotalkDTO.SendResponse
*/
@Override
public KkotalkDTO.SendResponse requestSend(final KkotalkDTO.SendRequest reqDTO) {
if(Checks.isEmpty(reqDTO.getProductCode())){
throw BizRuntimeException.create("상품 코드는 필수 입니다.");
@ -114,9 +112,8 @@ public class KkoTalkApiService implements
* (Redirect URL /) : GET
* </pre>
* @param reqDTO KkopayDocDTO.ValidTokenRequest
* @return ApiResponseDTO<KkopayDocDTO.ValidTokenResponse>
* @return KkotalkApiDTO.ValidTokenResponse
*/
@Override
public KkotalkApiDTO.ValidTokenResponse validToken(final KkotalkApiDTO.ValidTokenRequest reqDTO) {
validate(reqDTO, null);
@ -140,7 +137,6 @@ public class KkoTalkApiService implements
* </pre>
* @param reqDTO KkopayDocAttrDTO.EnvelopeId
*/
@Override
public KkotalkApiDTO.KkotalkErrorDTO modifyStatus(final KkotalkDTO.EnvelopeId reqDTO){
validate(reqDTO.getEnvelopeId(), null);
@ -160,7 +156,6 @@ public class KkoTalkApiService implements
* @param reqDTO KkotalkDTO.EnvelopeId
* @return KkotalkApiDTO.EnvelopeStatusResponse
*/
@Override
public KkotalkApiDTO.EnvelopeStatusResponse findStatus(final KkotalkApiDTO.EnvelopeId reqDTO){
validate(reqDTO, null);
@ -182,7 +177,6 @@ public class KkoTalkApiService implements
* @param reqDTO KkotalkDTO.BulkSendRequest
* @return KkotalkDTO.BulkSendResponse
*/
@Override
public KkotalkDTO.BulkSendResponse requestSendBulk(final KkotalkDTO.BulkSendRequest reqDTO) {
if(Checks.isEmpty(reqDTO.getProductCode())){
throw BizRuntimeException.create("상품 코드는 필수 입니다.");
@ -249,7 +243,6 @@ public class KkoTalkApiService implements
* @param reqDTO KkotalkDTO.BulkStatusRequest
* @return KkotalkDTO.BulkStatusResponse
*/
@Override
public KkotalkDTO.BulkStatusResponse findBulkStatus(final KkotalkDTO.BulkStatusRequest reqDTO) {
List<String> errors = new ArrayList<>();
@ -272,27 +265,6 @@ public class KkoTalkApiService implements
getRlaybsnmInfo(reqDTO));
}
// @Override
// public KkotalkApiDTO.ValidTokenResponse findKkotalkReadyAndMblPage(final KkotalkApiDTO.ValidTokenRequest reqDTO) {
// final String url = HOST + API_VALID_TOKEN[0].replace(ENVELOPE_ID, reqDTO.getEnvelopeId())
// .replace("{TOKEN}", reqDTO.getToken());
//
// // 유효성 검증
// final KkotalkApiDTO.ValidTokenResponse validTokenRes = webClient.exchangeKkotalk(url, HttpMethod.valueOf(API_VALID_TOKEN[1]), null,
// KkotalkApiDTO.ValidTokenResponse.class, getRlaybsnmInfo(reqDTO));
//
// // 문서상태 변경
// final String url2 = HOST + API_MODIFY_STATUS[0].replace(ENVELOPE_ID, reqDTO.getEnvelopeId());
//
// // 정상 : HttpStatus.NO_CONTENT(204) return
// // error : body에 error_code, error_message return
// final KkotalkApiDTO.KkotalkErrorDTO errorDTO = webClient.exchangeKkotalk(url2, HttpMethod.valueOf(API_MODIFY_STATUS[1]), null, KkotalkApiDTO.KkotalkErrorDTO.class, getRlaybsnmInfo(reqDTO));
// if(errorDTO != null){
// return ApiResponseDTO.error(errorDTO.getErrorCode(), errorDTO.getErrorMessage());
// }
// return ApiResponseDTO.success();
// }
//-------------------------------------------------------------------------------------------------------------------
private static <T> List<String> validate(T t, List<String> errList) {
final Set<ConstraintViolation<T>> list = validator.validate(t);

@ -52,7 +52,7 @@ public class KkoTalkRsltFetcher extends ResultProcTemplate {
private final IKkoTalkMapper talkMapper;
private final SendDetailKkoMydocStatHistRepository sendDetailKkoMydocStatHistRepository;
private final OrgMngService orgMngService;
private final IKkoTalkApiService kkoTalkApi;
private final KkoTalkApiService kkoTalkApi;
//private final KkoMydocApiSpec kkoMydocApi;
@Value("${contract.kakao.pay.mydoc.api.bulksend-batch-unit}")
private int SEND_BATCH_UNIT;

@ -58,7 +58,7 @@ public class KkoTalkSender extends SendProcTemplate {
private final SendDetailKkoMydocReqHistRepository sendDetailKkoMydocReqHistRepository;
private final OrgMngService orgMngService;
//private final KkoMydocApiSpec kkoMydocApi;
private final IKkoTalkApiService kkoTalkApi;
private final KkoTalkApiService kkoTalkApi;
@Value("${contract.kakao.pay.mydoc.api.bulksend-batch-unit}")
private int SEND_BATCH_UNIT;

@ -10,7 +10,7 @@ import cokr.xit.ens.core.aop.ApiResponseDTO;
import cokr.xit.ens.core.aop.IApiResponse;
import cokr.xit.ens.modules.kkotalk.model.KkotalkApiDTO;
import cokr.xit.ens.modules.kkotalk.model.KkotalkDTO;
import cokr.xit.ens.modules.kkotalk.service.support.IKkoTalkApiService;
import cokr.xit.ens.modules.kkotalk.service.support.KkoTalkApiService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
@ -32,13 +32,13 @@ import lombok.extern.slf4j.Slf4j;
*
* </pre>
*/
@Tag(name = "KkotalkController", description = "카카오톡 전자문서 API")
@Tag(name = "KkotalkApiController", description = "카카오톡 인증톡 API")
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping(value = "/api/ens/kakao/v2")
@RequestMapping(value = "/kko/talk/api")
public class KkotalkApiController {
private final IKkoTalkApiService service;
private final KkoTalkApiService service;
/**
* <pre>

@ -0,0 +1,198 @@
package cokr.xit.ens.modules.kkotalk.web;
import java.util.Map;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cokr.xit.ens.core.aop.EnsResponseVO;
import cokr.xit.ens.core.exception.EnsException;
import cokr.xit.ens.core.exception.code.EnsErrCd;
import cokr.xit.ens.modules.kkotalk.mapper.IKkoTalkMapper;
import cokr.xit.ens.modules.kkotalk.model.KkotalkDTO;
import cokr.xit.ens.modules.kkotalk.service.KkoTalkService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* <pre>
* description : controller
* packageName : kr.xit.ens.kakao.talk.web
* fileName : KkotalkEltrcDocController
* author : julim
* date : 2024-08-12
* ======================================================================
*
* ----------------------------------------------------------------------
* 2024-08-12 julim
*
* </pre>
*/
@Tag(name = "KkotalkController", description = "카카오톡 인증톡")
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping(value = "/kko/talk")
public class KkotalkController {
private final KkoTalkService service;
private final IKkoTalkMapper talkMapper;
@Operation(summary = "접수")
@PostMapping(value = "/accept", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> accept(@RequestBody KkotalkDTO.KkoTalkAcceptReqDTO reqDTO) {
EnsResponseVO<?> responseVO = service.accept(reqDTO);
return new ResponseEntity<>(responseVO, HttpStatus.OK);
}
@io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = {
@Content(mediaType = "application/json", examples = {
@ExampleObject(name = "Sample Example..."
, summary = "제작"
, value = "{\"sendMastId\": 1}")
})
})
@Operation(summary = "제작")
@PostMapping(value = "/make", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> make(@RequestBody Map<String, Long> mParam) {
EnsResponseVO<?> responseVO = service.remake(mParam.get("sendMastId"));
return new ResponseEntity<>(responseVO, HttpStatus.OK);
}
@Operation(summary = "제작(일괄)")
// @PutMapping(value = "/kko/mydoc/make/all", produces = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(value = "/make/all", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> makeAll() {
EnsResponseVO<?> responseVO = service.makeAll();
return new ResponseEntity<>(responseVO, HttpStatus.OK);
}
@io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = {
@Content(mediaType = "application/json", examples = {
@ExampleObject(name = "Sample Example..."
, summary = "(대량)전송요청"
, value = "{\"sendMastId\": 1}")
})
})
@Operation(summary = "(대량)전송요청")
@PostMapping(value = "/send/bulk", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> sendBulk(@RequestBody Map<String, Long> mParam) {
EnsResponseVO<?> responseVO = service.sendBulk(mParam.get("sendMastId"));
return new ResponseEntity<>(responseVO, HttpStatus.OK);
}
@Operation(summary = "(대량)전송요청 일괄")
@PostMapping(value = "/send/bulk/all", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> sendBulkAll() {
EnsResponseVO<?> responseVO = service.sendBulkAll();
return new ResponseEntity<>(responseVO, HttpStatus.OK);
}
@io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = {
@Content(mediaType = "application/json", examples = {
@ExampleObject(name = "Sample Example..."
, summary = "(대량)문서상태 갱신"
, value = "{\"sendMastId\": 1}")
})
})
@Operation(summary = "(대량)문서상태 갱신")
@PostMapping(value = "/stat/bulk", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> statBulk(@RequestBody Map<String, Long> mParam) {
EnsResponseVO<?> responseVO = service.statBulk(mParam.get("sendMastId"));
return new ResponseEntity<>(responseVO, HttpStatus.OK);
}
@Operation(summary = "(대량)문서상태 일괄 갱신")
// @PutMapping(value = "/kko/mydoc/stat/bulk/all", produces = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(value = "/stat/bulk/all", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> statBulkAll() {
EnsResponseVO<?> responseVO = service.statBulkAll();
return new ResponseEntity<>(responseVO, HttpStatus.OK);
}
@io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = {
@Content(mediaType = "application/json", examples = {
@ExampleObject(name = "Sample Example..."
, summary = "토큰(OTT) 검증"
, value = "{\"envelopeId\": \"BIN-ff806328863311ebb61432ac599d6150\", \"token\": \"ZDU3NGU1ZTYtNTk2Yy99OGNjLWJiYjUtYjZmMjI9NzRhOTA4\", \"externalId\": \"A0001\"}")
})
})
@Operation(summary = "토큰(OTT) 검증")
@PostMapping(value = "/token/verify", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> tokenVerify(@RequestBody Map<String, String> mParam) {
final String envelopeId = mParam.get("envelopeId");
final String token = mParam.get("token");
final String externalId = mParam.get("externalId");
KkotalkDTO.SendDetailKkoTalkDTO sendDetail = talkMapper.findFetchByExternalIdAndEnvelopeId(externalId, envelopeId)
.orElseThrow(() -> new EnsException(EnsErrCd.ERR404, "문서를 찾을 수 없습니다."));
EnsResponseVO<?> responseVO = service.tokenVerify("getOrgCd()", envelopeId, token, externalId);
return new ResponseEntity<>(responseVO, HttpStatus.OK);
}
@io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = {
@Content(mediaType = "application/json", examples = {
@ExampleObject(name = "Sample Example..."
, summary = "문서열람 완료처리"
, value = "{\"envelopeId\": \"BIN-ff806328863311ebb61432ac599d6150\"}")
})
})
@Operation(summary = "문서열람 완료처리")
@PostMapping(value = "/read/cmplt", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> readCmplt(@RequestBody Map<String, String> mParam) {
final String envelopeId = mParam.get("envelopeId");
KkotalkDTO.SendDetailKkoTalkDTO sendDetail = talkMapper.findFetchByExternalIdAndEnvelopeId(null, envelopeId)
.orElseThrow(() -> new EnsException(EnsErrCd.ERR404, "문서를 찾을 수 없습니다."));
EnsResponseVO<?> responseVO = service.readCmplt("getOrgCd()", envelopeId);
return new ResponseEntity<>(responseVO, HttpStatus.OK);
}
@io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = {
@Content(mediaType = "application/json", examples = {
@ExampleObject(name = "Sample Example..."
, summary = "전송결과 가져오기"
, value = "{\"sendMastId\": 1}")
})
})
@Operation(summary = "전송결과 가져오기")
@PostMapping(value = "/send/result/provide", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> sendResultProvide(@RequestBody Map<String, Long> mParam) {
EnsResponseVO<?> responseVO = service.sendResultProvide(mParam.get("sendMastId"));
return new ResponseEntity<>(responseVO, HttpStatus.OK);
}
}
Loading…
Cancel
Save