diff --git a/.claude/.gitignore b/.claude/.gitignore new file mode 100644 index 00000000..53ced0f0 --- /dev/null +++ b/.claude/.gitignore @@ -0,0 +1 @@ +/settings.local.json diff --git a/src/main/java/itn/com/cmm/util/MsgSendUtils.java b/src/main/java/itn/com/cmm/util/MsgSendUtils.java index e7409a87..cda92413 100644 --- a/src/main/java/itn/com/cmm/util/MsgSendUtils.java +++ b/src/main/java/itn/com/cmm/util/MsgSendUtils.java @@ -229,8 +229,8 @@ public final class MsgSendUtils { placeholders.put("[*4*]", MjonMsgSendVO::getRep4); boolean hasPerformedSpamCheck = false; // 치환 문자가 없는 경우, 스팸 체크가 한 번만 수행되도록 제어 - boolean hasPerformedMsgType = false; // 치환 문자가 없는 경우, 스팸 체크가 한 번만 수행되도록 제어 - boolean hasPerformedDelayYn = false; // 치환 문자가 없는 경우, 스팸 체크가 한 번만 수행되도록 제어 + boolean hasPerformedMsgType = false; // 치환 문자가 없는 경우, 메세지 타입 체크 한번 + boolean hasPerformedDelayYn = false; // 치환 문자가 없는 경우, String msgKind = mjonMsgVO.getMsgKind(); String smsTxtTemp = mjonMsgVO.getSmsTxt(); @@ -257,10 +257,6 @@ public final class MsgSendUtils { for (Map.Entry> entry : placeholders.entrySet()) { String placeholder = entry.getKey(); String value = entry.getValue().apply(sendVO); -// log.info(" + smsTxtTemp [{}]", smsTxtTemp); -// log.info(" + placeholder [{}]", placeholder); -// log.info(" + value [{}]", value); -// log.info(" + smsTxtTemp.contains(placeholder) [{}]", smsTxtTemp.contains(placeholder)); if (smsTxt.contains(placeholder)) { if (StringUtils.isEmpty(value)) { // statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "치환 문구중 " + placeholder + " 데이터가 없습니다."); diff --git a/src/main/java/itn/let/kakao/kakaoComm/KakaoSendAdvcVO.java b/src/main/java/itn/let/kakao/kakaoComm/KakaoSendAdvcVO.java index ccb4fe8c..ac2ea6c2 100644 --- a/src/main/java/itn/let/kakao/kakaoComm/KakaoSendAdvcVO.java +++ b/src/main/java/itn/let/kakao/kakaoComm/KakaoSendAdvcVO.java @@ -67,13 +67,16 @@ public class KakaoSendAdvcVO implements Serializable { private String kakaoAtPrice; // 카카오 알림톡 단가 private String bizJsonName; // 카카오 알림톡 단가 private String reserveYn; // 카카오 알림톡 단가 - private String atDelayYn; // 카카오 알림톡 단가 + private String atDelayYn; // 지연 문자 발송 private String bizKakaoResendOrgnlTxt; // 카카오 알림톡 단가 private String bizKakaoResendType; // 카카오 알림톡 단가 private String filePath1; // 대체문자 이미지 private String fileCnt; // 파일 카운트 private String bizKakaoImageType; // 파일 카운트 + private String spamStatus; + + diff --git a/src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java b/src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java index bcfb9052..b84828cc 100644 --- a/src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java +++ b/src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java @@ -40,6 +40,7 @@ import itn.let.mjo.spammsg.web.ComGetSpamStringParser; import itn.let.module.base.PriceAndPoint; import itn.let.sym.site.service.JoinSettingVO; import itn.let.uss.umt.service.MberManageVO; +import itn.let.uss.umt.service.UserManageVO; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -134,8 +135,16 @@ public class KakaoSendUtil { // 사용자 개인 단가 정보 불러오기 MberManageVO mberManageVO = mjonMsgDataService.selectMberManageInfo(kakaoVO.getUserId()); + + float shortPrice = getValidPrice(mberManageVO.getShortPrice(), sysJoinSetVO.getShortPrice()); + float longPrice = getValidPrice(mberManageVO.getLongPrice(), sysJoinSetVO.getLongPrice()); + float kakaoAtPrice = getValidPrice(mberManageVO.getKakaoAtPrice(), sysJoinSetVO.getKakaoAtPrice()); + String shortPStr = Float.toString(shortPrice); + String mmsPStr = Float.toString(longPrice); + String kakaoAtPStr = Float.toString(kakaoAtPrice); + /** @MSGID KEY값 */ List idList = mjonCommon.getNextCustomMsgCId(kakaoVO.getVarListMap().size()); @@ -152,22 +161,6 @@ public class KakaoSendUtil { /** @Map에 총 갯수가 수신자 갯수와 동일함 */ List> varList = kakaoVO.getVarListMap(); - /* - for (int i = 0; i < varList.size(); i++) { - Map map = varList.get(i); - for (Map.Entry entry : map.entrySet()) { - // key=value 형태로 로그 출력 - log.info("varList[{}] {} = {}", i, entry.getKey(), entry.getValue()); - } - } - - if(1==1) { - - // 강제로 예외 발생 - throw new RuntimeException("강제 예외 발생 테스트"); - } - */ - for (int i = 0; i < varList.size(); i++) { // for(Map variables : kakaoVO.getVarListMap()) { // 치환 데이터 @@ -176,6 +169,12 @@ public class KakaoSendUtil { /** @공통 기본값 */ KakaoSendAdvcVO sendVO = createATSendVO(kakaoVO); + // 공통 가격 설정 + sendVO.setSmsPrice(shortPStr); + sendVO.setMmsPrice(mmsPStr); + sendVO.setKakaoAtPrice(kakaoAtPStr); + + String msgId = idList.get(i); sendVO.setMsgId(msgId); @@ -191,6 +190,7 @@ public class KakaoSendUtil { String templateContentTemp = templateContent; String templateTitleTemp = templateTitle; + // api가 아니면 if(!isApiData) { if (hasContentReplacement) { templateContentTemp = mjonCommon.ATReplaceTemplateVariables(templateContent, variables); @@ -199,7 +199,8 @@ public class KakaoSendUtil { } } }else { - + templateContentTemp = variables.get("templateContent"); + templateTitleTemp = variables.get("templateTitle"); } @@ -217,44 +218,19 @@ public class KakaoSendUtil { String subMsgTxtTemp = subMsgTxt; // Step 1-4: 실패 대체 문자 치환데이터 설정 if("Y".equals(kakaoVO.getSubMsgSendYn())) { // 대체문자가 있나? - if ("Y".equals(kakaoVO.getSubMsgTxtReplYn())) { // 치환데이터가 있나? - subMsgTxtTemp = mjonCommon.ATReplaceTemplateVariables(subMsgTxt, variables); + // api가 아니면 + if(!isApiData) { + if ("Y".equals(kakaoVO.getSubMsgTxtReplYn())) { // 치환데이터가 있나? + subMsgTxtTemp = mjonCommon.ATReplaceTemplateVariables(subMsgTxt, variables); + } + }else { + subMsgTxtTemp = variables.get("subMsgTxt"); } sendVO.setSubMsgTxt(subMsgTxtTemp);// 실패 } sendVO.setSubMsgSendYn(kakaoVO.getSubMsgSendYn()); - /* - log.info("kakaoSendAdvcVO Details: [callTo={}\n, templateContent=\n{}\n, subMsgTxt=\n{}]\n\n\n\n", - kakaoSendAdvcVO.getCallTo(), - kakaoSendAdvcVO.getTemplateContent(), - kakaoSendAdvcVO.getSubMsgTxt() - ); - */ - - // Step1 END - - -// step3 -// 바이트 수 체크 및 금액설정 - - - // 유효한 단가 계산 - float shortPrice = getValidPrice(mberManageVO.getShortPrice(), sysJoinSetVO.getShortPrice()); - float longPrice = getValidPrice(mberManageVO.getLongPrice(), sysJoinSetVO.getLongPrice()); - float kakaoAtPrice = getValidPrice(mberManageVO.getKakaoAtPrice(), sysJoinSetVO.getKakaoAtPrice()); - - - String shortPStr = Float.toString(shortPrice); - String mmsPStr = Float.toString(longPrice); - String kakaoAtPStr = Float.toString(kakaoAtPrice); - - // 공통 가격 설정 - sendVO.setSmsPrice(shortPStr); - sendVO.setMmsPrice(mmsPStr); - sendVO.setKakaoAtPrice(kakaoAtPStr); - if("Y".equals(kakaoVO.getSubMsgSendYn())) { int smsTxtByte = mjonCommon.getSmsTxtBytes(sendVO.getSubMsgTxt()); @@ -325,21 +301,36 @@ public class KakaoSendUtil { * @description : * @return : List * @param kakaoVO - * @param isNotified + * @param isHolidayNotified * @param statusResponse * @return * @throws Exception * */ - public List populateSendListsFT(KakaoVO kakaoVO, boolean isNotified, StatusResponse statusResponse) throws Exception { + public List populateSendListsFT(KakaoVO kakaoVO + , boolean isHolidayNotified + , StatusResponse statusResponse + , UserManageVO userManageVO + , List resultSpamTxt + ) throws Exception { //사용자 현재 보유 금액 불러오기(문자 발송 금액 차감 이전 금액) // String befCash = kakaoVO.getBefCash(); log.info("kakaoVO.ftToString() :: [{}]", kakaoVO.ftToString()); + + // 예약 시간 기본값 설정 + Date now = new Date(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + + String atSmishingYn = userManageVO.getAtSmishingYn(); + String exceptSpamYn = userManageVO.getExceptSpamYn(); + + List kakaoSendAdvcListVO = new ArrayList<>(); - Calendar calendar = setupBaseDate(kakaoVO, isNotified); + Calendar calendar = setupBaseDateFT(kakaoVO); + // 친구톡 내용 @@ -403,18 +394,18 @@ public class KakaoSendUtil { float shortPrice = getValidPrice(mberManageVO.getShortPrice(), sysJoinSetVO.getShortPrice()); float longPrice = getValidPrice(mberManageVO.getLongPrice(), sysJoinSetVO.getLongPrice()); float picturePrice = getValidPrice(mberManageVO.getPicturePrice(), sysJoinSetVO.getPicturePrice()); -// String shortPStr = Float.toString(shortPrice); -// String mmsPStr = Float.toString(longPrice); -// String imgPrice = Float.toString(picturePrice); + + boolean hasPerformedSpamCheck = false; // 치환 문자가 없는 경우, 스팸 체크가 한 번만 수행되도록 제어 + boolean hasPerformedSubSpamCheck = false; // 치환 문자가 없는 경우, 스팸 체크가 한 번만 수행되도록 제어 + boolean hasPerformedMsgType = false; // 치환 문자가 없는 경우, 메세지 타입 체크 한번 + boolean hasPerformedDelayYn = false; // 치환 문자가 없는 경우, + String imgFilePath = ""; if(StringUtils.isNotEmpty(kakaoVO.getAtchFileId()) && ("I".equals(imageType) || "W".equals(imageType))) { - - imgFilePath = mjonMsgDAO.selectPhotoImgFileRealPath(kakaoVO.getAtchFileId()); - } @@ -423,7 +414,20 @@ public class KakaoSendUtil { boolean hasButtons = CollectionUtils.isNotEmpty(kakaoVO.getButtonVOList()); String sharedJsonStr = null; - + + // 치환데이터가 없는 경우 한 번만 계산하기 위한 캐시 변수 추가 + Map sharedPricingResult = null; + // 치환데이터가 없는 경우 for문 전에 한 번만 계산 + if (!replaceSubYN && StringUtils.isNotEmpty(subMsgTxt)) { + sharedPricingResult = calculateSubMsgPricing(subMsgTxt, imgFilePath, shortPrice, longPrice, picturePrice, kakaoFtPrice); + + // 사전계산에서 INVALID인 경우 즉시 리턴 + String preSendType = (String) sharedPricingResult.get("sendType"); + if ("INVALID".equals(preSendType)) { + statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "전송 문자 길이를 초과하였습니다."); + return kakaoSendAdvcListVO; + } + } List mjonFTSendVOList = kakaoVO.getMjonFTSendVOList(); @@ -439,7 +443,9 @@ public class KakaoSendUtil { sendVO.setCallTo(mjonFTSendVO.getPhone()); sendVO.setMsgId(idList.get(i)); - String smsTxt = templateContent; + + // 친구톡 문자 + String templateContentTemp = templateContent; // 치환 문자면 if(replaceYN) { @@ -447,21 +453,19 @@ public class KakaoSendUtil { for (Map.Entry> entry : placeholders.entrySet()) { String placeholder = entry.getKey(); String value = entry.getValue().apply(mjonFTSendVO); - if (smsTxt.contains(placeholder)) { + if (templateContentTemp.contains(placeholder)) { if (StringUtils.isEmpty(value)) { statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "치환 문구중 " + placeholder + " 데이터가 없습니다."); return null; } - smsTxt = smsTxt.replace(placeholder, value); + templateContentTemp = templateContentTemp.replace(placeholder, value); } } } - sendVO.setTemplateContent(smsTxt); - - + sendVO.setTemplateContent(templateContentTemp); + // 실패 대체 문자 String subMsgTxtTemp = null; - if(StringUtils.isNotEmpty(subMsgTxt)) { subMsgTxtTemp = subMsgTxt; @@ -487,34 +491,28 @@ public class KakaoSendUtil { // Step 1-4: 실패 대체 문자 치환데이터 설정 if(StringUtils.isNotEmpty(subMsgTxtTemp)) { // 대체문자가 있나? - String sendType = "MMS"; - if(StringUtils.isEmpty(imgFilePath)) { - int smsTxtByte = mjonCommon.getSmsTxtBytes(subMsgTxtTemp); // 문자 byte 수 계산 - sendType = getMsgType(smsTxtByte); // 문자 타입(SHORT / MMS) 판별 - } - sendVO.setSubMsgType(sendType); // 실패 대체 문자 타입 설정 + // 최적화된 계산 로직 + Map pricingResult; + + if (replaceSubYN) { + // 치환데이터 있음 → 매번 새로 계산 + pricingResult = calculateSubMsgPricing(subMsgTxtTemp, imgFilePath, + shortPrice, longPrice, picturePrice, kakaoFtPrice); - if ("INVALID".equals(sendType)) { - // INVALID 타입이면 길이 초과 에러 응답 후 리턴 - statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "전송 문자 길이를 초과하였습니다."); - return kakaoSendAdvcListVO; - } - - float chosenPrice = 0f; - - if(StringUtils.isNotEmpty(imgFilePath)) { - chosenPrice = Math.max(picturePrice, kakaoFtPrice); - sendVO.setFilePath1(imgFilePath); - sendVO.setFileCnt("1"); - - }else if ("MMS".equals(sendType)) { - // MMS 타입일 경우: longPrice(장문 가격)와 카카오톡 단가 중 큰 값을 선택 - chosenPrice = Math.max(longPrice, kakaoFtPrice); + // INVALID 체크 + String resultSendType = (String) pricingResult.get("sendType"); + if ("INVALID".equals(resultSendType)) { + statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "전송 문자 길이를 초과하였습니다."); + return kakaoSendAdvcListVO; + } } else { - // SHORT 타입일 경우: shortPrice(단문 가격)와 카카오톡 단가 중 큰 값을 선택 - chosenPrice = Math.max(shortPrice, kakaoFtPrice); + // 치환데이터 없음 → 미리 계산된 결과 재사용 + pricingResult = sharedPricingResult; } - sendVO.setEachPrice(Float.toString(chosenPrice)); // 선택된 단가 설정 + + + // 결과 적용 + applyPricingResult(sendVO, pricingResult); }else { @@ -522,8 +520,68 @@ public class KakaoSendUtil { sendVO.setEachPrice( Float.toString(kakaoFtPrice) ); } + + // 스팸 단어 체크 + // exceptSpam는 사용자 스팸 단어 체크할건지에 대한 여부 N : 체크 + if("N".equals(exceptSpamYn)) { + // 친구톡 내용 + if(replaceYN) { + checkSpamAndSetStatus(kakaoVO + , templateContentTemp + , resultSpamTxt, isHolidayNotified); + }else if(!hasPerformedSpamCheck) { + checkSpamAndSetStatus(kakaoVO + , templateContentTemp + , resultSpamTxt, isHolidayNotified); + hasPerformedSpamCheck = true; + } + // 대체문자 내용 + if(StringUtils.isNotEmpty(subMsgTxtTemp)) { + if(replaceSubYN) { + checkSpamAndSetStatus(kakaoVO + , subMsgTxtTemp + , resultSpamTxt, isHolidayNotified); + }else if(!hasPerformedSubSpamCheck) { + checkSpamAndSetStatus(kakaoVO + , subMsgTxtTemp + , resultSpamTxt, isHolidayNotified); + hasPerformedSubSpamCheck = true; + } - // 타이틀과 버튼이 있고 + } + } + + log.info(" kakaoVO.toString() :: [{}]",kakaoVO.ftToString()); + + + /* @isHolidayNotified + * - 관리자 알림 설정으로 인해 + * - 해당 시간이면 지연 미처리 + * @smishingYn + * - 회원 별 '스미싱 온' 상태값 + * - Y면 알림, 지연 처리해야 함 + * */ + if("Y".equalsIgnoreCase(atSmishingYn) && isHolidayNotified) { + kakaoVO.setSpamStatus("Y"); + kakaoVO.setSmishingYn("Y"); + kakaoVO.setAtDelayYn("Y"); + } + + // 지연 여부 처리 + if (( "Y".equalsIgnoreCase(atSmishingYn) || "Y".equalsIgnoreCase(kakaoVO.getAtDelayYn())) + && !hasPerformedDelayYn && isHolidayNotified) { + calendar.add(Calendar.MINUTE, 30); // 모든 시간을 30분 뒤로 미룸 + // TEST +// calendar.add(Calendar.MINUTE, 5); // 모든 시간을 30분 뒤로 미룸 + hasPerformedDelayYn = true; + } + + sendVO.setReqDate(sdf.format(calendar.getTime())); // 분할된 시간 설정 또는 기본 예약 시간 사용 + + + + + // 타이틀이나 버튼이 있고 if(hasButtons || StringUtils.isNotEmpty(kakaoVO.getTemplateImageUrl())) { // if (StringUtils.isEmpty(sharedJsonStr)) { @@ -538,10 +596,114 @@ public class KakaoSendUtil { kakaoSendAdvcListVO.add(sendVO); log.info(" sendVO.toString() :: [{}]",sendVO.toString()); } - + return kakaoSendAdvcListVO; } + + private void checkSpamAndSetStatus(KakaoVO kakaoVO + , String chkText + , List resultSpamTxt, boolean isHolidayNotified) throws Exception { + // TODO Auto-generated method stub + + + kakaoVO.setSpamStatus("N"); + kakaoVO.setAtDelayYn("N"); + + if(StringUtils.isNotEmpty(chkText)) { + + String resultParser = ComGetSpamStringParser.getSpamTextParse(chkText).trim(); + int spmCnt = 0; + String spmFilterTxt = ""; + + for (String spmTxt : resultSpamTxt) { + String parserStr = ComGetSpamStringParser.getSpamTextParse(spmTxt).trim(); + if (resultParser.contains(parserStr) || chkText.contains(parserStr)) { + spmCnt++; + spmFilterTxt += spmTxt + ","; + } + } + + if (spmCnt > 0) { // 스팸 문자가 포함된 경우 + + if (StringUtil.getWordRight(spmFilterTxt.trim(), 1).equals(",")) { + // 처음부터 idx 만큼 잘라낸 나머지 글자 + spmFilterTxt = StringUtil.getWordLeft(spmFilterTxt.trim(), 1); + + } + + /* @isHolidayNotified + * - 관리자 알림 설정으로 인해 + * - 해당 시간이면 지연 미처리 + * */ + kakaoVO.setSpamStatus("Y"); + if(isHolidayNotified) { + kakaoVO.setAtDelayYn("Y"); + } + } + } + + + } + + // TODO(human): 아래에 새로운 메소드 구현 + /** + * 대체문자 가격 계산 최적화 메소드 + * @param subMsgTxt 대체문자 내용 + * @param imgFilePath 이미지 파일 경로 + * @param shortPrice 단문 가격 + * @param longPrice 장문 가격 + * @param picturePrice 사진 가격 + * @param kakaoFtPrice 카카오 친구톡 가격 + * @return 계산 결과 Map (sendType, chosenPrice, filePath 포함) + * @throws UnsupportedEncodingException + */ + private Map calculateSubMsgPricing(String subMsgTxt, String imgFilePath, + float shortPrice, float longPrice, + float picturePrice, float kakaoFtPrice) throws UnsupportedEncodingException { + Map result = new HashMap<>(); + + String sendType = "MMS"; + if(StringUtils.isEmpty(imgFilePath)) { + int smsTxtByte = mjonCommon.getSmsTxtBytes(subMsgTxt); + sendType = getMsgType(smsTxtByte); + } + + result.put("sendType", sendType); + + // INVALID인 경우 추가 처리 없이 반환 + if ("INVALID".equals(sendType)) { + return result; + } + + float chosenPrice = 0f; + if(StringUtils.isNotEmpty(imgFilePath)) { + chosenPrice = Math.max(picturePrice, kakaoFtPrice); + result.put("filePath", imgFilePath); + } else if ("MMS".equals(sendType)) { + chosenPrice = Math.max(longPrice, kakaoFtPrice); + } else { + chosenPrice = Math.max(shortPrice, kakaoFtPrice); + } + + result.put("sendType", sendType); + result.put("chosenPrice", Float.toString(chosenPrice)); + return result; + } + + /** + * 가격 계산 결과를 sendVO에 적용하는 헬퍼 메소드 + * @param sendVO 적용할 KakaoSendAdvcVO 객체 + * @param pricingResult 가격 계산 결과 Map + */ + private void applyPricingResult(KakaoSendAdvcVO sendVO, Map pricingResult) { + sendVO.setSubMsgType((String) pricingResult.get("sendType")); + sendVO.setEachPrice((String) pricingResult.get("chosenPrice")); + if (pricingResult.get("filePath") != null) { + sendVO.setFilePath1((String) pricingResult.get("filePath")); + sendVO.setFileCnt("1"); + } + } public static String getMsgTypeWithByteValidation(MjonFTSendVO sendVO, String p_smsTxt) throws UnsupportedEncodingException { @@ -571,9 +733,21 @@ public class KakaoSendUtil { } return msgType; } - - private Calendar setupBaseDate(KakaoVO kakaoVO, boolean isNotified) throws ParseException { + + private Calendar setupBaseDateFT(KakaoVO kakaoVO) throws ParseException { + + // baseDate 추출 + Date baseDate = resolveBaseDate(kakaoVO); + + // 시간 성정 + Calendar calendar = Calendar.getInstance(); + calendar.setTime(baseDate); // calendar에 baseDate 설정 + + return calendar; + } + + private Calendar setupBaseDate(KakaoVO kakaoVO, boolean isHolidayNotified) throws ParseException { // baseDate 추출 Date baseDate = resolveBaseDate(kakaoVO); @@ -585,7 +759,7 @@ public class KakaoSendUtil { // 지연 여부 처리 // 알림톡 스미싱의심 + 공휴일알림 조건이 맞으면 30분 delay if ( "Y".equalsIgnoreCase(kakaoVO.getAtSmishingYn()) - && isNotified) { + && isHolidayNotified) { calendar.add(Calendar.MINUTE, 30); // 모든 시간을 30분 뒤로 미룸 } return calendar; @@ -657,7 +831,7 @@ public class KakaoSendUtil { sendVO.setReqDate(DATE_FORMATTER.format(calendar.getTime())); sendVO.setSenderKey(kakaoVO.getSenderKey()); - sendVO.setTemplateCode(kakaoVO.getTemplateCode()); +// sendVO.setTemplateCode(kakaoVO.getTemplateCode()); sendVO.setUserId(kakaoVO.getUserId()); sendVO.setCallFrom(kakaoVO.getCallFrom()); sendVO.setSubMsgSendYn(kakaoVO.getSubMsgSendYn()); @@ -1711,12 +1885,14 @@ public class KakaoSendUtil { sendVO.setBefPoint(priceAndPoint.getBefPoint(sendVO.getUserId())); sendVO.setAdFlag(kakaoVO.getAdFlag()); + sendVO.setSendKind(kakaoVO.getSendKind()); + Float eachPrice = Float.parseFloat(sendVO.getEachPrice()); Float totPrice = eachPrice * instCnt; sendVO.setTotPrice(String.format("%.1f", totPrice)); - sendVO.setAtDelayYn(kakaoVO.getAtSmishingYn()); + sendVO.setAtDelayYn(kakaoVO.getAtDelayYn()); sendVO.setBizKakaoResendOrgnlTxt(kakaoVO.getSubMsgTxt()); sendVO.setBizKakaoResendType(sendVO.getSubMsgType()); sendVO.setBizKakaoImageType(kakaoVO.getImageType()); diff --git a/src/main/java/itn/let/kakao/kakaoComm/KakaoVO.java b/src/main/java/itn/let/kakao/kakaoComm/KakaoVO.java index f6802249..740ab4bd 100644 --- a/src/main/java/itn/let/kakao/kakaoComm/KakaoVO.java +++ b/src/main/java/itn/let/kakao/kakaoComm/KakaoVO.java @@ -336,28 +336,33 @@ public class KakaoVO extends MjonMsgVO{ public String ftToString() { StringBuilder sb = new StringBuilder("KakaoFTSendVO["); - sb.append("\n senderKey=[").append(senderKey).append("]"); + sb.append("\n sendKind=[").append(getSendKind()).append("]"); + sb.append("\n , senderKey=[").append(senderKey).append("]"); sb.append("\n , imageFileName=[").append(imageFileName).append("]"); sb.append("\n , imageType=[").append(imageType).append("]"); - sb.append("\n , imgTitle=[").append(imgTitle).append("]"); - sb.append("\n , imgLink=[").append(imgLink).append("]"); + sb.append("\n , atchFileId=[").append(atchFileId).append("]"); +// sb.append("\n , imgTitle=[").append(imgTitle).append("]"); +// sb.append("\n , imgLink=[").append(imgLink).append("]"); sb.append("\n , templateContent=[").append(templateContent).append("]"); sb.append("\n , templateImageUrl=[").append(templateImageUrl).append("]"); - sb.append("\n , smsTxtArea=[").append(getSubMsgTxt()).append("]"); - sb.append("\n , subMsgSendYn=[").append(subMsgSendYn).append("]"); - sb.append("\n , subMsgTxtReplYn=[").append(subMsgTxtReplYn).append("]"); - sb.append("\n , subMsgType=[").append(subMsgType).append("]"); +// sb.append("\n , imgLink=[").append(imgLink).append("]"); +// sb.append("\n , smsTxtArea=[").append(getSubMsgTxt()).append("]"); +// sb.append("\n , subMsgSendYn=[").append(subMsgSendYn).append("]"); +// sb.append("\n , subMsgTxtReplYn=[").append(subMsgTxtReplYn).append("]"); +// sb.append("\n , subMsgType=[").append(subMsgType).append("]"); sb.append("\n , subMsgTxt=[").append(subMsgTxt).append("]"); + sb.append("\n , subMsgSendYn=[").append(subMsgSendYn).append("]"); sb.append("\n , reserveYn=[").append(getReserveYn()).append("]"); - sb.append("\n , menuTopTab=[").append(menuTopTab).append("]"); - sb.append("\n , bizJsonYn=[").append(bizJsonYn).append("]"); - sb.append("\n , senderKey=[").append(senderKey).append("]"); +// sb.append("\n , menuTopTab=[").append(menuTopTab).append("]"); +// sb.append("\n , bizJsonYn=[").append(bizJsonYn).append("]"); sb.append("\n , callFrom=[").append(getCallFrom()).append("]"); - sb.append("\n , kakaoFtPrice=[").append(getEachPrice()).append("]"); +// sb.append("\n , kakaoFtPrice=[").append(getEachPrice()).append("]"); sb.append("\n , reqDate=[").append(getReqDate()).append("]"); - sb.append("\n , spamStatus=[").append(getSpamStatus()).append("]"); - sb.append("\n , txtReplYn=[").append(getTxtReplYn()).append("]"); - sb.append("\n , atSmishingYn=[").append(getAtSmishingYn()).append("]"); +// sb.append("\n , spamStatus=[").append(getSpamStatus()).append("]"); +// sb.append("\n , txtReplYn=[").append(getTxtReplYn()).append("]"); +// sb.append("\n , atSmishingYn=[").append(getAtSmishingYn()).append("]"); +// sb.append("\n , atDelayYn=[").append(getAtDelayYn()).append("]"); +// sb.append("\n , filePath1=[").append(getFilePath1()).append("]"); // sb.append("\n , tmpBtnSelect=[").append(getTmpBtnSelect()).append("]"); StringBuilder btnListSb = new StringBuilder("["); if (buttonVOList != null && !buttonVOList.isEmpty()) { @@ -387,4 +392,7 @@ public class KakaoVO extends MjonMsgVO{ return sb.toString(); } + + + } diff --git a/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiImageUpload.java b/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiImageUpload.java index 13394aeb..dbbe4a79 100644 --- a/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiImageUpload.java +++ b/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiImageUpload.java @@ -19,6 +19,7 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; @@ -395,6 +396,7 @@ public class KakaoApiImageUpload { .addTextBody("senderKey", kakaoVO.getSenderKey()) .addBinaryBody("image", new File(filePath), ContentType.MULTIPART_FORM_DATA, newName + "." + ext) .build(); +; httpPost.setEntity(httpEntity); @@ -407,7 +409,8 @@ public class KakaoApiImageUpload { String result = EntityUtils.toString(response.getEntity(), "UTF-8"); JSONParser parser = new JSONParser(); JSONObject object = (JSONObject) parser.parse(result); - + log.info("object + :: [{}]", object.toJSONString()); + String code = object.get("code").toString(); if ("200".equals(code)) { Map returnMap = new HashMap<>(); diff --git a/src/main/java/itn/let/kakao/user/kakaoAt/service/KakaoAlimTalkService.java b/src/main/java/itn/let/kakao/user/kakaoAt/service/KakaoAlimTalkService.java index 098f9768..469a774c 100644 --- a/src/main/java/itn/let/kakao/user/kakaoAt/service/KakaoAlimTalkService.java +++ b/src/main/java/itn/let/kakao/user/kakaoAt/service/KakaoAlimTalkService.java @@ -23,12 +23,10 @@ public interface KakaoAlimTalkService { //카카오 친구톡 발신 public MjonMsgReturnVO insertKakaoFtSendAjax(KakaoVO kakaoVO) throws Exception; - //카카오 알림톡 전송 실패 환불리스트 조회 - public void selectKakaoAtSentRefundList() throws Exception; - - //카카오 친구톡 전송 실패 환불리스트 조회 - public void selectKakaoFtSentRefundList() throws Exception; - StatusResponse insertKakaoAtSandAjax_advc(KakaoVO kakaoVO, HttpServletRequest request) throws Exception; + //카카오(알림톡, 친구톡 통합) 전송 실패 환불리스트 조회 + public List selectKakaoSentRefundListForSingle() throws Exception; + + public void kakaoSingleRefund(KakaoVO kakaoVO) throws Exception; } diff --git a/src/main/java/itn/let/kakao/user/kakaoAt/service/impl/KakaoAlimTalkDAO.java b/src/main/java/itn/let/kakao/user/kakaoAt/service/impl/KakaoAlimTalkDAO.java index 46520d26..d1a280b7 100644 --- a/src/main/java/itn/let/kakao/user/kakaoAt/service/impl/KakaoAlimTalkDAO.java +++ b/src/main/java/itn/let/kakao/user/kakaoAt/service/impl/KakaoAlimTalkDAO.java @@ -49,13 +49,8 @@ public class KakaoAlimTalkDAO extends EgovAbstractDAO { } @SuppressWarnings("unchecked") - public List selectKakaoAtSentRefundList() throws Exception{ - return (List) list("kakaoAlimTalkDAO.selectKakaoAtSentRefundList"); - } - - @SuppressWarnings("unchecked") - public List selectKakaoFtSentRefundList() throws Exception{ - return (List) list("kakaoAlimTalkDAO.selectKakaoFtSentRefundList"); + public List selectKakaoSentRefundList() throws Exception{ + return (List) list("kakaoAlimTalkDAO.selectKakaoSentRefundList"); } public KakaoVO selectKakaoAtUmid(KakaoVO kakaoVO) throws Exception{ diff --git a/src/main/java/itn/let/kakao/user/kakaoAt/service/impl/KakaoAlimTalkServiceImpl.java b/src/main/java/itn/let/kakao/user/kakaoAt/service/impl/KakaoAlimTalkServiceImpl.java index 700f3b09..2aa79e7f 100644 --- a/src/main/java/itn/let/kakao/user/kakaoAt/service/impl/KakaoAlimTalkServiceImpl.java +++ b/src/main/java/itn/let/kakao/user/kakaoAt/service/impl/KakaoAlimTalkServiceImpl.java @@ -11,8 +11,6 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Resource; @@ -22,12 +20,13 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl; import egovframework.rte.fdl.idgnr.EgovIdGnrService; import egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper; import itn.com.cmm.LoginVO; -import itn.com.cmm.MjonMsgSendVO; import itn.com.utl.fcc.service.EgovStringUtil; import itn.let.kakao.kakaoComm.BizKakaoPriceVO; import itn.let.kakao.kakaoComm.KakaoSendAdvcVO; @@ -51,7 +50,6 @@ import itn.let.module.base.PriceAndPoint; import itn.let.sym.site.service.JoinSettingVO; import itn.let.sym.site.service.impl.SiteManagerDAO; import itn.let.uss.umt.service.EgovUserManageService; -import itn.let.uss.umt.service.UserManageVO; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -105,6 +103,8 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements final String RESEND_YN_YES = "Y"; final String SMS_SUCCESS_CODE = "4100"; // SMS 성공 코드 final String MMS_SUCCESS_CODE = "6600"; // MMS 성공 코드 + final String AT_MSG_TYPE = "8"; // MSG 타입 알림톡 + final String FT_MSG_TYPE = "9"; // MSG 타입 친구톡 //발신프로필 상태값 변경(삭제/복구 기능) @Override @@ -793,144 +793,76 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements return returnVO; } - - /* - * 카카오 알림톡 발송 실패에 따른 금액 환불 처리 - * - * */ - @Override - public void selectKakaoAtSentRefundList() throws Exception { + private void processKakaoSendCharge(KakaoVO kakaoVO) throws Exception { - /** - * 1. 카카오 AT 전송성공 확인 - * 2. 카카오 AT 전송실패, 대채문자 전송확인 - * 3. 카카오 AT 전송 실패 확인 - */ - List kakaoAtSentRefundList = kakaoAlimTalkDAO.selectKakaoAtSentRefundList(); - - for(KakaoVO vo : kakaoAtSentRefundList) { - System.out.println(vo.getMsgGroupId() +"________결과 : " +vo.getRsltCode() +" 대체문자 전송 : "+vo.getSubMsgSendYn()); - if(vo.getRsltCode().equals("7000")) { - kakaoAlimTalkDAO.updateKakaoAtSend(vo); - }else if(vo.getSubMsgSendYn().equals("Y")) { - KakaoVO info = kakaoAlimTalkDAO.selectKakaoAtUmid(vo); - - System.out.println("대체문자 전송 : " + info.getBizUmid()); - if (info.getBizUmid() != null) { - kakaoAlimTalkDAO.updateKakaoAtSubMsgSend(vo); - }else { - kakaoAlimTalkDAO.updateKakaoAtNotSend(vo); - } - - }else { - kakaoAlimTalkDAO.updateKakaoAtNotSend(vo); - } - } - } - - - /** - * @ 카카오 친구톡 환불 - */ - @Override - public void selectKakaoFtSentRefundList() throws Exception { - - List kakaoFtSentRefundList = kakaoAlimTalkDAO.selectKakaoFtSentRefundList(); - - for(KakaoVO kakaoVO : kakaoFtSentRefundList) { - System.out.println(kakaoVO.getMsgGroupId() +"________결과 : " +kakaoVO.getRsltCode() +" 대체문자 전송 : "+kakaoVO.getSubMsgSendYn()); - - if(KAKAO_SUCCESS_CODE.equals(kakaoVO.getRsltCode())) {//친구톡 발송 성공시 - - processFtSendCharge(kakaoVO); - - }else if(RESEND_YN_YES.equals(kakaoVO.getSubMsgSendYn())) { - //친구톡 발송 실패 했고, 대체문자 발송 했을 경우 - handleAlternativeMessageScenario(kakaoVO); - - }else { - handleRefund(kakaoVO, "카카오 친구톡 전송 실패로 인한 결재 금액 환불"); - } - } - } - - - private void processFtSendCharge(KakaoVO kakaoVO) throws Exception { - - + //1-1.카카오톡 발송 성공 + 대체문자 신청 O : 대체문자 금액 환불 if(RESEND_YN_YES.equals(kakaoVO.getSubMsgSendYn())) { BizKakaoPriceVO bizKakaoPriceVO = mjonPayDAO.selectBizKakaoPrice(kakaoVO.getMsgGroupId()); BigDecimal sendPrice = null; - if(StringUtils.isEmpty(kakaoVO.getBizKakaoImageType())){ - sendPrice = new BigDecimal(bizKakaoPriceVO.getBizKakaoFtPrice()); - }else if("I".equals(kakaoVO.getBizKakaoImageType())){ - sendPrice = new BigDecimal(bizKakaoPriceVO.getBizKakaoFtImgPrice()); - }else if("W".equals(kakaoVO.getBizKakaoImageType())){ - sendPrice = new BigDecimal(bizKakaoPriceVO.getBizKakaoFtWideImgPrice()); + + if(AT_MSG_TYPE.equals(kakaoVO.getMsgType())){ + sendPrice = new BigDecimal(bizKakaoPriceVO.getBizKakaoAtPrice()); + }else { + if(StringUtils.isEmpty(kakaoVO.getBizKakaoImageType())){ + sendPrice = new BigDecimal(bizKakaoPriceVO.getBizKakaoFtPrice()); + }else if("I".equals(kakaoVO.getBizKakaoImageType())){ + sendPrice = new BigDecimal(bizKakaoPriceVO.getBizKakaoFtImgPrice()); + }else if("W".equals(kakaoVO.getBizKakaoImageType())){ + sendPrice = new BigDecimal(bizKakaoPriceVO.getBizKakaoFtWideImgPrice()); + } } - // 예시: 각 건당 가격이 이미 String 형태라면 변환 BigDecimal eachPrice = new BigDecimal(kakaoVO.getEachPrice()); // 차이 계산 BigDecimal diffPrice = eachPrice.subtract(sendPrice); - + //대체문자 비용(eachPrace - sendPrice) if (diffPrice.compareTo(BigDecimal.ZERO) > 0) { String result = diffPrice.toString(); kakaoVO.setEachPrice(result); - - handleRefund(kakaoVO, "카카오 친구톡 전송으로 인한 결재 차액 환불"); + handleRefund(kakaoVO, "카카오 " + kakaoVO.getMsgTypeTxt() + " 발송 성공 후 대체문자 금액 환불"); } - }else { - mjonMsgDAO.updateRefundY(kakaoVO); - } - // TODO Auto-generated method stub + //1-2.카카오톡 발송 성공 + 대체문자 신청 X : 금액 환불 X } private void handleAlternativeMessageScenario(KakaoVO kakaoVO) throws Exception { KakaoVO bizLogVO = kakaoAlimTalkDAO.selectBizLog(kakaoVO.getBizUmid()); log.info("대체문자 전송 UMID: {}", kakaoVO.getBizUmid()); - // 대체문자가 성공적으로 발송되었는지 확인 (SMS 또는 MMS 성공) + //2-1.카카오톡 발송 실패 + 대체문자 발송 성공 : 금액 환불 X boolean isAlternativeMessageSuccessful = false; if (bizLogVO != null && StringUtils.isNotEmpty(bizLogVO.getBizLogCallStatus())) { if (SMS_SUCCESS_CODE.equals(bizLogVO.getBizLogCallStatus()) || MMS_SUCCESS_CODE.equals(bizLogVO.getBizLogCallStatus())) { isAlternativeMessageSuccessful = true; } + log.info("bizLogVO.getBizLogCallStatus() :: [{}]", bizLogVO.getBizLogCallStatus()); + log.info("isAlternativeMessageSuccessful :: [{}]", isAlternativeMessageSuccessful); } - log.info("bizLogVO.getBizLogCallStatus() :: [{}]", bizLogVO.getBizLogCallStatus()); - log.info("isAlternativeMessageSuccessful :: [{}]", isAlternativeMessageSuccessful); - // 대체문자 성공이면 환불 완료처리면 한다. - if (isAlternativeMessageSuccessful) { - mjonMsgDAO.updateRefundY(kakaoVO); - } else { - // 대체문자 발송 실패 된 경우 (친구톡 비용 환불 필요) - handleRefund(kakaoVO, "카카오 친구톡 전송 실패로 인한 결재 금액 환불"); - } + //2-2.카카오톡 발송 실패 + 대체문자 발송 실패 : 전액 환불 + if (!isAlternativeMessageSuccessful) { + handleRefund(kakaoVO, "카카오 " + kakaoVO.getMsgTypeTxt() + " 전송 실패로 인한 결제 금액 환불"); + } } private void handleRefund(KakaoVO vo, String msg) throws Exception { // mj_cash 테이블에 환불 내역 추가 및 회원 금액 업데이트 // eachPrice는 환불될 금액이므로 양수여야 합니다. - priceAndPoint.insertCashAndPoint( + priceAndPoint.insertCashAndPointNoUpdate( vo.getUserId(), Float.parseFloat(vo.getEachPrice()), // 환불 금액은 양수 msg, vo.getMsgGroupId(), vo.getUserData() ); - - // 해당 row 환불 처리 (mj_msg_data.REFUND_YN = 'Y') - mjonMsgDAO.updateRefundY(vo); } @Override @@ -1033,6 +965,21 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements apiMsgType = StringUtils.isNotEmpty(apiMsgType) ? apiMsgType + "," + kakaoSendAdvcListVO.get(0).getMsgType() : kakaoSendAdvcListVO.get(0).getMsgType(); + + + + groupedMsgList.stream().forEach(t-> log.info("t.toString() [{}]", t.toString())); + +// +// if(1==1) { +// +// // 강제로 예외 발생 +// throw new RuntimeException("강제 예외 발생 테스트"); +// } +// +// + + // 발송 데이터 삽입 int instCnt = kakaoSendUtil.insertKakaoData_advc(groupedMsgList); // int instCnt = 6; @@ -1131,7 +1078,33 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements return statusResponse; } + @Override + public List selectKakaoSentRefundListForSingle() throws Exception{ + return kakaoAlimTalkDAO.selectKakaoSentRefundList(); + } + @Override + public void kakaoSingleRefund(KakaoVO kakaoVO) throws Exception { + + System.out.println(kakaoVO.getMsgGroupId() +"________결과 : " +kakaoVO.getRsltCode() +" 대체문자 전송 : "+kakaoVO.getSubMsgSendYn()); + kakaoVO.setMsgTypeTxt(AT_MSG_TYPE.equals(kakaoVO.getMsgType()) ? "알림톡" : "친구톡"); + + if(KAKAO_SUCCESS_CODE.equals(kakaoVO.getRsltCode())) { + //1.카카오톡 발송 성공 + processKakaoSendCharge(kakaoVO); + + }else if(RESEND_YN_YES.equals(kakaoVO.getSubMsgSendYn())) {//카카오톡 발송 실패, 대체문자 발송 신청 O + //2.카카오톡 발송 실패 + 대체문자 신청 O + handleAlternativeMessageScenario(kakaoVO); + + }else { + //3.카카오톡 발송 실패 + 대체문자 신청 X : 전액 환불 + handleRefund(kakaoVO, "카카오 " + kakaoVO.getMsgTypeTxt() + " 전송 실패로 인한 결제 금액 환불"); + } + + //모든 유형 환불 완료 처리 + mjonMsgDAO.updateRefundY(kakaoVO); + } private void insertKakaoAtDataJsonInfo_advc(List kakaoSendAdvcListVO) { // TODO Auto-generated method stub @@ -1279,5 +1252,4 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements - } diff --git a/src/main/java/itn/let/kakao/user/kakaoAt/web/KakaoAlimTalkSendController.java b/src/main/java/itn/let/kakao/user/kakaoAt/web/KakaoAlimTalkSendController.java index 2fbbee95..980c9823 100644 --- a/src/main/java/itn/let/kakao/user/kakaoAt/web/KakaoAlimTalkSendController.java +++ b/src/main/java/itn/let/kakao/user/kakaoAt/web/KakaoAlimTalkSendController.java @@ -9,9 +9,11 @@ import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Resource; @@ -61,7 +63,6 @@ import itn.com.cmm.util.MJUtil; import itn.com.cmm.util.StringUtil; import itn.com.utl.fcc.service.EgovStringUtil; import itn.let.kakao.kakaoComm.KakaoReturnVO; -import itn.let.kakao.kakaoComm.KakaoSendAdvcVO; import itn.let.kakao.kakaoComm.KakaoSendUtil; import itn.let.kakao.kakaoComm.KakaoVO; import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiJsonSave; @@ -79,6 +80,9 @@ import itn.let.mjo.msgdata.service.MjonMsgReturnVO; import itn.let.mjo.msgholiday.service.MsgAlarmSetVO; import itn.let.mjo.msgholiday.service.MsgHolidayService; import itn.let.mjo.msgholiday.service.MsgHolidayVO; +import itn.let.mjo.pay.service.MjonPayService; +import itn.let.mjo.pay.service.MjonPayVO; +import itn.let.org.web.OrgChartManageController; import itn.let.sym.site.service.EgovSiteManagerService; import itn.let.sym.site.service.JoinSettingVO; import itn.let.uss.umt.service.EgovUserManageService; @@ -102,6 +106,8 @@ import itn.let.uss.umt.service.UserManageVO; @Controller public class KakaoAlimTalkSendController { + private final OrgChartManageController orgChartManageController; + @Resource(name = "egovMjonMsgGroupIdGnrService") private EgovIdGnrService idgenMjonMsgGroupId; @@ -149,6 +155,13 @@ public class KakaoAlimTalkSendController { @Autowired private MjonCommon mjonCommon; + + @Resource(name = "mjonPayService") + private MjonPayService mjonPayService; + + KakaoAlimTalkSendController(OrgChartManageController orgChartManageController) { + this.orgChartManageController = orgChartManageController; + } @RequestMapping(value= {"/web/mjon/alimtalk/kakaoAlimtalkMsgDataView.do"}) public String KakaoAlimtalkMsgDataView(ModelMap model @@ -1540,4 +1553,55 @@ public class KakaoAlimTalkSendController { return "web/kakao/msgdata/at/KakaoAlimtalkMsgDataView_tmp"; } + + public void kakaoRefundSingleTransaction() throws Exception{ + System.out.println("=============카카오 환불 싱글 트랜잭션 수행 ============="); + + /* 회원 money 업데이트 처리 트랜잭션 분리를 위하여 impl이 아닌 현재 위치에서 반복문 실행 */ + System.out.println("=============SchedulerUtil=====runKakaoOneTime =============>"); + List kakaoRefundList = kakaoAlimTalkService.selectKakaoSentRefundListForSingle(); + Set targetIdSet = new HashSet<>(); + + for(KakaoVO kakaoVO : kakaoRefundList) { + try { + kakaoAlimTalkService.kakaoSingleRefund(kakaoVO); + targetIdSet.add(kakaoVO.getUserId()); + } catch (Exception e) { + String msg = "[문자온] 환불 실패 - " + kakaoVO.getMsgId() +"("+ kakaoVO.getUserId() + ")"; + mjonCommon.sendSimpleSlackMsg(msg);; + } + } + + MjonPayVO mjonPayVO = new MjonPayVO(); + for(String userId : targetIdSet) { + try { + mjonPayVO.setUserId(userId); + mjonPayService.updateMemberCash(mjonPayVO); //회원정보 업데이트 + } catch(Exception e) { + String msg = "[문자온] 환불 후 잔액 갱신 실패 - " + userId; + mjonCommon.sendSimpleSlackMsg(msg);; + } + } + + } + + /** + * @Method Name : kakaoMsgSendRefundTestAjax + * @작성일 : 2025. 8. 6. + * @작성자 : 이지우 + * @Method 설명 : 카카오 친구톡 전송 환불 스케줄러 서비스 테스트 + */ + @RequestMapping(value= {"/web/mjon/kakao/alimtalk/kakaoMsgSendRefundTestAjax.do"}) + public ModelAndView kakaoMsgSendRefundTestAjax(ModelMap model + , HttpServletRequest request + , @ModelAttribute("kakaoVO") KakaoVO kakaoVO) throws Exception { + + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("jsonView"); + + this.kakaoRefundSingleTransaction(); + + modelAndView.addObject("result", "success"); + return modelAndView; + } } diff --git a/src/main/java/itn/let/kakao/user/kakaoFt/service/impl/KakaoFriendsTalkServiceImpl.java b/src/main/java/itn/let/kakao/user/kakaoFt/service/impl/KakaoFriendsTalkServiceImpl.java index 77378891..31e184c4 100644 --- a/src/main/java/itn/let/kakao/user/kakaoFt/service/impl/KakaoFriendsTalkServiceImpl.java +++ b/src/main/java/itn/let/kakao/user/kakaoFt/service/impl/KakaoFriendsTalkServiceImpl.java @@ -11,6 +11,7 @@ import java.util.stream.Collectors; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; @@ -29,8 +30,10 @@ import itn.let.mail.service.StatusResponse; import itn.let.mjo.mjocommon.MjonCommon; import itn.let.mjo.msg.service.MjonMsgVO; import itn.let.mjo.msg.service.impl.MjonMsgDAO; +import itn.let.mjo.msgdata.service.MjonMsgDataService; import itn.let.module.base.PriceAndPoint; import itn.let.uss.umt.service.EgovUserManageService; +import itn.let.uss.umt.service.UserManageVO; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -56,6 +59,9 @@ public class KakaoFriendsTalkServiceImpl extends EgovAbstractServiceImpl implem @Resource(name="kakaoAlimTalkDAO") private KakaoAlimTalkDAO kakaoAlimTalkDAO; + + @Resource(name = "MjonMsgDataService") + private MjonMsgDataService mjonMsgDataService; @Autowired KakaoSendUtil kakaoSendUtil; @@ -75,20 +81,32 @@ public class KakaoFriendsTalkServiceImpl extends EgovAbstractServiceImpl implem log.info(" + kakaoVO.toString() :: [{}]", kakaoVO.ftToString()); +// if(1==1) { +// throw new RuntimeException("강제로 발생시킨 예외"); +// } // 측정할 메소드 호출 전 시간 기록 Instant start = Instant.now(); // KakaoSendAdvcVO - + Map returnMap = new HashMap<>(); + Map apiReturnMap = new HashMap<>(); + + String userId = ""; + if("A".equals(kakaoVO.getSendKind())) + { + userId = kakaoVO.getMberId(); + }else { + + LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated() + ? (LoginVO) EgovUserDetailsHelper.getAuthenticatedUser() + : null; + userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId()); + + if (userId.equals("")) { + return new StatusResponse(HttpStatus.BAD_REQUEST, "로그인 후 이용이 가능합니다."); + } - LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated() - ? (LoginVO) EgovUserDetailsHelper.getAuthenticatedUser() - : null; - String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId()); - - if (userId.equals("")) { - return new StatusResponse(HttpStatus.BAD_REQUEST, "로그인 후 이용이 가능합니다."); } kakaoVO.setUserId(userId); @@ -101,7 +119,7 @@ public class KakaoFriendsTalkServiceImpl extends EgovAbstractServiceImpl implem request.getSession().invalidate(); // UNAUTHORIZED : 인증되지 않은 사용자가 접근하려고 할 때 return new StatusResponse(HttpStatus.UNAUTHORIZED, - "현재 고객님께서는 문자온 서비스 이용이 정지된 상태로 친구톡을 발송하실 수 없습니다. 이용정지 해제를 원하시면 고객센터로 연락주시기 바랍니다."); + "현재 고객님께서는 문자온 서비스 이용이 정지된 상태로 친구톡을 발송하실 수 없습니다. 이용정지 해제를 원하시면 고객센터로 연락주시기 바랍니다.", "STAT_1070"); } @@ -111,30 +129,34 @@ public class KakaoFriendsTalkServiceImpl extends EgovAbstractServiceImpl implem if(kakaoSendUtil.isRestrictedFriendTalkTime(kakaoSendUtil.resolveBaseDate(kakaoVO))) { // UNAUTHORIZED : 인증되지 않은 사용자가 접근하려고 할 때 return new StatusResponse(HttpStatus.BAD_REQUEST, - "친구톡은 20시 50분부터 익일 08시까지 발송이 제한됩니다."); + "친구톡은 20시 50분부터 익일 08시까지 발송이 제한됩니다.","STAT_2080"); } /** @isHolidayNotified * @false : 알림 X * @true : 알림 O */ - boolean isNotified = mjonCommon.processUserAndCheckAT(kakaoVO); + boolean isHolidayNotified = mjonCommon.processUserAndCheckFT(kakaoVO); + + UserManageVO userManageVO = mjonCommon.getUserManageInfo(userId); + + // 스팸관련 키워드 select + List resultSpamTxt = mjonMsgDataService.selectSpamKeywordList(); /** @카카오톡 전송 list 셋팅 -------------------------------------------*/ - List kakaoSendAdvcListVO = kakaoSendUtil.populateSendListsFT(kakaoVO, isNotified, statusResponse); + List kakaoSendAdvcListVO = kakaoSendUtil.populateSendListsFT(kakaoVO, isHolidayNotified, statusResponse, userManageVO, resultSpamTxt); if (statusResponse.getStatus() != null && !statusResponse.getStatus().equals(HttpStatus.OK)) { log.error(" + populateSendLists 처리 중 오류 발생: {}", statusResponse.getMessage()); return statusResponse; } - - + /** @전송금액 확인 --------------------------------------------------*/ if (!kakaoSendUtil.isCashSufficient(userId, kakaoSendAdvcListVO)) { log.error("Insufficient balance for message sending."); - return new StatusResponse(HttpStatus.BAD_REQUEST, "문자 발송에 필요한 보유 잔액이 부족 합니다."); + return new StatusResponse(HttpStatus.BAD_REQUEST, "문자 발송에 필요한 보유 잔액이 부족 합니다.", "STAT_1060"); } @@ -152,6 +174,8 @@ public class KakaoFriendsTalkServiceImpl extends EgovAbstractServiceImpl implem // 임시 List nextMsgGroupIdA = new ArrayList<>(); // 대안: entrySet() 직접 사용 + String apiMsgGroupId = ""; + String apiMsgType = ""; for (Map.Entry> entry : priceGroupedMessages.entrySet()) { // entry 사용 @@ -159,7 +183,15 @@ public class KakaoFriendsTalkServiceImpl extends EgovAbstractServiceImpl implem String nextMsgGroupId = idgenMjonMsgGroupId.getNextStringId(); groupedMsgList.forEach(t -> t.setMsgGroupId(nextMsgGroupId)); + + // api 전달 값 + apiMsgGroupId = StringUtils.isNotEmpty(apiMsgGroupId) + ? apiMsgGroupId + "," + nextMsgGroupId + : nextMsgGroupId; + apiMsgType = StringUtils.isNotEmpty(apiMsgType) + ? apiMsgType + "," + kakaoSendAdvcListVO.get(0).getMsgType() + : kakaoSendAdvcListVO.get(0).getMsgType(); // 발송 데이터 삽입 int instCnt = kakaoSendUtil.insertKakaoData_advc(groupedMsgList); @@ -189,7 +221,9 @@ public class KakaoFriendsTalkServiceImpl extends EgovAbstractServiceImpl implem /** @SLACK발송 */ /** @발송조건이되면 발송 */ - if(isNotified) { + if(isHolidayNotified + && ("Y".equals(userManageVO.getAtSmishingYn()) || "Y".equals(kakaoVO.getAtDelayYn())) + ) { mjonCommon.getAdminKakaoAtSendSlack(sendVO); }else if("Y".equals(kakaoVO.getAtSmishingYn())){ /** @발송조건이 안되면 DB INSERT */ @@ -212,6 +246,12 @@ public class KakaoFriendsTalkServiceImpl extends EgovAbstractServiceImpl implem } + apiReturnMap.put("resultSts", instTotalCnt); + // 그룹 ID + apiReturnMap.put("msgGroupId", apiMsgGroupId); + // 메세지 타입 + apiReturnMap.put("msgType", apiMsgType); + returnMap.put("resultSts", instTotalCnt); returnMap.put("reserYn", kakaoVO.getReserveYn()); returnMap.put("groupIds", nextMsgGroupIdA); @@ -242,6 +282,9 @@ public class KakaoFriendsTalkServiceImpl extends EgovAbstractServiceImpl implem statusResponse.setStatus(HttpStatus.OK); statusResponse.setObject(returnMap); + apiReturnMap.put("result", HttpStatus.OK); + apiReturnMap.put("message", "전송이 완료되었습니다."); + statusResponse.setApiReturn(apiReturnMap); return statusResponse; } diff --git a/src/main/java/itn/let/kakao/user/kakaoFt/web/KakaoFriendsTalkSendController.java b/src/main/java/itn/let/kakao/user/kakaoFt/web/KakaoFriendsTalkSendController.java index 2edcb887..97279609 100644 --- a/src/main/java/itn/let/kakao/user/kakaoFt/web/KakaoFriendsTalkSendController.java +++ b/src/main/java/itn/let/kakao/user/kakaoFt/web/KakaoFriendsTalkSendController.java @@ -711,27 +711,6 @@ public class KakaoFriendsTalkSendController { return modelAndView; } - - /** - * @Method Name : kakaoFriendsTalkMsgSendRefundTestAjax - * @작성일 : 2024. 1. 18. - * @작성자 : 우영두 - * @Method 설명 : 카카오 친구톡 전송 환불 스케줄러 서비스 테스트 - */ - @RequestMapping(value= {"/web/mjon/kakao/friendstalk/kakaoFriendsTalkMsgSendRefundTestAjax.do"}) - public ModelAndView kakaoFriendsTalkMsgSendRefundTestAjax(ModelMap model - , HttpServletRequest request - , @ModelAttribute("kakaoVO") KakaoVO kakaoVO) throws Exception { - - ModelAndView modelAndView = new ModelAndView(); - modelAndView.setViewName("jsonView"); - - kakaoAlimTalkService.selectKakaoFtSentRefundList(); - - modelAndView.addObject("result", "success"); - return modelAndView; - } - /** * @Method Name : kakaoFriendsTalkMsgSendRefundTestAjax * @작성일 : 2024. 1. 18. diff --git a/src/main/java/itn/let/kakao/user/kakaoFt/web/KakaoFriendsTalkTemplateController.java b/src/main/java/itn/let/kakao/user/kakaoFt/web/KakaoFriendsTalkTemplateController.java index 8bf45081..fc002a03 100644 --- a/src/main/java/itn/let/kakao/user/kakaoFt/web/KakaoFriendsTalkTemplateController.java +++ b/src/main/java/itn/let/kakao/user/kakaoFt/web/KakaoFriendsTalkTemplateController.java @@ -199,19 +199,23 @@ public class KakaoFriendsTalkTemplateController { modelAndView.setViewName("jsonView"); try { - LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null; - String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId()); - if(StringUtils.isEmpty(userId)) { //KISA 보안취약점 조치 (2018-12-10, 이정은) - return ResponseEntity.ok( - new StatusResponse(HttpStatus.UNAUTHORIZED - , "로그인을 하셔야 이용 가능합니다." - , LocalDateTime.now() - ) - ); + if(!"A".equals(kakaoVO.getSendKind())) { + + LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null; + String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId()); + + if(StringUtils.isEmpty(userId)) { + return ResponseEntity.ok( + new StatusResponse(HttpStatus.UNAUTHORIZED + , "로그인을 하셔야 이용 가능합니다." + , LocalDateTime.now() + ) + ); + } + } - final Map files = multiRequest.getFileMap(); /* if (!files.isEmpty()){ diff --git a/src/main/java/itn/let/kakao/user/sent/web/KakaoSentController.java b/src/main/java/itn/let/kakao/user/sent/web/KakaoSentController.java index f797391b..8d60a7c9 100644 --- a/src/main/java/itn/let/kakao/user/sent/web/KakaoSentController.java +++ b/src/main/java/itn/let/kakao/user/sent/web/KakaoSentController.java @@ -272,6 +272,25 @@ public class KakaoSentController { model.addAttribute("kakaoTemplateInfo", kakaoTemplateInfo); + if(StringUtils.isNotEmpty( mjonKakaoATResultVO.getFilePath1() )) { + List fileInfos = new ArrayList<>(); + + + // 확장자 제외한 파일명 + String fileId = FilenameUtils.getBaseName(mjonKakaoATResultVO.getFilePath1()); + + // 파일 정보 조회 + MjonMsgSentVO info = mjonMsgSentDAO.selectFileInfo(fileId); + + // FileInfo 객체 생성 및 추가 + FileInfoVO fileInfo = new FileInfoVO(); + fileInfo.setAtchFileId(info.getAtchFileId()); + fileInfo.setFileSn(info.getFileSn()); + + fileInfos.add(fileInfo); + model.addAttribute("fileInfos", fileInfos); + } + }else { model.addAttribute("kakaoTemplateInfo", ""); @@ -1109,6 +1128,6 @@ public class KakaoSentController { e.printStackTrace(); // TODO: handle exception } - return "web/kakao/sent/KakaoSentDetailPopAjax"; + return "web/kakao/sent/KakaoSentDetailPhoneAjax"; } } diff --git a/src/main/java/itn/let/kakao/user/stepInfo/web/KakaoStepInfoController.java b/src/main/java/itn/let/kakao/user/stepInfo/web/KakaoStepInfoController.java index 50d04c07..0aebc4a1 100644 --- a/src/main/java/itn/let/kakao/user/stepInfo/web/KakaoStepInfoController.java +++ b/src/main/java/itn/let/kakao/user/stepInfo/web/KakaoStepInfoController.java @@ -188,6 +188,29 @@ public class KakaoStepInfoController { return "/web/kakao/intrd/KakaoAllimtalkIntro"; } + /** + * @Method Name : kakaotalkIntrdView + * @Project : mjon + * @Date : 2025. 8. 21 + * @작성자 : 원영현 + + * @프로그램 설명 :카카오 알림톡, 친구토 통합 소개페이지 + */ + @RequestMapping(value= {"/web/mjon/kakao/alimtalk/kakaotalkIntrdView.do"}) + public String kakaotalkIntrdView(HttpServletRequest request, + @ModelAttribute("searchVO") BoardMasterVO boardMasterVO, ModelMap model , BoardVO boardVO , + RedirectAttributes redirectAttributes) throws Exception { + + LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null; + String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId()); + if(userId == "") { + return "redirect:/web/user/login/login.do"; + } + model.addAttribute("loginVO", loginVO); + + return "/web/kakao/intrd/KakaotalkIntro"; + } + /** * XSS 방지 처리. diff --git a/src/main/java/itn/let/mjo/mjocommon/MjonCommon.java b/src/main/java/itn/let/mjo/mjocommon/MjonCommon.java index d1217838..e6792d0c 100644 --- a/src/main/java/itn/let/mjo/mjocommon/MjonCommon.java +++ b/src/main/java/itn/let/mjo/mjocommon/MjonCommon.java @@ -533,12 +533,12 @@ private int parseIntOrDefault(String value, int defaultValue) { UserManageVO userManageVO = getUserManageInfo(kakaoVO.getUserId()); // 기본값 처리된 사용자 정보와 문자 상태 - String adminSmsNoticeYn = userManageVO.getAdminSmsNoticeYn(); - String atSmishingYn = userManageVO.getAtSmishingYn(); + String adminSmsNoticeYn = userManageVO.getAdminSmsNoticeYn(); // 법인폰 알람 여부 - Y : ON + String atSmishingYn = userManageVO.getAtSmishingYn(); // 스미싱 의심 - Y : ON // 조건 체크 if ("Y".equals(adminSmsNoticeYn) || "Y".equals(atSmishingYn)) { - kakaoVO.setAtSmishingYn("Y"); // MjonMsgVO에 스미싱 정보 설정 + kakaoVO.setAtSmishingYn("Y"); // MjonMsgVO에 스미싱 정보 설정 - Y면 디 // 스미싱 알림 처리 return handleSmishingAlert(); // 알림 처리 결과 반환 @@ -546,6 +546,46 @@ private int parseIntOrDefault(String value, int defaultValue) { return false; // 알림 처리되지 않음 } + + + /** + * @methodName : processUserAndCheckFT + * @author : 이호영 + * @date : 2025. 8. 21. + * @description : + * @return : boolean + * @param kakaoVO + * @return + * @throws Exception + * + * @isHolidayNotified + * @false : 알림 X + * @true : 알림 O + * + */ + public boolean processUserAndCheckFT(KakaoVO kakaoVO) throws Exception { +// UserManageVO userManageVO = getUserManageInfo(kakaoVO.getUserId()); +// kakaoVO.setAtSmishingYn("N"); // MjonMsgVO에 스미싱 정보 설정 - Y면 딜레이 처리 됨 + + + // 기본값 처리된 사용자 정보와 문자 상태 +// String adminSmsNoticeYn = userManageVO.getAdminSmsNoticeYn(); // 법인폰 알람 여부 - Y : ON +// String atSmishingYn = userManageVO.getAtSmishingYn(); // 스미싱 의심 - Y : ON !== mj_msg_group_data와 다른거임 + + // 조건 체크 +// if ("Y".equals(adminSmsNoticeYn) || "Y".equals(atSmishingYn)) { +// if ("Y".equals(atSmishingYn)) { +// Boolean B_return = handleSmishingAlert(); +// if(B_return) { // true면 알림ON이라서 스미싱Yn을 Y로 설정 아니면 N / 나머지는 로직에서 처리 +// kakaoVO.setAtSmishingYn(atSmishingYn); // MjonMsgVO에 스미싱 정보 설정 - Y면 딜레이 처리 됨 +// } + // 스미싱 알림 처리 +// return B_return; // 알림 처리 결과 반환 +// } + + return handleSmishingAlert(); // 알림 처리되지 않음 + } + // 사용자 정보 조회 및 기본값 처리 public UserManageVO getUserManageInfo(String userId) throws Exception { diff --git a/src/main/java/itn/let/mjo/msg/service/MjonMsgVO.java b/src/main/java/itn/let/mjo/msg/service/MjonMsgVO.java index 92f2e106..d07fdb28 100644 --- a/src/main/java/itn/let/mjo/msg/service/MjonMsgVO.java +++ b/src/main/java/itn/let/mjo/msg/service/MjonMsgVO.java @@ -95,6 +95,7 @@ public class MjonMsgVO extends ComDefaultVO{ private String reserveYn ; //예약문자 여부 private String reserveCYn ; //예약문자 취소 여부 private String cancelDate; //예약 취소 일자 + private String msgResult; //문자 발송결과 10:성공 20:실패 30:대체문자 대기 40:대체문자 성공 50:대체문자 실패 private String sendRate; // 전송 배분률 @@ -318,5 +319,8 @@ public class MjonMsgVO extends ComDefaultVO{ private String detailType; private List mjonMsgSendVOList = new ArrayList<>(); + + private String cmId; //다우기술 cmId + } diff --git a/src/main/java/itn/let/mjo/msgdata/service/impl/MjonMsgDataDAO.java b/src/main/java/itn/let/mjo/msgdata/service/impl/MjonMsgDataDAO.java index 9f59ab1a..b28a2b52 100644 --- a/src/main/java/itn/let/mjo/msgdata/service/impl/MjonMsgDataDAO.java +++ b/src/main/java/itn/let/mjo/msgdata/service/impl/MjonMsgDataDAO.java @@ -463,6 +463,23 @@ public class MjonMsgDataDAO extends EgovAbstractDAO { } + //대체문자 대기 목록 조회 + @SuppressWarnings("unchecked") + public List selectBizResendLogList()throws Exception{ + + return (List) list("mjonMsgDataDAO.selectBizResendLogList"); + } + //대체문자 결과 반영 + public int updateResendResult(MjonMsgVO mjonMsgVO)throws Exception{ + + return update("mjonMsgDataDAO.updateResendResult", mjonMsgVO); + } + //대체문자 로그 삭제 + public int deleteBizResendLog(MjonMsgVO mjonMsgVO)throws Exception{ + + return delete("mjonMsgDataDAO.deleteBizResendLog", mjonMsgVO); + } + public Timestamp convertToTimestamp(String reqDate) { try { diff --git a/src/main/java/itn/let/mjo/msgdata/web/MjonMsgDataController.java b/src/main/java/itn/let/mjo/msgdata/web/MjonMsgDataController.java index de13ab68..76a9d0ea 100644 --- a/src/main/java/itn/let/mjo/msgdata/web/MjonMsgDataController.java +++ b/src/main/java/itn/let/mjo/msgdata/web/MjonMsgDataController.java @@ -6543,5 +6543,4 @@ public class MjonMsgDataController { return "web/msgdata/MsgSentListAjax"; } - } diff --git a/src/main/java/itn/let/mjo/pay/web/MjonPayController.java b/src/main/java/itn/let/mjo/pay/web/MjonPayController.java index e4a4e305..6f139c7c 100644 --- a/src/main/java/itn/let/mjo/pay/web/MjonPayController.java +++ b/src/main/java/itn/let/mjo/pay/web/MjonPayController.java @@ -4901,10 +4901,11 @@ public class MjonPayController { model.addAttribute("endDate", endDate); DecimalFormat decFormat = new DecimalFormat("###,###"); + DecimalFormat decFormatFloat = new DecimalFormat("###,###.#"); model.addAttribute("sendSumCount", decFormat.format(sendSumCount)); model.addAttribute("supplySumPrice", decFormat.format(supplySumPrice)); model.addAttribute("vatSumPrice", decFormat.format(vatSumPrice)); - model.addAttribute("totalSumPrice", decFormat.format(totalSumPrice)); + model.addAttribute("totalSumPrice", decFormatFloat.format(totalSumPrice)); model.addAttribute("resultList", payUserSumList); // 수신자 정보 diff --git a/src/main/java/itn/let/module/base/PriceAndPoint.java b/src/main/java/itn/let/module/base/PriceAndPoint.java index f640732f..4d9f0943 100644 --- a/src/main/java/itn/let/module/base/PriceAndPoint.java +++ b/src/main/java/itn/let/module/base/PriceAndPoint.java @@ -213,6 +213,36 @@ public class PriceAndPoint { kakaoAlimTalkDAO.insertKakaoSendPrice(kakaoVO); } - + + /** + * @methodName : insertCashAndPoint + * @author : 이지우 + * @date : 2025. 8. 14. + * @description : insertCashAndPoint 에서 updateMemberCash 제외 + * @return : void + * @param userId + * @param totPrice + * @param memo + * @param msgGroupId + * @param userData + * @throws Exception + * + */ + public void insertCashAndPointNoUpdate( + String userId + , float totPrice + , String memo + , String msgGroupId + , String userData + ) throws Exception { + + MjonPayVO mjonPayVO = buildPayVO(userId, totPrice, memo, msgGroupId); + +// 환불로 인해 userData가 추후 사용될 경우 여기에 처리 + if (StringUtils.isNotEmpty(userData)) { mjonPayVO.setOrderId(userData); } + + mjonPayDAO.insertCash(mjonPayVO); //캐시 + + } } \ No newline at end of file diff --git a/src/main/java/itn/let/schdlr/service/SchdlrManageService.java b/src/main/java/itn/let/schdlr/service/SchdlrManageService.java index 3717a18b..ab331442 100644 --- a/src/main/java/itn/let/schdlr/service/SchdlrManageService.java +++ b/src/main/java/itn/let/schdlr/service/SchdlrManageService.java @@ -47,11 +47,11 @@ public interface SchdlrManageService { //전용계좌 자동 충전 배치 public void vacsAutoCharge() throws Exception; - //문자온 카카오톡 실패 건수 환불 배치 - public void kakaoFailPayBack() throws Exception; - //문자온 문자전송 실패 건수 환불 배치 public void payBack(String type, int limitCout) throws Exception; public void payBack_advc(String p_type) throws Exception; + + //대체문자 결과 반영 배치 + public void updateKakaoResendResult() throws Exception; } diff --git a/src/main/java/itn/let/schdlr/service/SchedulerUtil.java b/src/main/java/itn/let/schdlr/service/SchedulerUtil.java index a5bda660..ae30e4bd 100644 --- a/src/main/java/itn/let/schdlr/service/SchedulerUtil.java +++ b/src/main/java/itn/let/schdlr/service/SchedulerUtil.java @@ -2,7 +2,9 @@ package itn.let.schdlr.service; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; import javax.annotation.Resource; import javax.sql.DataSource; @@ -24,12 +26,16 @@ import itn.let.fax.admin.service.FaxAdmService; import itn.let.fax.admin.service.FaxStatVO; import itn.let.kakao.admin.kakaoAt.service.MjonKakaoAtStatVO; import itn.let.kakao.admin.statistics.service.KakaoStatisticsService; +import itn.let.kakao.kakaoComm.KakaoVO; +import itn.let.kakao.user.kakaoAt.service.KakaoAlimTalkService; import itn.let.lett.service.LetterService; import itn.let.mail.service.MailTemplateService; +import itn.let.mjo.mjocommon.MjonCommon; import itn.let.mjo.msg.service.MjonMsgService; import itn.let.mjo.msg.service.MjonMsgStatVO; -import itn.let.mjo.msg.service.MjonMsgVO; import itn.let.mjo.msgdata.service.impl.MjonMsgDataDAO; +import itn.let.mjo.pay.service.MjonPayService; +import itn.let.mjo.pay.service.MjonPayVO; import itn.let.sts.com.StatsVO; import itn.let.sts.cst.service.EgovConectStatsService; import itn.let.uss.umt.service.EgovUserManageService; @@ -82,6 +88,15 @@ public class SchedulerUtil { @Resource(name="MjonMsgDataDAO") private MjonMsgDataDAO mjonMsgDataDAO; + @Resource(name="kakaoAlimTalkService") + private KakaoAlimTalkService kakaoAlimTalkService; + + @Resource(name="MjonCommon") + private MjonCommon mjonCommon; + + @Resource(name = "mjonPayService") + private MjonPayService mjonPayService; + /** 설정값 가져오기 */ @Value("#{globalSettings['Globals.Env']}") private String GlobalsEnv; @@ -470,13 +485,46 @@ public class SchedulerUtil { @SchedulerLock(name = "runKakaoOneTime", lockAtMostForString = ONE_MIN, lockAtLeastForString = ONE_MIN) public void runKakaoOneTime() throws Exception { - // do something... - try { + /* 회원 money 업데이트 처리 트랜잭션 분리를 위하여 impl이 아닌 현재 위치에서 반복문 실행 */ System.out.println("=============SchedulerUtil=====runKakaoOneTime =============>"); - schdlrManageService.kakaoFailPayBack(); + List kakaoRefundList = kakaoAlimTalkService.selectKakaoSentRefundListForSingle(); + Set targetIdSet = new HashSet<>(); + + for(KakaoVO kakaoVO : kakaoRefundList) { + try { + kakaoAlimTalkService.kakaoSingleRefund(kakaoVO); + targetIdSet.add(kakaoVO.getUserId()); + } catch (Exception e) { + String msg = "[문자온] 환불 실패 - " + kakaoVO.getMsgId() +"("+ kakaoVO.getUserId() + ")"; + mjonCommon.sendSimpleSlackMsg(msg);; + } + } + + MjonPayVO mjonPayVO = new MjonPayVO(); + for(String userId : targetIdSet) { + try { + mjonPayVO.setUserId(userId); + mjonPayService.updateMemberCash(mjonPayVO); //회원정보 업데이트 + } catch(Exception e) { + String msg = "[문자온] 환불 후 잔액 갱신 실패 - " + userId; + mjonCommon.sendSimpleSlackMsg(msg);; + } + } + + } + + //대체문자 결과 반영 + @Scheduled(cron = "0 0/2 * * * ?") // 2분마다 실행 + @SchedulerLock(name = "updateKakaoResendResult", lockAtMostForString = ONE_MIN, lockAtLeastForString = ONE_MIN) + public void runUpdateKakaoResendResult() throws Exception { + + try { + System.out.println("=============SchedulerUtil=====runUpdateKakaoResendResult =============>"); + schdlrManageService.updateKakaoResendResult(); }catch(Exception ex) { ex.printStackTrace(); } + } //환불 실행 diff --git a/src/main/java/itn/let/schdlr/service/impl/SchdlrManageServiceImpl.java b/src/main/java/itn/let/schdlr/service/impl/SchdlrManageServiceImpl.java index aa1757ad..071c1d4d 100644 --- a/src/main/java/itn/let/schdlr/service/impl/SchdlrManageServiceImpl.java +++ b/src/main/java/itn/let/schdlr/service/impl/SchdlrManageServiceImpl.java @@ -393,12 +393,12 @@ public class SchdlrManageServiceImpl extends EgovAbstractServiceImpl implements // 대상 : 휴대폰결제, 즉시이체, 전용계좌 // Step 1. 스미싱의심 지정 여부 - JoinSettingVO joinSettingVO = new JoinSettingVO(); - joinSettingVO = egovSiteManagerService.selectAdminNotiDetail(); +// JoinSettingVO joinSettingVO = new JoinSettingVO(); + JoinSettingVO joinSettingVO = egovSiteManagerService.selectAdminNotiDetail(); if (joinSettingVO != null && joinSettingVO.getSmishingNoti().equals("Y")) { // Step 1. 개인회원 여부 체크 - int isPersnalMemberCnt = egovSiteManagerService.selectPersnalMemberCnt(Userid); - if (isPersnalMemberCnt == 1) { +// int isPersnalMemberCnt = egovSiteManagerService.selectPersnalMemberCnt(Userid); +// if (isPersnalMemberCnt == 1) { // Step 2. 첫결제 여부 체크 int isFirstPayCnt = egovSiteManagerService.selectFirstPayCnt(Userid); if (isFirstPayCnt == 1) { @@ -418,10 +418,11 @@ public class SchdlrManageServiceImpl extends EgovAbstractServiceImpl implements // 스미싱 의심회원으로 변경 UserManageVO userManageVO = new UserManageVO(); userManageVO.setSmishingYn("Y"); + userManageVO.setAtSmishingYn("Y"); userManageVO.setMberId(Userid); userManageService.updateOneUserSmishingYnNotAlert(userManageVO); } - } +// } } } catch (Exception e) { @@ -437,17 +438,6 @@ public class SchdlrManageServiceImpl extends EgovAbstractServiceImpl implements } - // 카카오 환불 처리 리스트 - public void kakaoFailPayBack() throws Exception { - - // 카카오 알림톡 환불 처리 - kakaoAlimTalkService.selectKakaoAtSentRefundList(); - - // 카카오 친구톡 환불 처리 - kakaoAlimTalkService.selectKakaoFtSentRefundList(); - - } - @Override public void payBack(String type, int limitCout) throws Exception { // 문자 환불 @@ -566,4 +556,37 @@ public class SchdlrManageServiceImpl extends EgovAbstractServiceImpl implements return msgFailList; } + + + /** + * @methodName : updateKakaoResendResult + * @author : 이지우 + * @date : 2025.07.15 + * @description : 대체문자 결과 반영 + * @param p_type + * @param request + * @param model + * @return + * @throws Exception + */ + @Override + public void updateKakaoResendResult() throws Exception { + long startTime = System.currentTimeMillis(); + // 대체문자 대상 조회 + List resendLogList = mjonMsgDataDAO.selectBizResendLogList(); + for(MjonMsgVO vo : resendLogList) { + if("4100".equals(vo.getResultCode()) + || "6600".equals(vo.getResultCode()) + || "7000".equals(vo.getResultCode())) { + vo.setMsgResult("40"); + }else { + vo.setMsgResult("50"); + } + mjonMsgDataDAO.updateResendResult(vo); + mjonMsgDataDAO.deleteBizResendLog(vo); + } + long endTime = System.currentTimeMillis(); + long elapsedTime = (endTime - startTime) / 1000; // 초 단위 변환 + System.out.println("updateKakaoResendResult 실행 시간: " + elapsedTime + "초 (" + resendLogList.size() + "건 처리)"); + } } diff --git a/src/main/resources/egovframework/egovProps/globals_dev.properties b/src/main/resources/egovframework/egovProps/globals_dev.properties index be1d7088..344ef3a8 100644 --- a/src/main/resources/egovframework/egovProps/globals_dev.properties +++ b/src/main/resources/egovframework/egovProps/globals_dev.properties @@ -28,7 +28,7 @@ Globals.Env = dev # mysql Globals.DriverClassName=com.mysql.jdbc.Driver -Globals.Url=jdbc:mysql://192.168.0.125:3306/mjon_advc +Globals.Url=jdbc:mysql://192.168.0.60:3308/mjon_advc #Globals.Url=jdbc:mysql://139.150.73.12:3306/mjon Globals.UserName= mjonUr Globals.Password= mjon!@#$ diff --git a/src/main/resources/egovframework/egovProps/globals_local.properties b/src/main/resources/egovframework/egovProps/globals_local.properties index 1e164a84..338e88a2 100644 --- a/src/main/resources/egovframework/egovProps/globals_local.properties +++ b/src/main/resources/egovframework/egovProps/globals_local.properties @@ -28,7 +28,7 @@ Globals.Env = local # mysql Globals.DriverClassName=com.mysql.jdbc.Driver -Globals.Url=jdbc:mysql://192.168.0.125:3306/mjon_advc +Globals.Url=jdbc:mysql://192.168.0.60:3308/mjon_advc #Globals.Url=jdbc:mysql://192.168.0.60:3308/mjon Globals.UserName= mjonUr Globals.Password= mjon!@#$ diff --git a/src/main/resources/egovframework/sqlmap/let/mjo/kakao/Kakao_AT_SQL_Mysql.xml b/src/main/resources/egovframework/sqlmap/let/mjo/kakao/Kakao_AT_SQL_Mysql.xml index 60483daf..8aa1e89a 100644 --- a/src/main/resources/egovframework/sqlmap/let/mjo/kakao/Kakao_AT_SQL_Mysql.xml +++ b/src/main/resources/egovframework/sqlmap/let/mjo/kakao/Kakao_AT_SQL_Mysql.xml @@ -207,36 +207,11 @@ ) - - - SELECT MMD.USER_ID AS userId , MMD.MSG_GROUP_ID AS msgGroupId + , MMD.MSG_ID AS msgId , MMD.MSG_SEQ AS msgSeq , MMGD.BIZ_KAKAO_IMAGE_TYPE AS bizKakaoImageType , MMGD.EACH_PRICE AS eachPrice @@ -251,6 +226,7 @@ , MMD.BIZ_KAKAO_RESEND_TYPE AS subMsgType , MMD.FILE_CNT AS fileCnt , MMD.BIZ_UMID AS bizUmid + , MMD.MSG_TYPE AS msgType FROM MJ_MSG_DATA MMD INNER JOIN LETTNGNRLMBER MB @@ -261,7 +237,8 @@ AND MMD.CUR_STATE = '3' AND MMD.REFUND_YN = 'N' AND MMD.RESERVE_C_YN = 'N' - AND MMD.MSG_TYPE = 9 + AND MMD.MSG_TYPE IN(8, 9) + ORDER BY MMD.USER_ID ASC + + SELECT + BRLA.CMID AS cmId, + BRLA.CALL_STATUS AS resultCode, + BRLB.USER_KEY AS userData + FROM + BIZ_RESEND_LOG BRLA + JOIN + BIZ_RESEND_LOG BRLB + ON BRLB.UMID = BRLA.CMID + WHERE (BRLA.UMID = '' OR BRLA.UMID IS NULL); + + + + + + UPDATE MJ_MSG_DATA + SET MSG_RESULT = #msgResult# + WHERE USERDATA = #userData# + + + + + + DELETE FROM BIZ_RESEND_LOG + WHERE CMID = #cmId# OR UMID = #cmId# + + + diff --git a/src/main/resources/egovframework/sqlmap/let/uss/umt/EgovUserManage_SQL_Mysql.xml b/src/main/resources/egovframework/sqlmap/let/uss/umt/EgovUserManage_SQL_Mysql.xml index 75e0c297..9d56acdd 100644 --- a/src/main/resources/egovframework/sqlmap/let/uss/umt/EgovUserManage_SQL_Mysql.xml +++ b/src/main/resources/egovframework/sqlmap/let/uss/umt/EgovUserManage_SQL_Mysql.xml @@ -1367,6 +1367,7 @@ LETTNGNRLMBER SET SMISHING_YN = #smishingYn# + , AT_SMISHING_YN = #atSmishingYn# WHERE 1=1 AND MBER_ID = #mberId# diff --git a/src/main/webapp/WEB-INF/jsp/web/com/webCommonHeader.jsp b/src/main/webapp/WEB-INF/jsp/web/com/webCommonHeader.jsp index 7ec4848e..a5a15083 100644 --- a/src/main/webapp/WEB-INF/jsp/web/com/webCommonHeader.jsp +++ b/src/main/webapp/WEB-INF/jsp/web/com/webCommonHeader.jsp @@ -1557,8 +1557,10 @@ function actionLogin_end(){
diff --git a/src/main/webapp/WEB-INF/jsp/web/kakao/include/KaKaoAlimtalkTopMenuTap.jsp b/src/main/webapp/WEB-INF/jsp/web/kakao/include/KaKaoAlimtalkTopMenuTap.jsp index f107beaf..442ed9da 100644 --- a/src/main/webapp/WEB-INF/jsp/web/kakao/include/KaKaoAlimtalkTopMenuTap.jsp +++ b/src/main/webapp/WEB-INF/jsp/web/kakao/include/KaKaoAlimtalkTopMenuTap.jsp @@ -60,9 +60,9 @@ function fnLinkPageTopTab(tabInfo){ url = ""; - }else if(tabInfo == 'tabAlimtalkIntrd'){ + }else if(tabInfo == 'tabKakaotalkIntrd'){ - url = ""; + url = ""; } @@ -142,12 +142,7 @@ function cntntBtnInfo(stepInfo){
  • - -
  • -
    +
  • -
  • +
\ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/web/kakao/intrd/KakaoAllimtalkIntro.jsp b/src/main/webapp/WEB-INF/jsp/web/kakao/intrd/KakaoAllimtalkIntro.jsp index 2934827b..59d75ec2 100644 --- a/src/main/webapp/WEB-INF/jsp/web/kakao/intrd/KakaoAllimtalkIntro.jsp +++ b/src/main/webapp/WEB-INF/jsp/web/kakao/intrd/KakaoAllimtalkIntro.jsp @@ -17,281 +17,492 @@ <%@include file="/WEB-INF/jsp/web/kakao/include/KaKaoAlimtalkTopMenuTap.jsp" %> -
+ + +
-

알림톡 소개

+

카카오톡 소개

-
-
-

알림톡이란?

-
- -
-
-
-
- -
- -
- 핸드폰 -
    -
  • - 카카오톡 전용 기업 메시지 서비스  “알림톡” -
  • -
  • -

    1

    -

    1,000자 이내 텍스트 및 이미지 전송 가능

    -
  • -
  • -

    2

    -

    문자 메시지 대비 65% 이상 저렴

    -
  • -
  • -

    3

    -

    - 카톡 채널아이디를 추가하지 않은 이용자에게도 -
    전화번호만 있으면 메시지 전송 가능 -

    -
  • -
  • -

    4

    -

    발송실패 시 자동으로 문자 대체 발송

    -
  • -
  • -

    5

    -

    카카오 인증마크를 통해 신뢰도 높은 메시지 발송

    -
  • -
  • -

    6

    -

    발신자 브랜드의 이미지 및 신뢰도 상승 효과 달성

    -
  • -
-
- - -
-
-
-

문자 VS 알림톡

-
-
-
-
-
-

문자

-
- 문자 -

18원

-
-
-

VS

-
-

알림톡

-
- 카카오 -

6.9원

-
-
-
-

문자 대비 65% 저렴

-
-
-
-
-
-

문자

-
- 문자 -

90Byte

-
-
-

VS

-
-

알림톡

-
- 카카오 -

1,000글자

-
-
-
-

바이트(byte)에 관계없이 무조건 1,000자(한/영) 발송

-
-
-
-
-
-
- - -
-
-

알림톡 활용 방법

-
-
-
-
-
-
-
    - - - - - - -
-
- 금융,보험 -
-
- 기관,단체 -
-
- 여행 -
-
- 예약,예약 -
-
- 배송,배달 -
-
- 안내,이벤트 -
-
-
+
    +
  • +
  • +
- -
-
-

서비스 이용 방법

-
-
-
-
-
-
-
-
-

STEP 01

-
-
- -
-
-

- 카카오톡 채널을 먼저 가입해주신 다음
- 비즈니스 채널 전환 신청을 해주세요. -

-

- ※ 가입 후 카카오톡 채널 설정에서
- 공개, 검색허용 설정을 하셔야 합니다. -

-
-
- 카카오톡 채널 가입하러 가기 아이콘 -
-
+ +
+
+
+

알림톡이란?

-
-
-

STEP 02

+ +
+
+
+
+ +
+ +
+ 핸드폰 +
    +
  • + 카카오톡 전용 기업 메시지 서비스  “알림톡” +
  • +
  • +

    1

    +

    1,000자 이내 텍스트 및 이미지 전송 가능

    +
  • +
  • +

    2

    +

    문자 메시지 대비 65% 이상 저렴

    +
  • +
  • +

    3

    +

    + 카톡 채널아이디를 추가하지 않은 이용자에게도 +
    전화번호만 있으면 메시지 전송 가능 +

    +
  • +
  • +

    4

    +

    발송실패 시 자동으로 문자 대체 발송

    +
  • +
  • +

    5

    +

    카카오 인증마크를 통해 신뢰도 높은 메시지 발송

    +
  • +
  • +

    6

    +

    발신자 브랜드의 이미지 및 신뢰도 상승 효과 달성

    +
  • +
-
-
-<%-- 채널 ID 등록하러 가기화살표 --%> - 채널 ID 등록하러 가기화살표 + + +
+
+
+

문자 VS 알림톡

+
-
-
-

- 가입하신 카카오톡 채널의 채널ID(채널이름)를
- 채널ID 등록 메뉴에 등록해주세요. -

-
-
- 채널 ID 등록하러 가기 아이콘 +
+
+
+

문자

+
+ 문자 +

18원

+
+
+

VS

+
+

알림톡

+
+ 카카오 +

6.9원

+
+
+
+

문자 대비 65% 저렴

+
+
+
+
+
+

문자

+
+ 문자 +

90Byte

+
+
+

VS

+
+

알림톡

+
+ 카카오 +

1,000글자

+
+
+
+

바이트(byte)에 관계없이 무조건 1,000자(한/영) 발송

+
+
-
-
-
-

STEP 03

-
-
- -
-
-

- 알림톡 발송을 위해서는 사용하실 템플릿(메시지 내용)에 - 대한 카카오의 승인이 반드시 필요합니다. - 템플릿을 작성하신 후 심사요청을 진행해주세요. -

-

- ※ 템플릿 승인까지 최대 3일 소요 -

-
-
- 알림톡 템플릿 등록하러 가기 아이콘 -
-
+ + +
+
+

알림톡 활용 방법

-
-
-

STEP 04

+
+
+
+
+
+
    + + + + + + +
+
+ 금융,보험
-
- -
-
-

- 템플릿이 승인되셨다면 문자온 알림톡을
- 통해 메시지를 발송하실 수 있습니다. -

-
-
- 알림톡 전송하기 아이콘 -
+
+ 기관,단체 +
+
+ 여행 +
+
+ 예약,예약 +
+
+ 배송,배달 +
+
+ 안내,이벤트
- -
- 알림톡 이용가이드 보기 알림톡 이용가이드 화살표 + + +
+
+

서비스 이용 방법

+
+
+
+
+
+
+
+
+

STEP 01

+
+
+ +
+
+

+ 카카오톡 채널을 먼저 가입해주신 다음
+ 비즈니스 채널 전환 신청을 해주세요. +

+

+ ※ 가입 후 카카오톡 채널 설정에서
+ 공개, 검색허용 설정을 하셔야 합니다. +

+
+
+ 카카오톡 채널 가입하러 가기 아이콘 +
+
+
+
+
+

STEP 02

+
+
+ +
+
+

+ 가입하신 카카오톡 채널의 채널ID(채널이름)를
+ 채널ID 등록 메뉴에 등록해주세요. +

+
+
+ 채널 ID 등록하러 가기 아이콘 +
+
+
+
+
+
+
+

STEP 03

+
+
+ +
+
+

+ 알림톡 발송을 위해서는 사용하실 템플릿(메시지 내용)에 + 대한 카카오의 승인이 반드시 필요합니다. + 템플릿을 작성하신 후 심사요청을 진행해주세요. +

+

+ ※ 템플릿 승인까지 최대 3일 소요 +

+
+
+ 알림톡 템플릿 등록하러 가기 아이콘 +
+
+
+
+
+

STEP 04

+
+
+ +
+
+

+ 템플릿이 승인되셨다면 문자온 알림톡을
+ 통해 메시지를 발송하실 수 있습니다. +

+
+
+ 알림톡 전송하기 아이콘 +
+
+
+
+ + +
+ + +
+
+

+ + 유의사항 아이콘 + 유의사항 +

+
+
    +
  • - 한글, 영문 구분 없이 최대 1,000자까지 전송 가능합니다.
  • +
  • - 알림톡 발송 실패에 따른 대체문자 발송 시 문자요금(단문, 장문, 그림)이 보유 캐시에서 차감됩니다.
  • +
  • - 알림톡에서 허용하는 영리목적이 없는 정보성 메시지에 해당하는지 여부는 스팸 관련 정보통신망법 안내서를 꼭 참고하시길 바랍니다.
  • +
  • (주문/예약 확인, 결제 내역, 배송 현황 메시지 등이 이에 해당하며 구독자 대상의 뉴스레터나 일반적인 공지문은 포함되지 않습니다.)
  • +
  • + 스팸 관련 정보통신망법 안내서 바로가기 +
  • +
  • - 부고, 답례, 초대장 등은 정보성 메시지가 아니므로 알림톡으로 보내실 수 없습니다.
  • +
- - -
-
-

- - 유의사항 아이콘 - 유의사항 -

+ + + +
+
+
+

친구톡이란?

+
+ +
+
+
+
+ +
+ +
+ 핸드폰 + +
    +
  • + 카카오톡 전용 기업 메시지 서비스  “알림톡” +
  • +
  • +

    1

    +

    광고성 메시지 발송 가능(광고 표기 및 수신거부 안내 포함)

    +
  • +
  • +

    2

    +

    채널 친구 추가된 사용자라면 누구에게나 발송 가능

    +
  • +
  • +

    3

    +

    1,000자 이내 텍스트 및 이미지 전송 가능

    +
  • +
  • +

    4

    +

    맞춤형 메시지 및 쿠폰, 링크 버튼 제공 가능

    +
  • +
  • +

    5

    +

    문자 메시지 대비 O % 이상 저렴

    +
  • +
  • +

    6

    +

    발송실패 시 대체문자 발송 기능 지원

    +
  • +
  • +

    7

    +

    클릭률/도달률 분석을 통한 마케팅 효율 강화

    +
  • +
  • +

    8

    +

    브랜드 친화적인 이미지 커스터마이징 가능

    +
  • +
+
+ + +
+
+
+

알림톡 VS 친구톡

+
+
+ +
+
+
알림톡
+
+
    +
  • 전화번호 보유자
  • +
  • 정보성 (예 : 주문, 예약, 안내 등)
  • +
  • 텍스트, 이미지 등
  • +
  • 최대 5개
  • +
  • 사전 승인 필요
  • +
  • 6.9원
  • +
  • 1,000자
  • +
  • 로고, 아이콘 형식만 가능
  • +
+
+
+ +
+
VS
+
    +
  • 전송대상
  • +
  • 발송목적
  • +
  • 메세지 형태
  • +
  • 버튼 사용
  • +
  • 템플릿 승인
  • +
  • 비용
  • +
  • 길이제한
  • +
  • 이미지
  • +
+
+ +
+
친구톡
+
+
    +
  • 채널 친구
  • +
  • 광고 및 마케팅성(예 : 이벤트, 쿠폰 등)
  • +
  • 텍스트, 기본이미지, 와이드 이미지형 등
  • +
  • 최대 5개
  • +
  • 별도 승인 없음 야간 발송 제한(20:50 ~ 익일 08:00)
  • +
  • 0.0원 ~ 0.0원
  • +
  • 1,000자
  • +
  • 가능
  • +
+
+
+
+
+
+
+ + +
+
+

친구톡 유형

+
+ +
+
+
+
+ +
    +
  • +
    텍스트형
    + +

    한/영 구분없이 1,000자 + 버튼 최대 5개

    +
  • +
  • +
    기본 이미지형
    + +

    한/영 구분없이 400자 + 이미지 1장 + 버튼 최대 5개

    +
  • +
  • +
    와이드 이미지형
    + +

    한/영 구분없이 76자 + 이미지 1장 + 버튼 최대 1개

    +
  • +
+
+ + +
+
+

서비스 이용 방법

+
+ +
+
+
+
+ +
    +
  • +
    STEP 01
    + +

    카카오톡 채널 가입

    + 카카오톡 채널 생성을 위한
    계정이 없으시다면, 카카오에서
    카카오톡 비즈니스 회원가입을
    먼저 진행해주세요.
    +
  • +
  • +
    STEP 02
    + +

    채널 ID 등록하러 가기

    + 가입하신 카카오톡 채널의 채널 ID(채널이름)를 채널 ID 등록 메뉴에 등록해주세요. +
  • +
  • +
    STEP 03
    + +

    친구톡 전송

    + 친구톡은 별도의 템플릿 심사 절차 없이, 즉시 발송 가능합니다. +
  • +
+ + + +
+ + +
+
+

유의사항 아이콘유의사항

+
+
    +
  • - (광고) 표기 여부는 선택 가능하나 , (광고)표기 해제에 따른 법령상 의무사항을 미 준수시에는 메시지 발송이 중단될 수 있습니다.
  • +
  • - 광고성 친구톡 메시지에는 “(광고) 표시 및 수신거부 방식”이 표시되며, 대체 문자의 경우에는 “(광고) 문구 및 080 무료수신거부 번호”가 자동으로 포함됩니다.
  • +
  • - 광고성 메시지의 발송 가능 시간은 08:00 ~ 20:50(한국시간) 입니다.
  • +
  • - 친구톡 발송 실패에 따른 대체문자 발송 시 문자요금(단문, 장문, 그림)이 보유 캐시에서 차감됩니다.
  • +
  • - 카카오정책 및 심의기준을 반드시 준수하여야 합니다.
  • +
-
    -
  • - 한글, 영문 구분 없이 최대 1,000자까지 전송 가능합니다.
  • -
  • - 알림톡 발송 실패에 따른 대체문자 발송 시 문자요금(단문, 장문, 그림)이 보유 캐시에서 차감됩니다.
  • -
  • - 알림톡에서 허용하는 영리목적이 없는 정보성 메시지에 해당하는지 여부는 스팸 관련 정보통신망법 안내서를 꼭 참고하시길 바랍니다.
  • -
  • (주문/예약 확인, 결제 내역, 배송 현황 메시지 등이 이에 해당하며 구독자 대상의 뉴스레터나 일반적인 공지문은 포함되지 않습니다.)
  • -
  • - 스팸 관련 정보통신망법 안내서 바로가기 -
  • -
  • - 부고, 답례, 초대장 등은 정보성 메시지가 아니므로 알림톡으로 보내실 수 없습니다.
  • -
+ +
diff --git a/src/main/webapp/WEB-INF/jsp/web/kakao/intrd/KakaotalkIntro.jsp b/src/main/webapp/WEB-INF/jsp/web/kakao/intrd/KakaotalkIntro.jsp new file mode 100644 index 00000000..2b977212 --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/web/kakao/intrd/KakaotalkIntro.jsp @@ -0,0 +1,509 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> +<%@ taglib prefix="ec" uri="/WEB-INF/tld/ecnet_tld.tld"%> +<%@ page import="itn.com.cmm.LoginVO" %> + + +
+ +
+ +
+ +
+ + <%@include file="/WEB-INF/jsp/web/kakao/include/KaKaoAlimtalkTopMenuTap.jsp" %> + + + + +
+
+

카카오톡 소개

+
+ +
    +
  • +
  • +
+ + +
+
+
+

알림톡이란?

+
+ +
+
+
+
+ +
+ +
+ 핸드폰 +
    +
  • + 카카오톡 전용 기업 메시지 서비스  “알림톡” +
  • +
  • +

    1

    +

    1,000자 이내 텍스트 및 이미지 전송 가능

    +
  • +
  • +

    2

    +

    문자 메시지 대비 65% 이상 저렴

    +
  • +
  • +

    3

    +

    + 카톡 채널아이디를 추가하지 않은 이용자에게도 +
    전화번호만 있으면 메시지 전송 가능 +

    +
  • +
  • +

    4

    +

    발송실패 시 자동으로 문자 대체 발송

    +
  • +
  • +

    5

    +

    카카오 인증마크를 통해 신뢰도 높은 메시지 발송

    +
  • +
  • +

    6

    +

    발신자 브랜드의 이미지 및 신뢰도 상승 효과 달성

    +
  • +
+
+ + +
+
+
+

문자 VS 알림톡

+
+
+
+
+
+

문자

+
+ 문자 +

18원

+
+
+

VS

+
+

알림톡

+
+ 카카오 +

6.9원

+
+
+
+

문자 대비 65% 저렴

+
+
+
+
+
+

문자

+
+ 문자 +

90Byte

+
+
+

VS

+
+

알림톡

+
+ 카카오 +

1,000글자

+
+
+
+

바이트(byte)에 관계없이 무조건 1,000자(한/영) 발송

+
+
+
+
+
+
+ + +
+
+

알림톡 활용 방법

+
+
+
+
+
+
+
    + + + + + + +
+
+ 금융,보험 +
+
+ 기관,단체 +
+
+ 여행 +
+
+ 예약,예약 +
+
+ 배송,배달 +
+
+ 안내,이벤트 +
+
+
+ + +
+
+

서비스 이용 방법

+
+
+
+
+
+
+
+
+

STEP 01

+
+
+ +
+
+

+ 카카오톡 채널을 먼저 가입해주신 다음
+ 비즈니스 채널 전환 신청을 해주세요. +

+

+ ※ 가입 후 카카오톡 채널 설정에서
+ 공개, 검색허용 설정을 하셔야 합니다. +

+
+
+ 카카오톡 채널 가입하러 가기 아이콘 +
+
+
+
+
+

STEP 02

+
+
+ +
+
+

+ 가입하신 카카오톡 채널의 채널ID(채널이름)를
+ 채널ID 등록 메뉴에 등록해주세요. +

+
+
+ 채널 ID 등록하러 가기 아이콘 +
+
+
+
+
+
+
+

STEP 03

+
+
+ +
+
+

+ 알림톡 발송을 위해서는 사용하실 템플릿(메시지 내용)에 + 대한 카카오의 승인이 반드시 필요합니다. + 템플릿을 작성하신 후 심사요청을 진행해주세요. +

+

+ ※ 템플릿 승인까지 최대 3일 소요 +

+
+
+ 알림톡 템플릿 등록하러 가기 아이콘 +
+
+
+
+
+

STEP 04

+
+
+ +
+
+

+ 템플릿이 승인되셨다면 문자온 알림톡을
+ 통해 메시지를 발송하실 수 있습니다. +

+
+
+ 알림톡 전송하기 아이콘 +
+
+
+
+ + +
+ + +
+
+

+ + 유의사항 아이콘 + 유의사항 +

+
+
    +
  • - 한글, 영문 구분 없이 최대 1,000자까지 전송 가능합니다.
  • +
  • - 알림톡 발송 실패에 따른 대체문자 발송 시 문자요금(단문, 장문, 그림)이 보유 캐시에서 차감됩니다.
  • +
  • - 알림톡에서 허용하는 영리목적이 없는 정보성 메시지에 해당하는지 여부는 스팸 관련 정보통신망법 안내서를 꼭 참고하시길 바랍니다.
  • +
  • (주문/예약 확인, 결제 내역, 배송 현황 메시지 등이 이에 해당하며 구독자 대상의 뉴스레터나 일반적인 공지문은 포함되지 않습니다.)
  • +
  • + 스팸 관련 정보통신망법 안내서 바로가기 +
  • +
  • - 부고, 답례, 초대장 등은 정보성 메시지가 아니므로 알림톡으로 보내실 수 없습니다.
  • +
+
+
+ + + +
+
+
+

친구톡이란?

+
+ +
+
+
+
+ +
+ +
+ 핸드폰 + +
    +
  • + 카카오톡 전용 기업 메시지 서비스  “알림톡” +
  • +
  • +

    1

    +

    광고성 메시지 발송 가능(광고 표기 및 수신거부 안내 포함)

    +
  • +
  • +

    2

    +

    채널 친구 추가된 사용자라면 누구에게나 발송 가능

    +
  • +
  • +

    3

    +

    1,000자 이내 텍스트 및 이미지 전송 가능

    +
  • +
  • +

    4

    +

    맞춤형 메시지 및 쿠폰, 링크 버튼 제공 가능

    +
  • +
  • +

    5

    +

    문자 메시지 대비 저렴한 단가

    +
  • +
  • +

    6

    +

    발송실패 시 대체문자 발송 기능 지원

    +
  • +
  • +

    7

    +

    클릭률/도달률 분석을 통한 마케팅 효율 강화

    +
  • +
  • +

    8

    +

    브랜드 친화적인 이미지 커스터마이징 가능

    +
  • +
+
+ + +
+
+
+

알림톡 VS 친구톡

+
+
+ +
+
+
알림톡
+
+
    +
  • 전화번호 보유자
  • +
  • 정보성 (예 : 주문, 예약, 안내 등)
  • +
  • 텍스트, 이미지 등
  • +
  • 최대 5개
  • +
  • 사전 승인 필요
  • +
  • 6.9원
  • +
  • 1,000자
  • +
  • 로고, 아이콘 형식만 가능
  • +
+
+
+ +
+
VS
+
    +
  • 전송대상
  • +
  • 발송목적
  • +
  • 메세지 형태
  • +
  • 버튼 사용
  • +
  • 템플릿 승인
  • +
  • 비용
  • +
  • 길이제한
  • +
  • 이미지
  • +
+
+ +
+
친구톡
+
+
    +
  • 채널 친구
  • +
  • 광고 및 마케팅성(예 : 이벤트, 쿠폰 등)
  • +
  • 텍스트, 기본이미지, 와이드 이미지형 등
  • +
  • 최대 5개
  • +
  • 별도 승인 없음 야간 발송 제한(20:50 ~ 익일 08:00)
  • +
  • 13.8원 ~ 22.9원
  • +
  • 1,000자
  • +
  • 가능
  • +
+
+
+
+
+
+
+ + +
+
+

친구톡 유형

+
+ +
+
+
+
+ +
    +
  • +
    텍스트형
    + +

    한/영 구분없이 1,000자 + 버튼 최대 5개

    +
  • +
  • +
    기본 이미지형
    + +

    한/영 구분없이 400자 + 이미지 1장 + 버튼 최대 5개

    +
  • +
  • +
    와이드 이미지형
    + +

    한/영 구분없이 76자 + 이미지 1장 + 버튼 최대 1개

    +
  • +
+
+ + +
+
+

서비스 이용 방법

+
+ +
+
+
+
+ +
    +
  • +
    STEP 01
    + +

    카카오톡 채널 가입

    + 카카오톡 채널 생성을 위한
    계정이 없으시다면, 카카오에서
    카카오톡 비즈니스 회원가입을
    먼저 진행해주세요.
    +
  • +
  • +
    STEP 02
    + +

    채널 ID 등록하러 가기

    + 가입하신 카카오톡 채널의 채널 ID(채널이름)를 채널 ID 등록 메뉴에 등록해주세요. +
  • +
  • +
    STEP 03
    + +

    친구톡 전송

    + 친구톡은 별도의 템플릿 심사 절차 없이, 즉시 발송 가능합니다. +
  • +
+ + + +
+ + +
+
+

유의사항 아이콘유의사항

+
+
    +
  • - (광고) 표기 여부는 선택 가능하나 , (광고)표기 해제에 따른 법령상 의무사항을 미 준수시에는 메시지 발송이 중단될 수 있습니다.
  • +
  • - 광고성 친구톡 메시지에는 “(광고) 표시 및 수신거부 방식”이 표시되며, 대체 문자의 경우에는 “(광고) 문구 및 080 무료수신거부 번호”가 자동으로 포함됩니다.
  • +
  • - 광고성 메시지의 발송 가능 시간은 08:00 ~ 20:50(한국시간) 입니다.
  • +
  • - 친구톡 발송 실패에 따른 대체문자 발송 시 문자요금(단문, 장문, 그림)이 보유 캐시에서 차감됩니다.
  • +
  • - 카카오정책 및 심의기준을 반드시 준수하여야 합니다.
  • +
+
+
+ + +
+
+
+ \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/web/kakao/sent/KakaoSentDetailPhoneAjax.jsp b/src/main/webapp/WEB-INF/jsp/web/kakao/sent/KakaoSentDetailPhoneAjax.jsp new file mode 100644 index 00000000..0b12b87f --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/web/kakao/sent/KakaoSentDetailPhoneAjax.jsp @@ -0,0 +1,194 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> +<% pageContext.setAttribute("newLineChar", "\n"); %> +
+ +
+
    +
  • + +
  • +
    +
+
+ + + + + +
+ + +
+
+

+ +
+
+ + 알림톡 도착 +
+
+ + +

+

+
+ +
+ +
+
+
+ +

+ +

+ + + +

+
+ +

+
+
+ + + + + + + + + + + +
+ +
+
+

※ 단말기 설정에 따라 다르게 보일 수 있습니다

+
+
+ + + +
+
+

+ +
+ +

(광고)

+
+
+ + +

+

+
+ +
+ +
+
+
+ +

+ +

+ + + +

+
+ +

+
+
+ + + + + + + + + + + +
+ + +

수신거부 : 홈 > 채널차단

+
+ +
+
+

※ 단말기 설정에 따라 다르게 보일 수 있습니다

+
+
+ +
+ + + + + + + +
+ \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/web/kakao/sent/KakaoSentDetailPopAjax.jsp b/src/main/webapp/WEB-INF/jsp/web/kakao/sent/KakaoSentDetailPopAjax.jsp index dc18c0fb..2a8cbad7 100644 --- a/src/main/webapp/WEB-INF/jsp/web/kakao/sent/KakaoSentDetailPopAjax.jsp +++ b/src/main/webapp/WEB-INF/jsp/web/kakao/sent/KakaoSentDetailPopAjax.jsp @@ -6,118 +6,174 @@ <% pageContext.setAttribute("newLineChar", "\n"); %>
- -
-
    -
  • - -
  • -
    -
-
- + +
+
    +
  • + +
  • +
    +
+
+ - - - -
-
-
-

- -
- -

(광고)

-
-
- - -

-

-
- -
- -
-
-
+
+ + +
+
+
+ + 발송일시 : + + 알림톡 + +
+ +
+
+
+ + 알림톡 도착 +
+
+ + +

+

+
+ +
+ +
+
+
+

+ +

+ + + +

+
+ +

+
+
+ + + + + + + + + + + +
+
+
+
+

※ 단말기 설정에 따라 다르게 보일 수 있습니다

+
+
+ + + +
+
+
+ + 발송일시 : + + 친구톡 + +
+ +
+
+ +

(광고)

+
+
+ + +

+

+
+ +
+ +
+
+
-

- -

- - - -

-
- -

-
-
- - - - - - - - - - - -
- - -

수신거부 : 홈 > 채널차단

-
- -
-
-

※ 단말기 설정에 따라 다르게 보일 수 있습니다

-
-
- +

+ +

+ + + +

+
+ +

+
+
+ + + + + + + + + + + +
+ + +

수신거부 : 홈 > 채널차단

+
+ +
+
+
+

※ 단말기 설정에 따라 다르게 보일 수 있습니다

+
+ +
+ - - diff --git a/src/main/webapp/WEB-INF/jsp/web/pay/PayUserMsgDetailPopAjax.jsp b/src/main/webapp/WEB-INF/jsp/web/pay/PayUserMsgDetailPopAjax.jsp index 1fed6956..6e3d77a2 100644 --- a/src/main/webapp/WEB-INF/jsp/web/pay/PayUserMsgDetailPopAjax.jsp +++ b/src/main/webapp/WEB-INF/jsp/web/pay/PayUserMsgDetailPopAjax.jsp @@ -11,7 +11,7 @@ <%-- --%>
- 발송일시 : + 발송일시 : SMS diff --git a/src/main/webapp/WEB-INF/jsp/web/pay/PayUserSWList.jsp b/src/main/webapp/WEB-INF/jsp/web/pay/PayUserSWList.jsp index 88679c48..b444156f 100644 --- a/src/main/webapp/WEB-INF/jsp/web/pay/PayUserSWList.jsp +++ b/src/main/webapp/WEB-INF/jsp/web/pay/PayUserSWList.jsp @@ -563,7 +563,7 @@ function fnRevDetailPop03(msgGroupId){
  • - +
  • diff --git a/src/main/webapp/publish/css/popupLayer.css b/src/main/webapp/publish/css/popupLayer.css index 8bd79e24..334e876c 100644 --- a/src/main/webapp/publish/css/popupLayer.css +++ b/src/main/webapp/publish/css/popupLayer.css @@ -512,8 +512,7 @@ /* 예약관리 */ /* 예약관리 - 문자내용 */ .rev_pop_in input[type="text"] {background-color: #f2f2f2; width: 100%; height: 50px; border-radius: 5px;} -.rev_pop_in input[type="text"]::placeholder {font-size: 17px; color: #222; font-weight: 400 -;} +.rev_pop_in input[type="text"]::placeholder {font-size: 17px; color: #222; font-weight: 400;} .rev_pop_in input[type="text"]-ms-input-placeholder {font-size: 17px; color: #222; font-weight: 400;} .rev_pop_middle {margin:0 0 10px;} .rev_pop_middle span:first-child {float: left; font-size: 16px; font-weight: 300; padding-top: 5px;} @@ -1077,6 +1076,7 @@ .kakao_rev_popup .kakao_wrap .allimtalk_title::after{position: absolute; content: " "; width: 42px; height: 42px; background: url(/publish/images/content/icon_kakao01.png) no-repeat; right: -20px; top: -10px;} .kakao_rev_popup .kakao_wrap .allimtalk_title img{margin: 0 8px 0 0; vertical-align: bottom;} .kakao_rev_popup .kakao_wrap .allimtalk_content{width: calc(100% - 60px);background-color: #fff; border-radius: 0 0 5px 5px; padding: 0 0 10px 0; margin: 0 0 20px 0;} +.kakao_rev_popup .kakao_wrap .friendtalk .allimtalk_content{margin:0;} .kakao_rev_popup .kakao_wrap .allimtalk_content .kakao_image img{width: 100%;} .kakao_rev_popup .kakao_wrap .allimtalk_content p{width: calc(100% - 20px); white-space: normal; word-break: break-all; line-height: 1.4; padding: 0 10px; margin: 0 auto;} .kakao_rev_popup .kakao_wrap .allimtalk_content .template_text,.kakao_rev_popup .kakao_wrap .allimtalk_content .emphasis_title_text{font-size: 16px; font-weight: 500; color: #222;} @@ -1091,6 +1091,15 @@ .kakao_rev_popup .kakao_wrap .allimtalk_content .template_text+.btn_kakao_type{margin-top: 8px;} .kakao_rev_popup .kakao_wrap .allimtalk_content .btn_kakao_channel{width: calc(100% - 20px); height: 40px; font-size: 15px; border-radius: 5px; background-color: #ffea00;} .kakao_rev_popup .kakao_wrap .allimtalk_content .btn_kakao_type{width: calc(100% - 20px); height: 40px; font-size: 15px; border-radius: 5px; background-color: #ededed;} +.kakao_rev_popup .tab_phone .addText{margin:8px 0 0 0;color:#002c9a;font-size:14px;} + +/* 카카오톡 발송결과, 예약관리 문자내용 보기 - 친구톡 */ +.kakao_rev_popup .kakao_wrap .friendtalk .allimtalk_content{border-radius:5px;} +.kakao_rev_popup .kakao_wrap .friendtalk .kakao_image{border-radius:5px 5px 0 0;overflow:hidden;} +.kakao_rev_popup .kakao_wrap .friendtalk .rev_pop_txt{padding:20px;} +.kakao_rev_popup .kakao_wrap .friendtalk .rev_pop_txt p {margin:0 0 10px 0;font-size: 15px;color:#777;} +.kakao_rev_popup .kakao_wrap .friendtalk .rev_pop_txt .template_text{padding:10px 10px 0 10px;} +.kakao_rev_popup .kakao_wrap .friendtalk .rev_pop_txt p.kakao_block_text{width:calc(100% - 60px);text-align:right;font-size:13px;color:#555;font-weight:300;margin:10px 0 0 0;} /* 카카오테스트발송 팝업 */ .test_sendpop.kakao_rev_popup .kakao_wrap .phone .phoneIn{height: 620px; background-image: url(/publish/images/content/kakaoBg.png);padding: 28px 19px 0 19px;}