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/.gitignore b/.gitignore index a8209c63..f1e66539 100644 --- a/.gitignore +++ b/.gitignore @@ -202,6 +202,4 @@ rebel.xml /mvnw /mvnw.cmd /.gemini.zip - -### MAC OS ### -.DS_Store \ No newline at end of file +/CLAUDE.md diff --git a/src/main/java/itn/com/cmm/MjonFTSendVO.java b/src/main/java/itn/com/cmm/MjonFTSendVO.java new file mode 100644 index 00000000..edc815dc --- /dev/null +++ b/src/main/java/itn/com/cmm/MjonFTSendVO.java @@ -0,0 +1,130 @@ +package itn.com.cmm; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +public class MjonFTSendVO{ + + + /** + * @description : 수신자번호 + */ + private String phone; + + /** + * @description : [*이름*] - 치환문자 + */ + private String name; + + /** + * @description : [*1*] - 치환문자 + */ + private String rep1; + + /** + * @description : [*2*] - 치환문자 + */ + private String rep2; + + /** + * @description : [*3*] - 치환문자 + */ + private String rep3; + + /** + * @description : [*4*] - 치환문자 + */ + private String rep4; + + /** + * @description : 문자ID + */ + private String msgId; + + /** + * @description : 전송그룹ID (대량문자의 경우 하나의 그룹으로 세팅) + */ + private String msgGroupId; + + /** + * @description : 문자온 일반회원ID + */ + private String userId; + + /** + * @description : 발신번호 (하이픈 등의 문자를 제외한 12byte이하의 숫자로 입력한다.) + */ + private String callFrom; + /** + * @description : 수신번호 (하이픈 등의 문자를 제외한 12byte이하의 숫자로 입력한다.) + */ + private String callTo; + /** + * @description : 예약 발송일시 + */ + private String reqDate; + /** + * @description :전송사(04:다우, 05:JJ, 07:IVT, 01:아이하트 , 02:현대퓨처넷, 03:아이엠오) + */ + private String agentCode; + + /** + * @description : MMS용 메시지제목 + */ + private String subject; + + /** + * @description : SMS용 메시지본문 + */ + private String smsTxt; + + /** + * @description : 메세지타입(4: SMS 전송, 5: URL 전송, 6: MMS전송, 7: BARCODE전송, 8: 카카오 알림톡 전송) + */ + private String msgType; + + + /** + * @description : 첨부파일 갯수 + */ + private String fileCnt; + + /** + * @description : 파일이름1 + */ + private String filePath1; + + /** + * @description : 파일이름2 + */ + private String filePath2; + + /** + * @description : 파일이름3 + */ + private String filePath3; + + + + /** + * @description : event 여부 / group tb에 넣는 용도 / 기본값 N + */ + private String eventYn="N"; + + + + /** + * @description : 개별단가 + */ + private String eachPrice; + + + + + + +} diff --git a/src/main/java/itn/com/cmm/util/MsgSendUtils.java b/src/main/java/itn/com/cmm/util/MsgSendUtils.java index 339137e9..4f4b9ee9 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 + " 데이터가 없습니다."); @@ -463,7 +459,7 @@ public final class MsgSendUtils { } } - private static Boolean getReplaceYN(String smsTxtTemplate) {// 여러 치환 구문이 포함된 정규식 패턴 + public static Boolean getReplaceYN(String smsTxtTemplate) {// 여러 치환 구문이 포함된 정규식 패턴 if (smsTxtTemplate == null) { return false; // null일 경우 false 반환 diff --git a/src/main/java/itn/let/kakao/admin/kakaoAt/service/MjonKakaoATVO.java b/src/main/java/itn/let/kakao/admin/kakaoAt/service/MjonKakaoATVO.java index 712e0b91..1792b097 100644 --- a/src/main/java/itn/let/kakao/admin/kakaoAt/service/MjonKakaoATVO.java +++ b/src/main/java/itn/let/kakao/admin/kakaoAt/service/MjonKakaoATVO.java @@ -3,7 +3,11 @@ package itn.let.kakao.admin.kakaoAt.service; import java.util.List; import itn.com.cmm.ComDefaultVO; +import lombok.Getter; +import lombok.Setter; +@Getter +@Setter public class MjonKakaoATVO extends ComDefaultVO{ private static final long serialVersionUID = 1L; @@ -30,6 +34,7 @@ public class MjonKakaoATVO extends ComDefaultVO{ private String msgKind; // '문자 종류 일반:N, 광고:A, 선거:C', private String msgPayCode; // '재전송 기능에 의한 최종전송콘텐트 종류 저장', private String contSeq; // COMMENT 'MMS의 콘텐츠 Key(MMS_CONTENTS_INFO의 CONT_SEQ)', + private String contents; // BIZ_ATTACHMENTS -> COMMENT private String msgTypeResend; // '재전송할 문자 타입. 값이 있으면 재전송. 없으면 단 건 전송', private String centerSeqResend; // '재전송할 센터. NPro 내부적으로 사용함.', private String msgNoticetalkSenderKey; // '카카오 알림톡에 등록된 사용자 고유키', @@ -154,88 +159,8 @@ public class MjonKakaoATVO extends ComDefaultVO{ private String yellowId; private String bizKakaoResendTypeCnt; - public String getMsgDiv() { - return msgDiv; - } - public void setMsgDiv(String msgDiv) { - this.msgDiv = msgDiv; - } - public Float getAgentPrice() { - return agentPrice; - } - public void setAgentPrice(Float agentPrice) { - this.agentPrice = agentPrice; - } private String registPnttm; //통계등록일시 - public String getNowDate() { - return nowDate; - } - public void setNowDate(String nowDate) { - this.nowDate = nowDate; - } - public String getTodayYn() { - return todayYn; - } - public void setTodayYn(String todayYn) { - this.todayYn = todayYn; - } - public String getReserveType() { - return reserveType; - } - public void setReserveType(String reserveType) { - this.reserveType = reserveType; - } - public String getAtchFiles() { - return atchFiles; - } - public void setAtchFiles(String atchFiles) { - this.atchFiles = atchFiles; - } - public String getApprovalPnttm() { - return approvalPnttm; - } - public void setApprovalPnttm(String approvalPnttm) { - this.approvalPnttm = approvalPnttm; - } - public String getPayCnt() { - return payCnt; - } - public void setPayCnt(String payCnt) { - this.payCnt = payCnt; - } - public String getPayPct() { - return payPct; - } - public void setPayPct(String payPct) { - this.payPct = payPct; - } - public String getAdminSmsNoticeYn() { - return adminSmsNoticeYn; - } - public void setAdminSmsNoticeYn(String adminSmsNoticeYn) { - this.adminSmsNoticeYn = adminSmsNoticeYn; - } - - public String getSearchAdminSmsNoticeYn() { - return searchAdminSmsNoticeYn; - } - public void setSearchAdminSmsNoticeYn(String searchAdminSmsNoticeYn) { - this.searchAdminSmsNoticeYn = searchAdminSmsNoticeYn; - } - - public String getMaxRegDate() { - return maxRegDate; - } - public void setMaxRegDate(String maxRegDate) { - this.maxRegDate = maxRegDate; - } - public String getMinRegDate() { - return minRegDate; - } - public void setMinRegDate(String minRegDate) { - this.minRegDate = minRegDate; - } private String resultCode; //문자 결과 코드 정보 @@ -288,1005 +213,12 @@ public class MjonKakaoATVO extends ComDefaultVO{ private int totalCallCnt; //수신자 전체 갯 - public String getUserCallbackYn() { - return userCallbackYn; - } - public void setUserCallbackYn(String userCallbackYn) { - this.userCallbackYn = userCallbackYn; - } - - public String getCallbackYn() { - return callbackYn; - } - public void setCallbackYn(String callbackYn) { - this.callbackYn = callbackYn; - } - - public int getCallRejectionCount() { - return callRejectionCount; - } - public void setCallRejectionCount(int callRejectionCount) { - this.callRejectionCount = callRejectionCount; - } - public int getSuccessCount() { - return successCount; - } - public void setSuccessCount(int successCount) { - this.successCount = successCount; - } - - private int regCount; - public int getRegCount() { - return regCount; - } - public void setRegCount(int regCount) { - this.regCount = regCount; - } - public int getRegComCount() { - return regComCount; - } - public void setRegComCount(int regComCount) { - this.regComCount = regComCount; - } - - private int regComCount; - - public String getAddrGrpId() { - return addrGrpId; - } - public void setAddrGrpId(String addrGrpId) { - this.addrGrpId = addrGrpId; - } - public String getAddrGrpNm() { - return addrGrpNm; - } - public void setAddrGrpNm(String addrGrpNm) { - this.addrGrpNm = addrGrpNm; - } - - private int orderByCode; // 문자타입 정렬번호 private String detailType; + private String adFlag; - public int getOrderByCode() { - return orderByCode; - } - public void setOrderByCode(int orderByCode) { - this.orderByCode = orderByCode; - } - public String getRegDate() { - return regDate; - } - public void setRegDate(String regDate) { - this.regDate = regDate; - } - public String getMsgId() { - return msgId; - } - public void setMsgId(String msgId) { - this.msgId = msgId; - } - public String getUserId() { - return userId; - } - public void setUserId(String userId) { - this.userId = userId; - } - public String getAgentFlag() { - return agentFlag; - } - public void setAgentFlag(String agentFlag) { - this.agentFlag = agentFlag; - } - public String getUserData() { - return userData; - } - public void setUserData(String userData) { - this.userData = userData; - } - public String getMsgSeq() { - return msgSeq; - } - public void setMsgSeq(String msgSeq) { - this.msgSeq = msgSeq; - } - public String getCurState() { - return curState; - } - public void setCurState(String curState) { - this.curState = curState; - } - public String getSentDate() { - return sentDate; - } - public void setSentDate(String sentDate) { - this.sentDate = sentDate; - } - public String getRsltDate() { - return rsltDate; - } - public void setRsltDate(String rsltDate) { - this.rsltDate = rsltDate; - } - public String getReportDate() { - return reportDate; - } - public void setReportDate(String reportDate) { - this.reportDate = reportDate; - } - public String getReqDate() { - return reqDate; - } - public void setReqDate(String reqDate) { - this.reqDate = reqDate; - } - public String getRsltCode() { - return rsltCode; - } - public void setRsltCode(String rsltCode) { - this.rsltCode = rsltCode; - } - public String getRsltCode2() { - return rsltCode2; - } - public void setRsltCode2(String rsltCode2) { - this.rsltCode2 = rsltCode2; - } - public String getRsltNet() { - return rsltNet; - } - public void setRsltNet(String rsltNet) { - this.rsltNet = rsltNet; - } - public String getCallTo() { - return callTo; - } - public void setCallTo(String callTo) { - this.callTo = callTo; - } - public String getCallFrom() { - return callFrom; - } - public void setCallFrom(String callFrom) { - this.callFrom = callFrom; - } - public String getSmsTxt() { - return smsTxt; - } - public void setSmsTxt(String smsTxt) { - this.smsTxt = smsTxt; - } - public String getSmsTxtArea() { - return smsTxtArea; - } - public void setSmsTxtArea(String smsTxtArea) { - this.smsTxtArea = smsTxtArea; - } - public String getMsgType() { - return msgType; - } - public void setMsgType(String msgType) { - this.msgType = msgType; - } - public String getMsgKind() { - return msgKind; - } - public void setMsgKind(String msgKind) { - this.msgKind = msgKind; - } - public String getMsgPayCode() { - return msgPayCode; - } - public void setMsgPayCode(String msgPayCode) { - this.msgPayCode = msgPayCode; - } - public String getContSeq() { - return contSeq; - } - public void setContSeq(String contSeq) { - this.contSeq = contSeq; - } - public String getMsgTypeResend() { - return msgTypeResend; - } - public void setMsgTypeResend(String msgTypeResend) { - this.msgTypeResend = msgTypeResend; - } - public String getCenterSeqResend() { - return centerSeqResend; - } - public void setCenterSeqResend(String centerSeqResend) { - this.centerSeqResend = centerSeqResend; - } - public String getMsgNoticetalkSenderKey() { - return msgNoticetalkSenderKey; - } - public void setMsgNoticetalkSenderKey(String msgNoticetalkSenderKey) { - this.msgNoticetalkSenderKey = msgNoticetalkSenderKey; - } - public String getMsgNoticetalkTmpKey() { - return msgNoticetalkTmpKey; - } - public void setMsgNoticetalkTmpKey(String msgNoticetalkTmpKey) { - this.msgNoticetalkTmpKey = msgNoticetalkTmpKey; - } - public String getMsgResendCount() { - return msgResendCount; - } - public void setMsgResendCount(String msgResendCount) { - this.msgResendCount = msgResendCount; - } - public String getMsgResenddate() { - return msgResenddate; - } - public void setMsgResenddate(String msgResenddate) { - this.msgResenddate = msgResenddate; - } - public String getSentDatePre() { - return sentDatePre; - } - public void setSentDatePre(String sentDatePre) { - this.sentDatePre = sentDatePre; - } - public String getRsltDatePre() { - return rsltDatePre; - } - public void setRsltDatePre(String rsltDatePre) { - this.rsltDatePre = rsltDatePre; - } - public String getReportDatePre() { - return reportDatePre; - } - public void setReportDatePre(String reportDatePre) { - this.reportDatePre = reportDatePre; - } - public String getRsltCodePre() { - return rsltCodePre; - } - public void setRsltCodePre(String rsltCodePre) { - this.rsltCodePre = rsltCodePre; - } - public String getRsltCode2Pre() { - return rsltCode2Pre; - } - public void setRsltCode2Pre(String rsltCode2Pre) { - this.rsltCode2Pre = rsltCode2Pre; - } - public String getRsltNetPre() { - return rsltNetPre; - } - public void setRsltNetPre(String rsltNetPre) { - this.rsltNetPre = rsltNetPre; - } - public String getConectMthd() { - return conectMthd; - } - public void setConectMthd(String conectMthd) { - this.conectMthd = conectMthd; - } - - public String getAgentCode() { - return agentCode; - } - public void setAgentCode(String agentCode) { - this.agentCode = agentCode; - } - public String getConectMthdTxt() { - return conectMthdTxt; - } - public void setConectMthdTxt(String conectMthdTxt) { - this.conectMthdTxt = conectMthdTxt; - } - public String getAgentCodeTxt() { - return agentCodeTxt; - } - public void setAgentCodeTxt(String agentCodeTxt) { - this.agentCodeTxt = agentCodeTxt; - } - public String getCurStateTxt() { - return curStateTxt; - } - public void setCurStateTxt(String curStateTxt) { - this.curStateTxt = curStateTxt; - } - public String getMsgTypeTxt() { - return msgTypeTxt; - } - public void setMsgTypeTxt(String msgTypeTxt) { - this.msgTypeTxt = msgTypeTxt; - } - public String getSentDateTxt() { - return sentDateTxt; - } - public void setSentDateTxt(String sentDateTxt) { - this.sentDateTxt = sentDateTxt; - } - public String getSearchCondition2() { - return searchCondition2; - } - public void setSearchCondition2(String searchCondition2) { - this.searchCondition2 = searchCondition2; - } - public String getDelFlag() { - return delFlag; - } - public void setDelFlag(String delFlag) { - this.delFlag = delFlag; - } - public String getDelFlagTxt() { - return delFlagTxt; - } - public void setDelFlagTxt(String delFlagTxt) { - this.delFlagTxt = delFlagTxt; - } - public String getSearchCondition3() { - return searchCondition3; - } - public void setSearchCondition3(String searchCondition3) { - this.searchCondition3 = searchCondition3; - } - public String getSearchCondition4() { - return searchCondition4; - } - public void setSearchCondition4(String searchCondition4) { - this.searchCondition4 = searchCondition4; - } - public String getMmsSubject() { - return mmsSubject; - } - public void setMmsSubject(String mmsSubject) { - this.mmsSubject = mmsSubject; - } - public String getFileCnt() { - return fileCnt; - } - public void setFileCnt(String fileCnt) { - this.fileCnt = fileCnt; - } - public String getFileType1() { - return fileType1; - } - public void setFileType1(String fileType1) { - this.fileType1 = fileType1; - } - public String getFileName1() { - return fileName1; - } - public void setFileName1(String fileName1) { - this.fileName1 = fileName1; - } - public String getFileType2() { - return fileType2; - } - public void setFileType2(String fileType2) { - this.fileType2 = fileType2; - } - public String getFileName2() { - return fileName2; - } - public void setFileName2(String fileName2) { - this.fileName2 = fileName2; - } - public String getFileType3() { - return fileType3; - } - public void setFileType3(String fileType3) { - this.fileType3 = fileType3; - } - public String getFileName3() { - return fileName3; - } - public void setFileName3(String fileName3) { - this.fileName3 = fileName3; - } - public String getSubject() { - return subject; - } - public void setSubject(String subject) { - this.subject = subject; - } - public String getMsgGroupId() { - return msgGroupId; - } - public void setMsgGroupId(String msgGroupId) { - this.msgGroupId = msgGroupId; - } - public String getMsgGroupCnt() { - return msgGroupCnt; - } - public void setMsgGroupCnt(String msgGroupCnt) { - this.msgGroupCnt = msgGroupCnt; - } - public String[] getCallToList() { - return callToList; - } - public void setCallToList(String[] strings) { - this.callToList = strings; - } - public String[] getImgFilePath() { - return imgFilePath; - } - public void setImgFilePath(String[] imgFilePath) { - this.imgFilePath = imgFilePath; - } - public String getNeoType() { - return neoType; - } - public void setNeoType(String neoType) { - this.neoType = neoType; - } - public int getMsgCnt() { - return msgCnt; - } - public void setMsgCnt(int msgCnt) { - this.msgCnt = msgCnt; - } - public String getSearchCondition5() { - return searchCondition5; - } - public void setSearchCondition5(String searchCondition5) { - this.searchCondition5 = searchCondition5; - } - public String getNtceBgnde() { - return ntceBgnde; - } - public void setNtceBgnde(String ntceBgnde) { - this.ntceBgnde = ntceBgnde; - } - public String getEachPrice() { - return eachPrice; - } - public void setEachPrice(String eachPrice) { - this.eachPrice = eachPrice; - } - public String getTotPrice() { - return totPrice; - } - public void setTotPrice(String totPrice) { - this.totPrice = totPrice; - } - public String getBeforeUrl() { - return beforeUrl; - } - public void setBeforeUrl(String beforeUrl) { - this.beforeUrl = beforeUrl; - } - public String getReserveYn() { - return reserveYn; - } - public void setReserveYn(String reserveYn) { - this.reserveYn = reserveYn; - } - public String getReserveCYn() { - return reserveCYn; - } - public void setReserveCYn(String reserveCYn) { - this.reserveCYn = reserveCYn; - } - public String getCancelDate() { - return cancelDate; - } - public void setCancelDate(String cancelDate) { - this.cancelDate = cancelDate; - } - public String[] getImgFileId() { - return imgFileId; - } - public void setImgFileId(String[] imgFileId) { - this.imgFileId = imgFileId; - } - public String[] getTemplateYn() { - return templateYn; - } - public void setTemplateYn(String[] templateYn) { - this.templateYn = templateYn; - } - public String getNtceEndde() { - return ntceEndde; - } - public void setNtceEndde(String ntceEndde) { - this.ntceEndde = ntceEndde; - } - public static long getSerialversionuid() { - return serialVersionUID; - } - public String getSendRate() { - return sendRate; - } - public void setSendRate(String sendRate) { - this.sendRate = sendRate; - } - public float getSendRateInfo() { - return sendRateInfo; - } - public void setSendRateInfo(float sendRateInfo) { - this.sendRateInfo = sendRateInfo; - } - public String getDivideChk() { - return divideChk; - } - public void setDivideChk(String divideChk) { - this.divideChk = divideChk; - } - public String getDivideCnt() { - return divideCnt; - } - public void setDivideCnt(String divideCnt) { - this.divideCnt = divideCnt; - } - public String getDivideTime() { - return divideTime; - } - public void setDivideTime(String divideTime) { - this.divideTime = divideTime; - } - public String getBefCash() { - return befCash; - } - public void setBefCash(String befCash) { - this.befCash = befCash; - } - public String getRecommId() { - return recommId; - } - public void setRecommId(String recommId) { - this.recommId = recommId; - } - public String getBefPoint() { - return befPoint; - } - public void setBefPoint(String befPoint) { - this.befPoint = befPoint; - } - public String[] getNameList() { - return nameList; - } - public void setNameList(String[] nameList) { - this.nameList = nameList; - } - public String[] getRep1List() { - return rep1List; - } - public void setRep1List(String[] rep1List) { - this.rep1List = rep1List; - } - public String[] getRep2List() { - return rep2List; - } - public void setRep2List(String[] rep2List) { - this.rep2List = rep2List; - } - public String[] getRep3List() { - return rep3List; - } - public void setRep3List(String[] rep3List) { - this.rep3List = rep3List; - } - public String[] getRep4List() { - return rep4List; - } - public void setRep4List(String[] rep4List) { - this.rep4List = rep4List; - } - public String getThisPoint() { - return thisPoint; - } - public void setThisPoint(String thisPoint) { - this.thisPoint = thisPoint; - } - public String getEndDate() { - return endDate; - } - public void setEndDate(String endDate) { - this.endDate = endDate; - } - public String getStartDate() { - return startDate; - } - public void setStartDate(String startDate) { - this.startDate = startDate; - } - public int getPhoneNumberCnt() { - return phoneNumberCnt; - } - public void setPhoneNumberCnt(int phoneNumberCnt) { - this.phoneNumberCnt = phoneNumberCnt; - } - public String getPhmAuthType() { - return phmAuthType; - } - public void setPhmAuthType(String phmAuthType) { - this.phmAuthType = phmAuthType; - } - public String getRefundYn() { - return refundYn; - } - public void setRefundYn(String refundYn) { - this.refundYn = refundYn; - } - public String getFilePath1() { - return filePath1; - } - public void setFilePath1(String filePath1) { - this.filePath1 = filePath1; - } - public String getFilePath2() { - return filePath2; - } - public void setFilePath2(String filePath2) { - this.filePath2 = filePath2; - } - public String getFilePath3() { - return filePath3; - } - public void setFilePath3(String filePath3) { - this.filePath3 = filePath3; - } - public String getResultCodeTxt() { - return resultCodeTxt; - } - public void setResultCodeTxt(String resultCodeTxt) { - this.resultCodeTxt = resultCodeTxt; - } - public String getTxtReplYn() { - return txtReplYn; - } - public void setTxtReplYn(String txtReplYn) { - this.txtReplYn = txtReplYn; - } - public String getsPrice() { - return sPrice; - } - public void setsPrice(String sPrice) { - this.sPrice = sPrice; - } - public String getmPrice() { - return mPrice; - } - public void setmPrice(String mPrice) { - this.mPrice = mPrice; - } - public String getpPrice() { - return pPrice; - } - public void setpPrice(String pPrice) { - this.pPrice = pPrice; - } - public String getP2Price() { - return p2Price; - } - public void setP2Price(String p2Price) { - this.p2Price = p2Price; - } - public String getP3Price() { - return p3Price; - } - public void setP3Price(String p3Price) { - this.p3Price = p3Price; - } - public String getShortMsgCnt() { - return shortMsgCnt; - } - public void setShortMsgCnt(String shortMsgCnt) { - this.shortMsgCnt = shortMsgCnt; - } - public String getLongMsgCnt() { - return longMsgCnt; - } - public void setLongMsgCnt(String longMsgCnt) { - this.longMsgCnt = longMsgCnt; - } - public String getAtchFileId1() { - return atchFileId1; - } - public void setAtchFileId1(String atchFileId1) { - this.atchFileId1 = atchFileId1; - } - public String getAtchFileId2() { - return atchFileId2; - } - public void setAtchFileId2(String atchFileId2) { - this.atchFileId2 = atchFileId2; - } - public String getAtchFileId3() { - return atchFileId3; - } - public void setAtchFileId3(String atchFileId3) { - this.atchFileId3 = atchFileId3; - } - public String getAtchFileSn1() { - return atchFileSn1; - } - public void setAtchFileSn1(String atchFileSn1) { - this.atchFileSn1 = atchFileSn1; - } - public String getAtchFileSn2() { - return atchFileSn2; - } - public void setAtchFileSn2(String atchFileSn2) { - this.atchFileSn2 = atchFileSn2; - } - public String getAtchFileSn3() { - return atchFileSn3; - } - public void setAtchFileSn3(String atchFileSn3) { - this.atchFileSn3 = atchFileSn3; - } - - public String getMsgTypeName() { - return msgTypeName; - } - public void setMsgTypeName(String msgTypeName) { - this.msgTypeName = msgTypeName; - } - public int getSendCount() { - return sendCount; - } - public void setSendCount(int sendCount) { - this.sendCount = sendCount; - } - public double getSupplyPrice() { - return supplyPrice; - } - public void setSupplyPrice(double supplyPrice) { - this.supplyPrice = supplyPrice; - } - public double getVatPrice() { - return vatPrice; - } - public void setVatPrice(double vatPrice) { - this.vatPrice = vatPrice; - } - public double getTotalPrice() { - return totalPrice; - } - public void setTotalPrice(double totalPrice) { - this.totalPrice = totalPrice; - } - public String getDetailType() { - return detailType; - } - public void setDetailType(String detailType) { - this.detailType = detailType; - } - public String getMsgGroupSCnt() { - return msgGroupSCnt; - } - public void setMsgGroupSCnt(String msgGroupSCnt) { - this.msgGroupSCnt = msgGroupSCnt; - } - public String getMsgGroupFWCnt() { - return MsgGroupFWCnt; - } - public void setMsgGroupFWCnt(String msgGroupFWCnt) { - MsgGroupFWCnt = msgGroupFWCnt; - } - public String getTotSPrice() { - return totSPrice; - } - public void setTotSPrice(String totSPrice) { - this.totSPrice = totSPrice; - } - public String getTotFWPrice() { - return totFWPrice; - } - public void setTotFWPrice(String totFWPrice) { - this.totFWPrice = totFWPrice; - } - public String getMsgGroupSCntSum() { - return msgGroupSCntSum; - } - public void setMsgGroupSCntSum(String msgGroupSCntSum) { - this.msgGroupSCntSum = msgGroupSCntSum; - } - public String getMsgGroupFWCntSum() { - return MsgGroupFWCntSum; - } - public void setMsgGroupFWCntSum(String msgGroupFWCntSum) { - MsgGroupFWCntSum = msgGroupFWCntSum; - } - public String getTotSPriceSum() { - return totSPriceSum; - } - public void setTotSPriceSum(String totSPriceSum) { - this.totSPriceSum = totSPriceSum; - } - public String getTotFWPriceSum() { - return totFWPriceSum; - } - public void setTotFWPriceSum(String totFWPriceSum) { - this.totFWPriceSum = totFWPriceSum; - } - public String getSmiId() { - return smiId; - } - public void setSmiId(String smiId) { - this.smiId = smiId; - } - public List getDividDay() { - return dividDay; - } - public void setDividDay(List dividDay) { - this.dividDay = dividDay; - } - public String getUserNm() { - return userNm; - } - public void setUserNm(String userNm) { - this.userNm = userNm; - } - public String getMbtlnum() { - return mbtlnum; - } - public void setMbtlnum(String mbtlnum) { - this.mbtlnum = mbtlnum; - } - public String getEmailAdres() { - return emailAdres; - } - public void setEmailAdres(String emailAdres) { - this.emailAdres = emailAdres; - } - public String getAuthorCode() { - return authorCode; - } - public void setAuthorCode(String authorCode) { - this.authorCode = authorCode; - } - public String getResultLogUpdtPnttm() { - return resultLogUpdtPnttm; - } - public void setResultLogUpdtPnttm(String resultLogUpdtPnttm) { - this.resultLogUpdtPnttm = resultLogUpdtPnttm; - } - public String getRepAgent() { - return repAgent; - } - public void setRepAgent(String repAgent) { - this.repAgent = repAgent; - } - public String getEventYn() { - return eventYn; - } - public void setEventYn(String eventYn) { - this.eventYn = eventYn; - } - - public String getSpamKeyword() { - return spamKeyword; - } - public void setSpamKeyword(String spamKeyword) { - this.spamKeyword = spamKeyword; - } - public String getSpamMsgGroupId() { - return spamMsgGroupId; - } - public void setSpamMsgGroupId(String spamMsgGroupId) { - this.spamMsgGroupId = spamMsgGroupId; - } - public String getSpamStatus() { - return spamStatus; - } - public void setSpamStatus(String spamStatus) { - this.spamStatus = spamStatus; - } - - public String getSmishingYn() { - return smishingYn; - } - public void setSmishingYn(String smishingYn) { - this.smishingYn = smishingYn; - } - public int getTotalCallCnt() { - return totalCallCnt; - } - public void setTotalCallCnt(int totalCallCnt) { - this.totalCallCnt = totalCallCnt; - } - public String getDelayYn() { - return delayYn; - } - public void setDelayYn(String delayYn) { - this.delayYn = delayYn; - } - public String getDelayCompleteYn() { - return delayCompleteYn; - } - public void setDelayCompleteYn(String delayCompleteYn) { - this.delayCompleteYn = delayCompleteYn; - } - public String getVipYn() { - return vipYn; - } - public void setVipYn(String vipYn) { - this.vipYn = vipYn; - } - public String getResultCode() { - return resultCode; - } - public void setResultCode(String resultCode) { - this.resultCode = resultCode; - } - public String getResultCode2() { - return resultCode2; - } - public void setResultCode2(String resultCode2) { - this.resultCode2 = resultCode2; - } - public String getRegistPnttm() { - return registPnttm; - } - public void setRegistPnttm(String registPnttm) { - this.registPnttm = registPnttm; - } - public String getBizKakaoResendData() { - return bizKakaoResendData; - } - public void setBizKakaoResendData(String bizKakaoResendData) { - this.bizKakaoResendData = bizKakaoResendData; - } - public String getBizKakaoTitle() { - return bizKakaoTitle; - } - public void setBizKakaoTitle(String bizKakaoTitle) { - this.bizKakaoTitle = bizKakaoTitle; - } - public String getSmsTxtTrans() { - return smsTxtTrans; - } - public void setSmsTxtTrans(String smsTxtTrans) { - this.smsTxtTrans = smsTxtTrans; - } - public String getBizKakaoTitle01() { - return bizKakaoTitle01; - } - public void setBizKakaoTitle01(String bizKakaoTitle01) { - this.bizKakaoTitle01 = bizKakaoTitle01; - } - public String getBizKakaoTitle02() { - return bizKakaoTitle02; - } - public void setBizKakaoTitle02(String bizKakaoTitle02) { - this.bizKakaoTitle02 = bizKakaoTitle02; - } - public String getBizKakaoResendOrgnlTxt() { - return bizKakaoResendOrgnlTxt; - } - public void setBizKakaoResendOrgnlTxt(String bizKakaoResendOrgnlTxt) { - this.bizKakaoResendOrgnlTxt = bizKakaoResendOrgnlTxt; - } - public String getBizKakaoResendYn() { - return bizKakaoResendYn; - } - public void setBizKakaoResendYn(String bizKakaoResendYn) { - this.bizKakaoResendYn = bizKakaoResendYn; - } - public String getBizKakaoResendType() { - return bizKakaoResendType; - } - public void setBizKakaoResendType(String bizKakaoResendType) { - this.bizKakaoResendType = bizKakaoResendType; - } - public String getBizKakaoJsonFile() { - return bizKakaoJsonFile; - } - public void setBizKakaoJsonFile(String bizKakaoJsonFile) { - this.bizKakaoJsonFile = bizKakaoJsonFile; - } - public String getYellowId() { - return yellowId; - } - public void setYellowId(String yellowId) { - this.yellowId = yellowId; - } - public String getBizKakaoResendTypeCnt() { - return bizKakaoResendTypeCnt; - } - public void setBizKakaoResendTypeCnt(String bizKakaoResendTypeCnt) { - this.bizKakaoResendTypeCnt = bizKakaoResendTypeCnt; - } diff --git a/src/main/java/itn/let/kakao/admin/kakaoAt/web/MjonKakaoATController.java b/src/main/java/itn/let/kakao/admin/kakaoAt/web/MjonKakaoATController.java index b4513d7a..ef3278b4 100644 --- a/src/main/java/itn/let/kakao/admin/kakaoAt/web/MjonKakaoATController.java +++ b/src/main/java/itn/let/kakao/admin/kakaoAt/web/MjonKakaoATController.java @@ -796,9 +796,16 @@ public class MjonKakaoATController { String lastUpdtPnttm = resultChannelList.get(i).getLastUpdtPnttm(); kakaoProfileVO.setSenderKey(senderKey); kakaoProfileVO.setProfileId(profileId); - - KakaoReturnVO tmpProfileVO = kakaoApiProfile.kakaoApiProfileList(kakaoProfileVO); - + KakaoReturnVO tmpProfileVO = null; +// try { +// +// tmpProfileVO = kakaoApiProfile.kakaoApiProfileList(kakaoProfileVO); +// } catch (Exception e) { +// e.printStackTrace(); +// // TODO: handle exception +// } + + tmpProfileVO = kakaoApiProfile.kakaoApiProfileList(kakaoProfileVO); ChannelIDVO returnChannelVO = new ChannelIDVO(); returnChannelVO.setSenderKey(tmpProfileVO.getSenderKey()); diff --git a/src/main/java/itn/let/kakao/kakaoComm/BizKakaoPriceVO.java b/src/main/java/itn/let/kakao/kakaoComm/BizKakaoPriceVO.java new file mode 100644 index 00000000..3eebffc5 --- /dev/null +++ b/src/main/java/itn/let/kakao/kakaoComm/BizKakaoPriceVO.java @@ -0,0 +1,34 @@ +package itn.let.kakao.kakaoComm; + +import java.math.BigDecimal; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +/** + * @ BIZ_KAKAO_PRICE 테이블 관련 + */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class BizKakaoPriceVO { + + private Long bizKakaoPriceId; + + private String bizKakaoAtPrice; // 알림톡 단가 + private String bizKakaoFtPrice; // 친구톡 단가 + private String bizKakaoFtImgPrice; // 친구톡 이미지 단가 + private String bizKakaoFtWideImgPrice; // 친구톡 와이드 이미지 단가 + private String bizSmsPrice; // SMS 단가 + private String bizMmsPrice; // MMS 단가 + + private String msgGroupId; // 메시지 그룹 ID + + + // getters and setters 생략 +} \ No newline at end of file diff --git a/src/main/java/itn/let/kakao/kakaoComm/KakaoSendAdvcVO.java b/src/main/java/itn/let/kakao/kakaoComm/KakaoSendAdvcVO.java index 480cf85a..57c59184 100644 --- a/src/main/java/itn/let/kakao/kakaoComm/KakaoSendAdvcVO.java +++ b/src/main/java/itn/let/kakao/kakaoComm/KakaoSendAdvcVO.java @@ -45,7 +45,13 @@ public class KakaoSendAdvcVO implements Serializable { private String subMsgType; // 대체문자 타입 private String reqDate; // 예약일시 + private String msgKind; // 예약일시 + private String jsonStr; // jsonStr + + + + private String adFlag; //친구톡 광고성 정보 사용 유무(Y:사용 , N:미사용) // ===== // ===== @@ -53,15 +59,22 @@ public class KakaoSendAdvcVO implements Serializable { private String eachPrice; // sms 단가 private String smsPrice; // sms 단가 private String mmsPrice; // mms 단가 + private String picturePrice; // mms 단가 private String totPrice; // mms 단가 private String befCash; // mms 단가 private String befPoint; // mms 단가 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; + @@ -83,7 +96,7 @@ public class KakaoSendAdvcVO implements Serializable { "\n , msgType=[" + msgType + "]" + "\n , templateContent=[" + templateContent + "]" + "\n , templateTitle=[" + templateTitle + "]" + - "\n , buttonList=[" + buttonList.toString() + "]" + + "\n , buttonList=[" + (buttonList != null ? buttonList.toString() : "") + "]" + "\n , subMsgSendYn=[" + subMsgSendYn + "]" + "\n , subMsgTxt=[" + subMsgTxt + "]" + "\n , subMsgType=[" + subMsgType + "]" + @@ -103,6 +116,8 @@ public class KakaoSendAdvcVO implements Serializable { "\n , atDelayYn=[" + atDelayYn + "]" + "\n , bizKakaoResendOrgnlTxt=[" + bizKakaoResendOrgnlTxt + "]" + "\n , bizKakaoResendType=[" + bizKakaoResendType + "]" + + "\n , filePath1=[" + filePath1 + "]" + + "\n , bizKakaoImageType=[" + bizKakaoImageType + "]" + "\n ]"; } diff --git a/src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java b/src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java index bbe859e2..72b38370 100644 --- a/src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java +++ b/src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java @@ -1,12 +1,17 @@ package itn.let.kakao.kakaoComm; +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -19,17 +24,23 @@ import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import egovframework.rte.fdl.idgnr.EgovIdGnrService; +import itn.com.cmm.MjonFTSendVO; +import itn.com.cmm.MjonMsgSendVO; +import itn.com.cmm.util.MsgSendUtils; import itn.com.cmm.util.StringUtil; import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiJsonSave; import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiTemplate; +import itn.let.kakao.user.kakaoAt.service.impl.KakaoAlimTalkDAO; 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.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 @@ -38,9 +49,15 @@ public class KakaoSendUtil { @Autowired KakaoApiJsonSave kakaoApiJsonSave; + + @Resource(name="kakaoAlimTalkDAO") + private KakaoAlimTalkDAO kakaoAlimTalkDAO; @Resource(name = "MjonMsgDataService") private MjonMsgDataService mjonMsgDataService; + + @Resource(name = "mjonMsgDAO") + private MjonMsgDAO mjonMsgDAO; @Autowired KakaoApiTemplate kakaoApiTemplate; @@ -51,6 +68,7 @@ public class KakaoSendUtil { @Autowired private MjonCommon mjonCommon; + // 클래스 수준에서 정적 Pattern 정의 (성능 최적화) private static final Pattern REPLACEMENT_PATTERN = Pattern.compile("#\\{[^}]+\\}"); @@ -138,7 +156,7 @@ public class KakaoSendUtil { log.info(""); /** @공통 기본값 */ - KakaoSendAdvcVO sendVO = createSendVO(kakaoVO); + KakaoSendAdvcVO sendVO = createATSendVO(kakaoVO); String msgId = idList.get(i); sendVO.setMsgId(msgId); @@ -273,19 +291,464 @@ public class KakaoSendUtil { return kakaoSendAdvcListVO; } - private Calendar setupBaseDate(KakaoVO kakaoVO, boolean isNotified) throws ParseException { + /** + * @methodName : populateSendListsFT + * @author : 이호영 + * @date : 2025. 4. 18. + * @description : + * @return : List + * @param kakaoVO + * @param isHolidayNotified + * @param statusResponse + * @return + * @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(); - // ReqDate가 비어 있으면 현재 시간으로 설정, 그렇지 않으면 ReqDate로 설정 - // 화면에서 예약문자면 예약시간을 regDate로 설정한다. - Date baseDate; - if (StringUtils.isEmpty(kakaoVO.getReqDate())) { - kakaoVO.setReqDate(DATE_FORMATTER.format(now)); // ReqDate에 현재 시간 설정 - baseDate = now; - } else { - baseDate = DATE_FORMATTER.parse(kakaoVO.getReqDate()); // ReqDate를 baseDate로 설정 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + + String atSmishingYn = userManageVO.getAtSmishingYn(); + String exceptSpamYn = userManageVO.getExceptSpamYn(); + + + List kakaoSendAdvcListVO = new ArrayList<>(); + Calendar calendar = setupBaseDateFT(kakaoVO); + + + + // 친구톡 내용 + String templateContent = kakaoVO.getTemplateContent(); + // 실패 대체 문자 + String subMsgTxt = kakaoVO.getSubMsgTxt(); + log.info(" + StringUtils.isNotEmpty(subMsgTxt) :: [{}]", StringUtils.isNotEmpty(subMsgTxt)); + if(StringUtils.isNotEmpty(subMsgTxt)) { + kakaoVO.setSubMsgSendYn("Y"); + + // 광고문자면 처리 - 광고 Y + if ("Y".equals(kakaoVO.getAdFlag())) { + subMsgTxt = "(광고)" + subMsgTxt + "\n" + "무료거부 0808800858"; + } + } + + + // 사용자 개인 단가 정보 불러오기 + MberManageVO mberManageVO = mjonMsgDataService.selectMberManageInfo(kakaoVO.getUserId()); + // 시스템 기본 단가 정보 불러오기 + JoinSettingVO sysJoinSetVO = mjonMsgDataService.selectJoinSettingInfo(); + + + // 치환 문구가 있는지 확인 + Boolean replaceYN = MsgSendUtils.getReplaceYN(templateContent); + Boolean replaceSubYN = MsgSendUtils.getReplaceYN(subMsgTxt); + + + /** @MSGID KEY값 */ + List idList = mjonCommon.getNextCustomMsgCId(kakaoVO.getMjonFTSendVOList().size()); + + + Map> placeholders = new HashMap<>(); + placeholders.put("[*이름*]", MjonFTSendVO::getName); + placeholders.put("[*1*]", MjonFTSendVO::getRep1); + placeholders.put("[*2*]", MjonFTSendVO::getRep2); + placeholders.put("[*3*]", MjonFTSendVO::getRep3); + placeholders.put("[*4*]", MjonFTSendVO::getRep4); + + String imageType = kakaoVO.getImageType(); + // 개인단가 + Float kakaoMemberFtPrice = + imageType == null ? mberManageVO.getKakaoFtPrice() : + "I".equals(imageType) ? mberManageVO.getKakaoFtImgPrice() : + "W".equals(imageType) ? mberManageVO.getKakaoFtWideImgPrice() : + mberManageVO.getKakaoFtPrice(); + + // 시스템단가 + Float kakaoSysJoinFtPrice = + imageType == null ? sysJoinSetVO.getKakaoFtPrice() : + "I".equals(imageType) ? sysJoinSetVO.getKakaoFtImgPrice() : + "W".equals(imageType) ? sysJoinSetVO.getKakaoFtWideImgPrice() : + sysJoinSetVO.getKakaoFtPrice(); + + Float kakaoFtPrice = + getValidPrice(kakaoMemberFtPrice, kakaoSysJoinFtPrice); + + // 대체문자가 있을경우 사용 + float shortPrice = getValidPrice(mberManageVO.getShortPrice(), sysJoinSetVO.getShortPrice()); + float longPrice = getValidPrice(mberManageVO.getLongPrice(), sysJoinSetVO.getLongPrice()); + float picturePrice = getValidPrice(mberManageVO.getPicturePrice(), sysJoinSetVO.getPicturePrice()); + + 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()); + } + + + + /** @jsonStr 필요유무 */ + 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(); + + for (int i = 0; i < mjonFTSendVOList.size(); i++) { + MjonFTSendVO mjonFTSendVO = mjonFTSendVOList.get(i); + + KakaoSendAdvcVO sendVO = createFTSendVO(kakaoVO, calendar); + // 공통 가격 설정 + sendVO.setSmsPrice(Float.toString(shortPrice)); + sendVO.setMmsPrice(Float.toString(longPrice)); + sendVO.setPicturePrice(Float.toString(picturePrice)); + + sendVO.setCallTo(mjonFTSendVO.getPhone()); + sendVO.setMsgId(idList.get(i)); + + + // 친구톡 문자 + String templateContentTemp = templateContent; + // 치환 문자면 + if(replaceYN) { + + // 각 치환 구문을 확인하고 치환할 값이 없으면 오류 반환 + for (Map.Entry> entry : placeholders.entrySet()) { + String placeholder = entry.getKey(); + String value = entry.getValue().apply(mjonFTSendVO); + if (templateContentTemp.contains(placeholder)) { + if (StringUtils.isEmpty(value)) { + statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "치환 문구중 " + placeholder + " 데이터가 없습니다."); + return null; + } + templateContentTemp = templateContentTemp.replace(placeholder, value); + } + } + } + sendVO.setTemplateContent(templateContentTemp); + + // 실패 대체 문자 + String subMsgTxtTemp = null; + if(StringUtils.isNotEmpty(subMsgTxt)) { + subMsgTxtTemp = subMsgTxt; + + if(replaceSubYN) { + // 각 치환 구문을 확인하고 치환할 값이 없으면 오류 반환 + for (Map.Entry> entry : placeholders.entrySet()) { + String placeholder = entry.getKey(); + String value = entry.getValue().apply(mjonFTSendVO); + if (subMsgTxtTemp.contains(placeholder)) { + if (StringUtils.isEmpty(value)) { + statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "치환 문구중 " + placeholder + " 데이터가 없습니다."); + return null; + } + subMsgTxtTemp = subMsgTxtTemp.replace(placeholder, value); + } + } + } + } + sendVO.setSubMsgTxt(subMsgTxtTemp); + + + //대체문자가 있으면 + // Step 1-4: 실패 대체 문자 치환데이터 설정 + if(StringUtils.isNotEmpty(subMsgTxtTemp)) { // 대체문자가 있나? + + // 최적화된 계산 로직 + Map pricingResult; + + if (replaceSubYN) { + // 치환데이터 있음 → 매번 새로 계산 + pricingResult = calculateSubMsgPricing(subMsgTxtTemp, imgFilePath, + shortPrice, longPrice, picturePrice, kakaoFtPrice); + + // INVALID 체크 + String resultSendType = (String) pricingResult.get("sendType"); + if ("INVALID".equals(resultSendType)) { + statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "전송 문자 길이를 초과하였습니다."); + return kakaoSendAdvcListVO; + } + } else { + // 치환데이터 없음 → 미리 계산된 결과 재사용 + pricingResult = sharedPricingResult; + } + + + // 결과 적용 + applyPricingResult(sendVO, pricingResult); + + + }else { + // 대체문자가 없으면 카카오톡 단가 그대로 사용 + 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)) { + // 치환 데이터가 없고 아직 생성되지 않았으면 한 번만 생성 + sharedJsonStr = kakaoApiJsonSave.kakaoApiFTJsonSave_advc(kakaoVO); + sendVO.setJsonStr(sharedJsonStr); + } + sendVO.setBizJsonName(idList.get(0)); + + } + + 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 { + + + // // 내문자저장함에 저장 후 문자를 발송하는 경우 문자 타입이 숫자가 아닌 문자로 넘어와서 변경 처리함 + // if ("P".equals(msgType) || "L".equals(msgType)) { + // msgType = "6"; + // } else if ("S".equals(msgType)) { + // msgType = "4"; + // } + + int smsTxtByte = MjonCommon.getSmsTxtBytes(p_smsTxt); + String msgType = SHORT_MSG_TYPE; + + // 1. 2000 Byte 초과는 에러 처리 + if (smsTxtByte > 2000) { + return "INVALID"; + } + + // 2. 첨부파일 여부 확인 (첨부파일이 있으면 장문으로 설정) + if (StringUtils.isNotEmpty(sendVO.getFilePath1())) { + msgType = LONG_MSG_TYPE; + } + // 3. 문자 길이에 따라 메시지 타입 설정 (90 Byte 초과는 장문) + else if (smsTxtByte > 90) { + msgType = LONG_MSG_TYPE; + } + return msgType; + } + + + 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); + // 시간 성정 Calendar calendar = Calendar.getInstance(); calendar.setTime(baseDate); // calendar에 baseDate 설정 @@ -293,12 +756,37 @@ public class KakaoSendUtil { // 지연 여부 처리 // 알림톡 스미싱의심 + 공휴일알림 조건이 맞으면 30분 delay if ( "Y".equalsIgnoreCase(kakaoVO.getAtSmishingYn()) - && isNotified) { + && isHolidayNotified) { calendar.add(Calendar.MINUTE, 30); // 모든 시간을 30분 뒤로 미룸 } return calendar; } + public Date resolveBaseDate(KakaoVO kakaoVO) throws ParseException { + Date now = new Date(); + + if (StringUtils.isEmpty(kakaoVO.getReqDate())) { + kakaoVO.setReqDate(DATE_FORMATTER.format(now)); + return now; + } + return DATE_FORMATTER.parse(kakaoVO.getReqDate()); + } + + // 2. 친구톡 발송 제한 시간인지 확인 + public boolean isRestrictedFriendTalkTime(Date baseDate) { + Calendar cal = Calendar.getInstance(); + cal.setTime(baseDate); + + int hour = cal.get(Calendar.HOUR_OF_DAY); + int minute = cal.get(Calendar.MINUTE); + + // 20:50 이후 ~ 익일 08:00 이전은 제한 + if ((hour == 20 && minute >= 50) || hour > 20 || hour < 8) { + return true; + } + return false; + } + /** * @methodName : createSendVO * @author : 이호영 @@ -309,14 +797,45 @@ public class KakaoSendUtil { * @return * */ - private KakaoSendAdvcVO createSendVO(KakaoVO kakaoVO) { + private KakaoSendAdvcVO createATSendVO(KakaoVO kakaoVO) { KakaoSendAdvcVO sendVO = new KakaoSendAdvcVO(); sendVO.setMsgType("8"); + sendVO.setAgentCode("04"); sendVO.setSenderKey(kakaoVO.getSenderKey()); sendVO.setTemplateCode(kakaoVO.getTemplateCode()); sendVO.setUserId(kakaoVO.getUserId()); sendVO.setCallFrom(kakaoVO.getCallFrom()); + return sendVO; + } + + + /** + * @methodName : createFTSendVO + * @author : 이호영 + * @date : 2025. 4. 23. + * @description : + * @return : KakaoSendAdvcVO + * @param kakaoVO + * @return + * + */ + private KakaoSendAdvcVO createFTSendVO(KakaoVO kakaoVO, Calendar calendar) { + KakaoSendAdvcVO sendVO = new KakaoSendAdvcVO(); + + sendVO.setMsgType("9"); // 알림톡 8 친구톡 9 sendVO.setAgentCode("04"); + // 발송시간 : 친구톡은 분할 발송이 없어 처음 vo 생성 시 입력 + sendVO.setReqDate(DATE_FORMATTER.format(calendar.getTime())); + + sendVO.setSenderKey(kakaoVO.getSenderKey()); + sendVO.setTemplateCode(kakaoVO.getTemplateCode()); + sendVO.setUserId(kakaoVO.getUserId()); + sendVO.setCallFrom(kakaoVO.getCallFrom()); + sendVO.setSubMsgSendYn(kakaoVO.getSubMsgSendYn()); + + sendVO.setAdFlag(kakaoVO.getAdFlag()); + + return sendVO; } @@ -378,7 +897,7 @@ public class KakaoSendUtil { } - public Float getValidPrice(Float personalPrice, Float defaultPrice) { + public static Float getValidPrice(Float personalPrice, Float defaultPrice) { return (personalPrice != null && personalPrice > 0) ? personalPrice : defaultPrice; } @@ -692,6 +1211,10 @@ public class KakaoSendUtil { //카카오 친구톡 개인 단가가 없는 경우 시스템 단가로 if(mberManageVO.getKakaoFtPrice() == 0.0f) mberManageVO.setKakaoFtPrice(sysJoinSetVO.getKakaoFtPrice()); + if(mberManageVO.getKakaoFtImgPrice() == 0.0f) + mberManageVO.setKakaoFtImgPrice(sysJoinSetVO.getKakaoFtImgPrice()); + if(mberManageVO.getKakaoFtWideImgPrice() == 0.0f) + mberManageVO.setKakaoFtWideImgPrice(sysJoinSetVO.getKakaoFtWideImgPrice()); // SMS 인경우 @@ -703,7 +1226,9 @@ public class KakaoSendUtil { // 사용자 개인 단가가 없으면 시스템 단가로 if(mberManageVO.getLongPrice() == 0.0f) mberManageVO.setLongPrice(sysJoinSetVO.getLongPrice()); - + + if(mberManageVO.getPicturePrice() == 0.0f) + mberManageVO.setPicturePrice(sysJoinSetVO.getPicturePrice()); return mberManageVO; } @@ -1202,4 +1727,175 @@ public class KakaoSendUtil { statusResponse.setMessage(msg); } + + + // 보유 금액이 충분한지 확인하는 메서드 + public boolean isCashSufficient(String userId, List kakaoSendAdvcListVO) throws Exception { + + + String userMoney = priceAndPoint.getBefCash(userId); + // 쉼표 제거 + userMoney = userMoney.replace(",", ""); + + + // 사용자 보유 금액 BigDecimal 변환 (HALF_EVEN 적용) + BigDecimal befCash = new BigDecimal(userMoney).setScale(2, RoundingMode.HALF_EVEN); + log.info(" + userMoney :: [{}]", userMoney); + log.info(" + befCash :: [{}]", befCash); + + + // 총 메시지 금액 계산 (HALF_EVEN 적용) + BigDecimal totalEachPrice = kakaoSendAdvcListVO.stream() + .map(msg -> new BigDecimal(String.valueOf(msg.getEachPrice()))) // 변환 오류 방지 + .reduce(BigDecimal.ZERO, BigDecimal::add) + .setScale(2, RoundingMode.HALF_EVEN); // 일관성 유지 + + log.info(" + totalEachPrice :: [{}]", totalEachPrice); + // 비교 수행 + return befCash.compareTo(totalEachPrice) >= 0; + } + + + + /** + * @methodName : insertKakaoAtDataJsonInfo_advc + * @author : 이호영 + * @date : 2025. 4. 24. + * @description : INSERT INTO BIZ_ATTACHMENTS + * @return : void + * @param kakaoSendAdvcListVO + * + */ + public void insertKakaoAtDataJsonInfo_advc(List kakaoSendAdvcListVO) { + + List jsonInfoData = new ArrayList<>(kakaoSendAdvcListVO); + jsonInfoData.removeIf(t -> StringUtils.isBlank(t.getJsonStr())); + log.info(" + jsonInfoData Insert :: [{}]", jsonInfoData.size()); + if(jsonInfoData.size() > 0) { + kakaoAlimTalkDAO.insertKakaoAtDataJsonInfo_advc(jsonInfoData); + } + + } + + + + /** + * @methodName : insertKakaoData_advc + * @author : 이호영 + * @date : 2025. 3. 20. + * @description : 카카오 batch 발송 => mj_msg_data + * @return : int + * @param kakaoSendAdvcVOList + * @param parentLoopCount + * @param isJsonNotEmpty + * @param isJsonNameAllSame + * @return + * + */ + public int insertKakaoData_advc(List kakaoSendAdvcVOList) { + + + // 시작 시간 측정 + long totalStartTime = System.currentTimeMillis(); + + int totalSize = kakaoSendAdvcVOList.size(); // 총 데이터 개수 + // Batch 크기 설정 (고정값) +// int batchSize = 10000; 465 + int batchSize = 50000; // 9분 18초 + + log.info("총 데이터 개수 :: [{}] ", totalSize); + log.info("설정된 Batch 크기 :: [{}] ", batchSize); + + // 총 insert 카운트 + int instCnt = 0; + int batchCount = 0; + + // 각 배치별 실행 시간 기록 + List batchExecutionTimes = new ArrayList<>(); + + + // 첫 번째 배치에서만 삽입했는지 추적하는 플래그 + for (int i = 0; i < totalSize; i += batchSize) { + // Batch 시작 시간 측정 + long batchStartTime = System.currentTimeMillis(); + + // Batch 리스트 생성 + List batchList = kakaoSendAdvcVOList.subList(i, Math.min(i + batchSize, totalSize)); + System.out.println("Batch 시작 인덱스: " + i); + + // mj_msg_data 테이블 insert + int insertedCount = kakaoAlimTalkDAO.insertKakaoAtDataInfo_advc(batchList); + + /** @kakaoSendUtil.populateSendLists + * 하단에서 + * getJsonStr 데이터 처리 후 활용 + * */ + instCnt += insertedCount; + + // Batch 종료 시간 측정 및 실행 시간 계산 + long batchEndTime = System.currentTimeMillis(); + double batchExecutionTimeInSeconds = (batchEndTime - batchStartTime) / 1000.0; + + // 실행 시간 기록 + batchExecutionTimes.add(batchExecutionTimeInSeconds); + batchCount++; + } + + // 종료 시간 측정 + long totalEndTime = System.currentTimeMillis(); + + // 총 실행 시간 계산 (밀리초 -> 초로 변환) + double totalExecutionTimeInSeconds = (totalEndTime - totalStartTime) / 1000.0; + + // 실행 시간 출력 + log.info("총 배치 실행 횟수 :: [{}] ", batchCount); + log.info("batchSize :: [{}] ", batchSize); + log.info("총 실행 시간 :: [{}] ", totalExecutionTimeInSeconds + "초"); + log.info("총 삽입 건수 :: [{}] ", instCnt); + + // 각 배치별 실행 시간 출력 + for (int k = 0; k < batchExecutionTimes.size(); k++) { + System.out.println("배치 " + (k + 1) + " 실행 시간 :: " + batchExecutionTimes.get(k) + "초"); + } + + return instCnt; + + } + + + + + + + public void insertKakaoGroupDataTb_advc(int instCnt, KakaoVO kakaoVO, KakaoSendAdvcVO sendVO) throws Exception { + // TODO Auto-generated method stub + +// log.info(" + insertKakaoGroupDataTb_advc kakaoVO :: \n[{}]", kakaoVO.toString());; +// log.info(" + insertKakaoGroupDataTb_advc kakaoSendAdvcVOList :: \n[{}]", sendVO.toString()); + + + + sendVO.setTemplateContent(kakaoVO.getTemplateContent()); + sendVO.setMsgGroupCnt(Integer.toString(instCnt)); + sendVO.setReserveYn(kakaoVO.getReserveYn()); + sendVO.setBefCash(priceAndPoint.getBefCash(sendVO.getUserId())); + sendVO.setBefPoint(priceAndPoint.getBefPoint(sendVO.getUserId())); + sendVO.setAdFlag(kakaoVO.getAdFlag()); + + Float eachPrice = Float.parseFloat(sendVO.getEachPrice()); + + Float totPrice = eachPrice * instCnt; + sendVO.setTotPrice(String.format("%.1f", totPrice)); + + sendVO.setAtDelayYn(kakaoVO.getAtDelayYn()); + sendVO.setBizKakaoResendOrgnlTxt(kakaoVO.getSubMsgTxt()); + sendVO.setBizKakaoResendType(sendVO.getSubMsgType()); + sendVO.setBizKakaoImageType(kakaoVO.getImageType()); + + kakaoAlimTalkDAO.insertKakaoGroupDataTb_advc(sendVO); + + } + + + } diff --git a/src/main/java/itn/let/kakao/kakaoComm/KakaoVO.java b/src/main/java/itn/let/kakao/kakaoComm/KakaoVO.java index 527f146f..f59dc2dd 100644 --- a/src/main/java/itn/let/kakao/kakaoComm/KakaoVO.java +++ b/src/main/java/itn/let/kakao/kakaoComm/KakaoVO.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import itn.com.cmm.MjonFTSendVO; import itn.let.mjo.msg.service.MjonMsgVO; import lombok.Getter; import lombok.Setter; @@ -259,9 +260,14 @@ public class KakaoVO extends MjonMsgVO{ private String msgResendAllGroupId; private String msgResendAllTmpKey; private String msgResendAllYellowId; + + private String bizKakaoResendType; + private String fileCnt; private List> varListMap; + private List mjonFTSendVOList = new ArrayList<>(); + @Override public String toString() { String varListMapString = "["; @@ -286,6 +292,18 @@ public class KakaoVO extends MjonMsgVO{ } varListMapString += "]"; + + StringBuilder mjonFTListSb = new StringBuilder("["); + if (mjonFTSendVOList != null && !mjonFTSendVOList.isEmpty()) { + String prefix = ""; + for (MjonFTSendVO vo : mjonFTSendVOList) { + mjonFTListSb.append(prefix).append(vo == null ? "null" : vo.toString()); + prefix = ", "; + } + } + mjonFTListSb.append("]"); + + return "KakaoSendAdvcVO[" + "\n senderKey=[" + senderKey + "]" + "\n , subMsgTxtReplYn=[" + subMsgTxtReplYn + "]" + @@ -312,8 +330,62 @@ public class KakaoVO extends MjonMsgVO{ "\n , varListMap=[" + varListMapString + "]" + "\n , befCash=[" + getBefCash() + "]" + "\n , befPoint=[" + getBefPoint() + "]" + + "\n , mjonFTSendVOList=" + mjonFTListSb.toString() + "\n ]"; } + public String ftToString() { + StringBuilder sb = new StringBuilder("KakaoFTSendVO["); + 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 , 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 , subMsgTxt=[").append(subMsgTxt).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 , callFrom=[").append(getCallFrom()).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 , atDelayYn=[").append(getAtDelayYn()).append("]"); +// sb.append("\n , tmpBtnSelect=[").append(getTmpBtnSelect()).append("]"); + StringBuilder btnListSb = new StringBuilder("["); + if (buttonVOList != null && !buttonVOList.isEmpty()) { + String prefix = ""; + for (KakaoButtonVO btn : buttonVOList) { + btnListSb.append(prefix).append(btn == null ? "null" : btn.toString()); + prefix = ", "; + } + } + btnListSb.append("]"); + sb.append("\n , buttonVOList=").append(btnListSb); + + + // mjonFTSendVOList 내용 + StringBuilder ftList = new StringBuilder("["); + if (mjonFTSendVOList != null && !mjonFTSendVOList.isEmpty()) { + String prefix = ""; + for (MjonFTSendVO vo : mjonFTSendVOList) { + ftList.append(prefix).append(vo == null ? "null" : vo.toString()); + prefix = ", "; + } + } + ftList.append("]"); + sb.append("\n , mjonFTSendVOList=").append(ftList); + + sb.append("\n]"); + 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 6b090627..13394aeb 100644 --- a/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiImageUpload.java +++ b/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiImageUpload.java @@ -5,7 +5,10 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.ListIterator; @@ -15,6 +18,8 @@ import javax.annotation.Resource; import javax.imageio.ImageIO; import javax.swing.ImageIcon; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; @@ -30,16 +35,21 @@ import org.apache.http.util.EntityUtils; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import egovframework.rte.fdl.property.EgovPropertyService; +import itn.com.cmm.service.EgovFileMngService; import itn.com.cmm.service.EgovFileMngUtil; import itn.com.cmm.service.FileVO; import itn.let.kakao.kakaoComm.KakaoReturnVO; import itn.let.kakao.kakaoComm.KakaoVO; +import itn.let.mail.service.StatusResponse; import itn.let.utl.fcc.service.EgovStringUtil; +import lombok.extern.slf4j.Slf4j; +@Slf4j @Component("kakaoApiImageUpload") public class KakaoApiImageUpload { @@ -57,7 +67,17 @@ public class KakaoApiImageUpload { @Resource(name = "propertiesService") protected EgovPropertyService propertyService; - + + /** 첨부파일 저장경로 */ + @Value("#{globalSettings['Globals.file.saveDir']}") + private String fileSaveDir; + + @Resource(name="EgovFileMngUtil") + private EgovFileMngUtil fileUtil; + + + @Resource(name="EgovFileMngService") + private EgovFileMngService fileMngService; /** * @Method Name : kakaoApiImageUpload @@ -219,13 +239,13 @@ public class KakaoApiImageUpload { .addTextBody("bizId", mjonBizId) .addTextBody("apiKey", mjonBizKakaoApiKey) .addTextBody("imageType", kakaoVO.getImageType()) - .addTextBody("title", kakaoVO.getImgTitle()) - .addTextBody("link", kakaoVO.getImgLink()) + .addTextBody("title", "test") + .addTextBody("link", "https://maaa.com") .addTextBody("senderKey", kakaoVO.getSenderKey()) .addBinaryBody("image", new File(filePath),ContentType.MULTIPART_FORM_DATA,fullFileName) .build(); - httpPost.setEntity(httpEntity); + httpPost.setEntity(httpEntity); CloseableHttpResponse response = httpClient.execute(httpPost); @@ -245,6 +265,7 @@ public class KakaoApiImageUpload { String msg = object.get("message").toString(); String imgUrl = ""; + log.info(" : code :: [{}]", code); if(code.equals("200")) { imgUrl = object.get("image").toString(); } @@ -273,6 +294,174 @@ public class KakaoApiImageUpload { } + + + /** + * @methodName : kakaoApiImageUpload_advc + * @author : 이호영 + * @date : 2025. 6. 4. + * @description : kakaoApiImageUpload 수정 + * @return : StatusResponse + * @param kakaoVO + * @param files + * @param i + * @return + * @throws Exception + * + */ + public StatusResponse kakaoApiImageUpload_advc(KakaoVO kakaoVO, Map files, int fileKeyParam) throws Exception { +// try { + String storePathString = propertyService.getString("Globals.fileStorePath"); + File saveFolder = new File(storePathString); + if (!saveFolder.exists()) saveFolder.mkdirs(); + +// for (MultipartFile file : files.values()) { + MultipartFile file = files.values().stream().findFirst().orElse(null); + if (file == null || file.isEmpty()) { + return new StatusResponse(HttpStatus.BAD_REQUEST, "유효한 이미지 파일이 없습니다.", LocalDateTime.now()); + } + + + String originalName = file.getOriginalFilename(); + if (originalName == null || originalName.isEmpty()) { + return new StatusResponse(HttpStatus.BAD_REQUEST, "파일명이 비어 있습니다.", LocalDateTime.now()); + } + + String ext = FilenameUtils.getExtension(originalName).toLowerCase(); + if (!ext.matches("jpg|jpeg|png")) { + return new StatusResponse(HttpStatus.BAD_REQUEST, "지원하지 않는 이미지 형식입니다."); + } + + long size = file.getSize(); + if (size > 5 * 1024 * 1024) { + return new StatusResponse(HttpStatus.BAD_REQUEST, "이미지 용량은 5MB 이내여야 합니다."); + } + + BufferedImage image = ImageIO.read(file.getInputStream()); + if (image == null) { + return new StatusResponse(HttpStatus.BAD_REQUEST, "이미지를 읽을 수 없습니다."); + } + + int width = image.getWidth(); + int height = image.getHeight(); + String type = kakaoVO.getImageType(); + + if ("W".equals(type)) { + if (width != 800 || height != 600) { + return new StatusResponse(HttpStatus.BAD_REQUEST, "와이드 이미지는 800x600 사이즈만 허용됩니다."); + } + } else { + float ratio = width / (float) height; +// log.info("width : [{}], ",width); +// log.info("height : [{}], ",height); +// log.info("ratio : [{}], ",ratio); + if (width < 500 || ratio < 0.75 || ratio > 2.0) { + return new StatusResponse(HttpStatus.BAD_REQUEST, "일반 이미지는 가로 500px 이상, 비율 2:1 이상 또는 3:4 이하만 허용됩니다."); + } + } + + String atchFileId = this.saveImgFile(files); + + + + + + String newName = EgovStringUtil.getTimeStamp() + fileKeyParam; + String filePath = storePathString + File.separator + newName + "." + ext; + file.transferTo(new File(filePath)); + + // 카카오 API 호출 + CloseableHttpClient httpClient = HttpClients.createDefault(); + String apiUrl = mjonBizUrl + "/v3/kakao/image/upload"; + + HttpPost httpPost = new HttpPost(apiUrl); + /*HttpEntity httpEntity = MultipartEntityBuilder.create() + .addTextBody("bizId", mjonBizId) + .addTextBody("apiKey", mjonBizKakaoApiKey) + .addTextBody("imageType", kakaoVO.getImageType()) + .addTextBody("title", kakaoVO.getImgTitle()) + .addTextBody("link", kakaoVO.getImgLink()) + .addTextBody("senderKey", kakaoVO.getSenderKey()) + .addBinaryBody("image", new File(filePath), ContentType.MULTIPART_FORM_DATA, newName + "." + ext) + .build(); + */ + + HttpEntity httpEntity = MultipartEntityBuilder.create() + .addTextBody("bizId", mjonBizId) + .addTextBody("apiKey", mjonBizKakaoApiKey) + .addTextBody("imageType", kakaoVO.getImageType()) + .addTextBody("title", originalName) + .addTextBody("link", StringUtils.isEmpty(kakaoVO.getImgLink()) ? "https://" : kakaoVO.getImgLink()) + .addTextBody("senderKey", kakaoVO.getSenderKey()) + .addBinaryBody("image", new File(filePath), ContentType.MULTIPART_FORM_DATA, newName + "." + ext) + .build(); + + httpPost.setEntity(httpEntity); + + + + CloseableHttpResponse response = httpClient.execute(httpPost); + int statusCode = response.getStatusLine().getStatusCode(); + + if (statusCode == 200) { + String result = EntityUtils.toString(response.getEntity(), "UTF-8"); + JSONParser parser = new JSONParser(); + JSONObject object = (JSONObject) parser.parse(result); + + String code = object.get("code").toString(); + if ("200".equals(code)) { + Map returnMap = new HashMap<>(); + returnMap.put("imgUrl", object.get("image").toString()); + returnMap.put("fileName", originalName); + returnMap.put("atchFileId", atchFileId); + + return new StatusResponse(HttpStatus.OK, "이미지 등록이 완료 되었습니다.", returnMap); + } else { + return new StatusResponse(HttpStatus.BAD_REQUEST, object.get("message").toString(), LocalDateTime.now()); + } + } else { + return new StatusResponse(HttpStatus.BAD_REQUEST, "카카오 API 요청 실패", LocalDateTime.now()); + } +// } +// } catch (Exception e) { +// log.error("kakaoApiImageUpload_advc API Error", e); +// return new StatusResponse(HttpStatus.BAD_REQUEST, "친구톡 이미지 등록에 실패했습니다.", LocalDateTime.now()); +// } + } + + + + private String saveImgFile(Map files) throws Exception { + + + + String atchFileId = ""; + String isThumbFile = ""; + String imagePath = ""; + String KeyStr = "CANVASIMG_"; + + + Date now = new Date(); + SimpleDateFormat formatDate = new SimpleDateFormat("yyyyMMdd"); + String fdlDate = formatDate.format(now); + + + imagePath = fileSaveDir+"/file/MMS/" + fdlDate; + + + + if (!files.isEmpty()) { + List result = fileUtil.parseImageFileInf(files, KeyStr, 0, atchFileId, imagePath, isThumbFile); + atchFileId = fileMngService.insertFileInfs(result); + } + + + return atchFileId; + } + + + + /** * @Method Name : kakaoApiTemplateImageUpload * @작성일 : 2023. 2. 16. @@ -488,17 +677,20 @@ public class KakaoApiImageUpload { jsonObject.put("apiKey", mjonBizKakaoApiKey); jsonObject.put("imageUrl", kakaoVO.getTemplateImageUrl()); + log.info("kakaoVO.getTemplateImageUrl() :: [{}]", kakaoVO.getTemplateImageUrl()); + HttpClient httpClient = HttpClientBuilder.create().build(); HttpPost httpPost = new HttpPost(sendUrl); httpPost.setEntity(new StringEntity(jsonObject.toString(), "UTF-8")); httpPost.addHeader("Content-type", "application/json"); - httpPost.addHeader("Accept", "application/json"); + httpPost.addHeader("Accept", "application/json"); HttpResponse response = httpClient.execute(httpPost); String result = ""; String statusCode = Integer.toString(response.getStatusLine().getStatusCode()); + log.info(" + statusCode :: [{}]", statusCode); if(statusCode.equals("200")) { result = EntityUtils.toString(response.getEntity()); @@ -528,5 +720,7 @@ public class KakaoApiImageUpload { return kakaoReturnVO; } + + } diff --git a/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiJsonSave.java b/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiJsonSave.java index bbdd8f81..64dfd984 100644 --- a/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiJsonSave.java +++ b/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiJsonSave.java @@ -10,12 +10,18 @@ import java.util.Date; import java.util.List; import java.util.Map; +import org.apache.commons.lang3.StringUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + import itn.com.cmm.util.StringUtil; import itn.let.kakao.kakaoComm.KakaoButtonVO; import itn.let.kakao.kakaoComm.KakaoReturnVO; @@ -208,6 +214,139 @@ public class KakaoApiJsonSave { return jsonFileName; } + /* + * 친구톡 발송시 이미지, 버튼 추가에 따른 Json 파일 생성 + * 2025.04.18 + * 우영두 + * 파일은 하나만 생성해서 동일하게 사용함. + * + * */ + public String kakaoApiFTJsonSave_advc(KakaoVO kakaoVO) throws JsonProcessingException { + // json파일 저장 + + + ObjectMapper mapper = new ObjectMapper(); + ObjectNode jo = mapper.createObjectNode(); + + + + // 버튼 + if (kakaoVO.getButtonVOList() != null && !kakaoVO.getButtonVOList().isEmpty()) { + ArrayNode buttonList = mapper.createArrayNode(); + + for (KakaoButtonVO buttonInfoVO : kakaoVO.getButtonVOList()) { + ObjectNode button = mapper.createObjectNode(); + button.put("name", buttonInfoVO.getName()); + button.put("type", buttonInfoVO.getLinkType()); + + switch (buttonInfoVO.getLinkType()) { + case "WL": + button.put("url_mobile", buttonInfoVO.getLinkMo()); + button.put("url_pc", buttonInfoVO.getLinkPc()); + break; + case "AL": + button.put("scheme_ios", buttonInfoVO.getLinkIos()); + button.put("scheme_android", buttonInfoVO.getLinkAnd()); + break; + case "BC": + // 상담톡 + break; + case "BT": + // 봇 전환 + break; + } + buttonList.add(button); + } + jo.set("button", buttonList); + } + + + // 이미지 + String imageType = kakaoVO.getImageType(); + if (StringUtils.isNotEmpty(imageType)) { + ObjectNode image = mapper.createObjectNode(); + image.put("img_url", kakaoVO.getTemplateImageUrl()); + image.put("img_link", StringUtils.isNotEmpty(kakaoVO.getImgLink()) ? kakaoVO.getImgLink() : kakaoVO.getTemplateImageUrl()); + jo.set("image", image); + + // wide 여부 + if ("W".equals(imageType)) { + ObjectNode extra = mapper.createObjectNode(); + extra.put("wide", "Y"); + jo.set("extra", extra); + } + + } + + + // 문자열로 변환 (이스케이프 없음) + return mapper.writeValueAsString(jo); + + + + /* + + + // 버튼리스트 JSON 생성 + JSONArray buttonList = new JSONArray(); + for(KakaoButtonVO buttonInfoVO : kakaoVO.getButtonVOList()) { + JSONObject buttonInfo = new JSONObject(); + + buttonInfo.put("name", buttonInfoVO.getName()); + buttonInfo.put("type", buttonInfoVO.getLinkType()); + + if(buttonInfoVO.getLinkType().equals("WL")) { + buttonInfo.put("url_mobile", buttonInfoVO.getLinkMo()); + buttonInfo.put("url_pc", buttonInfoVO.getLinkPc()); + }else if(buttonInfoVO.getLinkType().equals("AL")) { + buttonInfo.put("scheme_ios", buttonInfoVO.getLinkIos()); + buttonInfo.put("scheme_android", buttonInfoVO.getLinkAnd()); + }else if(buttonInfoVO.getLinkType().equals("BC")) { + // 상담톡 진행시 등록해야함 + }else if(buttonInfoVO.getLinkType().equals("BT")) { + // 봇 전환 시 전달 + } + buttonList.add(buttonInfo); + } + + // 강조유형 JSON 생성 + JSONObject templateImageInfo = new JSONObject(); + JSONObject templateImageExtInfo = new JSONObject(); + String imageType = kakaoVO.getImageType(); + + if(StringUtils.isNotEmpty(imageType)) { + templateImageInfo.put("img_url", kakaoVO.getTemplateImageUrl()); + templateImageInfo.put("img_link", StringUtils.isNotEmpty(kakaoVO.getImgLink()) ? kakaoVO.getImgLink() : kakaoVO.getTemplateImageUrl() ); + } + + // wide 여부 + if ("W".equals(imageType)) { + ObjectNode extra = mapper.createObjectNode(); + extra.put("wide", "Y"); + jo.set("extra", extra); + } + + + JSONObject jo = new JSONObject(); + + if(buttonList.size() != 0) { + jo.put("button", buttonList); + } + + if(templateImageInfo.size() != 0) { + jo.put("image", templateImageInfo); + } + + if(templateImageExtInfo.size() != 0) { + jo.put("extra", templateImageExtInfo); + } + + // 입력 json 데이터를 파일로 변경 + String jsonStr = jo.toString(); + + return jsonStr;*/ + } + /* * 친구톡 발송시 이미지, 버튼 추가에 따른 Json 파일 생성 * 2024.01.17 @@ -298,7 +437,7 @@ public class KakaoApiJsonSave { // 입력 json 데이터를 파일로 변경 String jsonStr = jo.toString(); System.out.println("jsonFileName : "+jsonFileName); - + File outPut = new File(jsonFileName); outPut.createNewFile(); diff --git a/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiProfile.java b/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiProfile.java index 76583507..01d434b7 100644 --- a/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiProfile.java +++ b/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiProfile.java @@ -230,7 +230,8 @@ public class KakaoApiProfile { if(code.equals("200")) { JSONObject templateProfile = (JSONObject) object.get("data"); - + System.out.println("templateProfile = " + templateProfile.toJSONString()); + String senderKey = getStringValue(templateProfile, "senderKey"); //발신프로필키 String uuid = getStringValue(templateProfile, "uuid"); //카카오톡 채널 String name = getStringValue(templateProfile, "name"); //카카오톡 채널 발신프로필 명 diff --git a/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoFTJsonSave.java b/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoFTJsonSave.java index 4f9472ef..536a557a 100644 --- a/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoFTJsonSave.java +++ b/src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoFTJsonSave.java @@ -30,115 +30,6 @@ public class KakaoFTJsonSave { static String json; - @SuppressWarnings("unchecked") - public String kakaoApiJsonSave(KakaoVO kakaoVO, String[] varValInfo) { - // json파일 저장 - - - Date nowDate = new Date(); - SimpleDateFormat todayFrom = new SimpleDateFormat("yyyyMMdd"); - SimpleDateFormat timeFrom = new SimpleDateFormat("HHmmss"); - String jsonFileName = mjonBizJsonDir+"/"+kakaoVO.getUserId()+"/"+todayFrom.format(nowDate)+"/"+kakaoVO.getSendType(); // 아이디/날짜/타입 - - String fileName = timeFrom.format(nowDate)+"_"+kakaoVO.getDestPhone()+".json"; - - try { - - File userIdFile = new File(jsonFileName); - if(!userIdFile.exists()) { - userIdFile.mkdirs(); // 없으면 하위 디렉토리 까지 생성 - jsonFileName = jsonFileName +"/"+fileName; - }else { - - jsonFileName = jsonFileName +"/"+fileName; - System.out.println("jsonFileName : "+jsonFileName); - File file1 = new File(jsonFileName); - if (file1.isFile()) { - return jsonFileName; - } - } - - - - - KakaoReturnVO templateDetail = kakaoApiTemplate.selectKakaoApiTemplateDetail(kakaoVO); - - // 버튼리스트 JSON 생성 - JSONArray buttonList = new JSONArray(); - - // 버튼 수량 체크 후 진행 - for(KakaoButtonVO buttonInfoVO : templateDetail.getButtonList()) { - JSONObject buttonInfo = new JSONObject(); - - buttonInfo.put("name", buttonInfoVO.getName()); - buttonInfo.put("type", buttonInfoVO.getLinkType()); - - if(buttonInfoVO.getLinkType().equals("WL")) { - buttonInfo.put("url_mobile", buttonInfoVO.getLinkMo()); - buttonInfo.put("url_pc", buttonInfoVO.getLinkPc()); - }else if(buttonInfoVO.getLinkType().equals("AL")) { - buttonInfo.put("scheme_ios", buttonInfoVO.getLinkIos()); - buttonInfo.put("scheme_android", buttonInfoVO.getLinkAnd()); - }else if(buttonInfoVO.getLinkType().equals("BC")) { - // 상담톡 진행시 등록해야함 - }else if(buttonInfoVO.getLinkType().equals("BT")) { - // 봇 전환 시 전달 - } - buttonList.add(buttonInfo); - } - - - - - // Image JSON 생성 - JSONObject imageJson = new JSONObject(); - // img형과 wide 형인경우만 등록 (if문으로 제어) - imageJson.put("img_url", "등록된 이미지 URL"); - imageJson.put("img_link", "이동 페이지 URL"); - - - // Wide JSON 생성 - JSONObject wideJson = new JSONObject(); - // wide 형인경우만 등록(if문으로 제어) - wideJson.put("wide", "Y"); - - - - - JSONObject jo = new JSONObject(); - - if(imageJson.size() != 0) { - jo.put("image", imageJson); - } - if(wideJson.size() != 0) { - jo.put("extra", wideJson); - } - - if(buttonList.size() != 0) { - jo.put("button", buttonList); - } - - - - - // 입력 json 데이터를 파일로 변경 - String jsonStr = jo.toString(); - System.out.println("jsonFileName : "+jsonFileName); - - File outPut = new File(jsonFileName); - outPut.createNewFile(); - - BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outPut), "euc-kr")); - bw.write(jsonStr); - bw.close(); - - } catch (IOException e) { - System.out.println("json 생성 실패"); - e.printStackTrace(); - } - return jsonFileName; - } - @SuppressWarnings("unchecked") public String kakaoApiJsonSave(KakaoVO kakaoVO) { 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 fe3cd77b..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{ @@ -108,4 +103,9 @@ public class KakaoAlimTalkDAO extends EgovAbstractDAO { public void insertKakaoGroupDataTb_advc(KakaoSendAdvcVO sendVO) { insert("kakaoAlimTalkDAO.insertKakaoGroupDataTb_advc", sendVO); } + + public KakaoVO selectBizLog(String bizUmid) { + return (KakaoVO) select("kakaoAlimTalkDAO.selectBizLog", bizUmid); +// return (KakaoVO) select("kakaoAlimTalkDAO.selectKakaoAtUmid", bizUmid); + } } 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 21ca4b50..a3f37547 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 @@ -1,7 +1,6 @@ package itn.let.kakao.user.kakaoAt.service.impl; import java.math.BigDecimal; -import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.time.Duration; import java.time.Instant; @@ -11,8 +10,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,13 +19,15 @@ 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; import itn.let.kakao.kakaoComm.KakaoSendUtil; import itn.let.kakao.kakaoComm.KakaoVO; @@ -45,11 +44,11 @@ import itn.let.mjo.msgholiday.service.MsgHolidayVO; import itn.let.mjo.msgholiday.service.impl.MsgHolidayDAO; import itn.let.mjo.pay.service.MjonPayService; import itn.let.mjo.pay.service.MjonPayVO; +import itn.let.mjo.pay.service.impl.MjonPayDAO; 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 @@ -86,6 +85,9 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements /** userManageService */ @Resource(name = "userManageService") private EgovUserManageService userManageService; + + @Autowired + private MjonPayDAO mjonPayDAO; @Autowired KakaoSendUtil kakaoSendUtil; @@ -95,6 +97,13 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements @Autowired private PriceAndPoint priceAndPoint; + + final String KAKAO_SUCCESS_CODE = "7000"; + 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 @@ -783,80 +792,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); - } - + //1-1.카카오톡 발송 성공 + 대체문자 신청 O : 대체문자 금액 환불 + if(RESEND_YN_YES.equals(kakaoVO.getSubMsgSendYn())) { + + BizKakaoPriceVO bizKakaoPriceVO = mjonPayDAO.selectBizKakaoPrice(kakaoVO.getMsgGroupId()); + + BigDecimal sendPrice = null; + + if(AT_MSG_TYPE.equals(kakaoVO.getMsgType())){ + sendPrice = new BigDecimal(bizKakaoPriceVO.getBizKakaoAtPrice()); }else { - kakaoAlimTalkDAO.updateKakaoAtNotSend(vo); + 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, "카카오 " + kakaoVO.getMsgTypeTxt() + " 발송 성공 후 대체문자 금액 환불"); + } + } + + //1-2.카카오톡 발송 성공 + 대체문자 신청 X : 금액 환불 X + } + + private void handleAlternativeMessageScenario(KakaoVO kakaoVO) throws Exception { + KakaoVO bizLogVO = kakaoAlimTalkDAO.selectBizLog(kakaoVO.getBizUmid()); + log.info("대체문자 전송 UMID: {}", kakaoVO.getBizUmid()); + + //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); + } + + + //2-2.카카오톡 발송 실패 + 대체문자 발송 실패 : 전액 환불 + if (!isAlternativeMessageSuccessful) { + handleRefund(kakaoVO, "카카오 " + kakaoVO.getMsgTypeTxt() + " 전송 실패로 인한 결제 금액 환불"); + } } - - /* - * 카카오 친구톡 발송 실패에 따른 금액 환불 처리 - * 카카오 친구톡 대체문자 선택에 대해 성공시 친구톡과 문자 간 금액 차액의 환불도 처리 됨. - * */ - @Override - public void selectKakaoFtSentRefundList() throws Exception { - - /** - * 1. 카카오 FT 전송성공 확인 - * 2. 카카오 FT 전송실패, 대채문자 전송확인 - * 3. 카카오 FT 전송 실패 확인 - */ - List kakaoFtSentRefundList = kakaoAlimTalkDAO.selectKakaoFtSentRefundList(); - - for(KakaoVO vo : kakaoFtSentRefundList) { - System.out.println(vo.getMsgGroupId() +"________결과 : " +vo.getRsltCode() +" 대체문자 전송 : "+vo.getSubMsgSendYn()); - - if(vo.getRsltCode().equals("7000")) {//친구톡 발송 성공시 - - kakaoAlimTalkDAO.updateKakaoFtSend(vo); - - }else if(vo.getSubMsgSendYn().equals("Y")) {//친구톡 발송 실패 했을 경우 - - //대체문자 발송 UMID 번호 조회 - 알림톡 쿼리 동일하게 사용 - KakaoVO info = kakaoAlimTalkDAO.selectKakaoAtUmid(vo); - - System.out.println("대체문자 전송 : " + info.getBizUmid()); - - if (info.getBizUmid() != null) {//대체문자 발송 완료인 경우 - kakaoAlimTalkDAO.updateKakaoAtSubMsgSend(vo); - }else { - kakaoAlimTalkDAO.updateKakaoFtNotSend(vo); - } - - }else { - kakaoAlimTalkDAO.updateKakaoFtNotSend(vo); - } - } + private void handleRefund(KakaoVO vo, String msg) throws Exception { + // mj_cash 테이블에 환불 내역 추가 및 회원 금액 업데이트 + // eachPrice는 환불될 금액이므로 양수여야 합니다. + priceAndPoint.insertCashAndPointNoUpdate( + vo.getUserId(), + Float.parseFloat(vo.getEachPrice()), // 환불 금액은 양수 + msg, + vo.getMsgGroupId(), + vo.getUserData() + ); } @Override @@ -913,7 +918,7 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements /** @전송금액 확인 --------------------------------------------------*/ - if (!isCashSufficient(userId, kakaoSendAdvcListVO)) { + if (!kakaoSendUtil.isCashSufficient(userId, kakaoSendAdvcListVO)) { log.error("Insufficient balance for message sending."); return new StatusResponse(HttpStatus.BAD_REQUEST, "문자 발송에 필요한 보유 잔액이 부족 합니다."); } @@ -921,7 +926,8 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements /** @json파일이 있을 떄 biz_attachments insert */ - this.insertKakaoAtDataJsonInfo_advc(kakaoSendAdvcListVO); + kakaoSendUtil.insertKakaoAtDataJsonInfo_advc(kakaoSendAdvcListVO); +// this.insertKakaoAtDataJsonInfo_advc(kakaoSendAdvcListVO); Map> priceGroupedMessages = kakaoSendAdvcListVO.stream() @@ -941,7 +947,7 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements // 발송 데이터 삽입 - int instCnt = this.insertKakaoData_advc(groupedMsgList); + int instCnt = kakaoSendUtil.insertKakaoData_advc(groupedMsgList); // int instCnt = 6; if(instCnt > 0) { @@ -951,7 +957,7 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements KakaoSendAdvcVO sendVO = groupedMsgList.get(0); /** @groupData 테이블 insert */ - this.insertKakaoGroupDataTb_advc(instCnt, kakaoVO, sendVO); + kakaoSendUtil.insertKakaoGroupDataTb_advc(instCnt, kakaoVO, sendVO); /** @biz_kakao_price에 insert (대체문자 환불관련 테이블)*/ @@ -1029,178 +1035,54 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements return statusResponse; } - + @Override + public List selectKakaoSentRefundListForSingle() throws Exception{ + return kakaoAlimTalkDAO.selectKakaoSentRefundList(); + } - - private void insertKakaoAtDataJsonInfo_advc(List kakaoSendAdvcListVO) { - // TODO Auto-generated method stub - - // 측정할 메소드 호출 전 시간 기록 - List jsonInfoData = new ArrayList<>(kakaoSendAdvcListVO); - jsonInfoData.removeIf(t -> StringUtils.isBlank(t.getJsonStr())); - log.info(" + jsonInfoData Insert :: [{}]", jsonInfoData.size()); - if(jsonInfoData.size() > 0) { - kakaoAlimTalkDAO.insertKakaoAtDataJsonInfo_advc(jsonInfoData); - } - - } - - private void insertKakaoGroupDataTb_advc(int instCnt, KakaoVO kakaoVO, KakaoSendAdvcVO sendVO) throws Exception { - // TODO Auto-generated method stub - -// log.info(" + insertKakaoGroupDataTb_advc kakaoVO :: \n[{}]", kakaoVO.toString());; -// log.info(" + insertKakaoGroupDataTb_advc kakaoSendAdvcVOList :: \n[{}]", sendVO.toString()); + @Override + public void kakaoSingleRefund(KakaoVO kakaoVO) throws Exception { - sendVO.setMsgGroupCnt(Integer.toString(instCnt)); - sendVO.setReserveYn(kakaoVO.getReserveYn()); - sendVO.setBefCash(priceAndPoint.getBefCash(sendVO.getUserId())); - sendVO.setBefPoint(priceAndPoint.getBefPoint(sendVO.getUserId())); + System.out.println(kakaoVO.getMsgGroupId() +"________결과 : " +kakaoVO.getRsltCode() +" 대체문자 전송 : "+kakaoVO.getSubMsgSendYn()); + kakaoVO.setMsgTypeTxt(AT_MSG_TYPE.equals(kakaoVO.getMsgType()) ? "알림톡" : "친구톡"); - Float eachPrice = Float.parseFloat(sendVO.getEachPrice()); - - Float totPrice = eachPrice * instCnt; - sendVO.setTotPrice(String.format("%.1f", totPrice)); - - sendVO.setAtDelayYn(kakaoVO.getAtSmishingYn()); - sendVO.setBizKakaoResendOrgnlTxt(kakaoVO.getSubMsgTxt()); - sendVO.setBizKakaoResendType(sendVO.getSubMsgType()); - - kakaoAlimTalkDAO.insertKakaoGroupDataTb_advc(sendVO); - - } - - /** - * @methodName : insertKakaoData_advc - * @author : 이호영 - * @date : 2025. 3. 20. - * @description : 카카오 batch 발송 => mj_msg_data - * @return : int - * @param kakaoSendAdvcVOList - * @param parentLoopCount - * @param isJsonNotEmpty - * @param isJsonNameAllSame - * @return - * - */ - private int insertKakaoData_advc(List kakaoSendAdvcVOList) { - - - // 시작 시간 측정 - long totalStartTime = System.currentTimeMillis(); - - int totalSize = kakaoSendAdvcVOList.size(); // 총 데이터 개수 - // Batch 크기 설정 (고정값) -// int batchSize = 10000; 465 - int batchSize = 50000; // 9분 18초 - - log.info("총 데이터 개수 :: [{}] ", totalSize); - log.info("설정된 Batch 크기 :: [{}] ", batchSize); - - // 총 insert 카운트 - int instCnt = 0; - int batchCount = 0; - - // 각 배치별 실행 시간 기록 - List batchExecutionTimes = new ArrayList<>(); - - - // 첫 번째 배치에서만 삽입했는지 추적하는 플래그 - for (int i = 0; i < totalSize; i += batchSize) { - // Batch 시작 시간 측정 - long batchStartTime = System.currentTimeMillis(); - - // Batch 리스트 생성 - List batchList = kakaoSendAdvcVOList.subList(i, Math.min(i + batchSize, totalSize)); - System.out.println("Batch 시작 인덱스: " + i); - - // mj_msg_data 테이블 insert - int insertedCount = kakaoAlimTalkDAO.insertKakaoAtDataInfo_advc(batchList); + if(KAKAO_SUCCESS_CODE.equals(kakaoVO.getRsltCode())) { + //1.카카오톡 발송 성공 + processKakaoSendCharge(kakaoVO); - /** @kakaoSendUtil.populateSendLists - * 하단에서 - * getJsonStr 데이터 처리 후 활용 - * */ - instCnt += insertedCount; - - // Batch 종료 시간 측정 및 실행 시간 계산 - long batchEndTime = System.currentTimeMillis(); - double batchExecutionTimeInSeconds = (batchEndTime - batchStartTime) / 1000.0; - - // 실행 시간 기록 - batchExecutionTimes.add(batchExecutionTimeInSeconds); - batchCount++; + }else if(RESEND_YN_YES.equals(kakaoVO.getSubMsgSendYn())) {//카카오톡 발송 실패, 대체문자 발송 신청 O + //2.카카오톡 발송 실패 + 대체문자 신청 O + handleAlternativeMessageScenario(kakaoVO); + + }else { + //3.카카오톡 발송 실패 + 대체문자 신청 X : 전액 환불 + handleRefund(kakaoVO, "카카오 " + kakaoVO.getMsgTypeTxt() + " 전송 실패로 인한 결제 금액 환불"); } - - // 종료 시간 측정 - long totalEndTime = System.currentTimeMillis(); - - // 총 실행 시간 계산 (밀리초 -> 초로 변환) - double totalExecutionTimeInSeconds = (totalEndTime - totalStartTime) / 1000.0; - - // 실행 시간 출력 - log.info("총 배치 실행 횟수 :: [{}] ", batchCount); - log.info("batchSize :: [{}] ", batchSize); - log.info("총 실행 시간 :: [{}] ", totalExecutionTimeInSeconds + "초"); - log.info("총 삽입 건수 :: [{}] ", instCnt); - - // 각 배치별 실행 시간 출력 - for (int k = 0; k < batchExecutionTimes.size(); k++) { - System.out.println("배치 " + (k + 1) + " 실행 시간 :: " + batchExecutionTimes.get(k) + "초"); - } - - return instCnt; + //모든 유형 환불 완료 처리 + mjonMsgDAO.updateRefundY(kakaoVO); } - // 보유 금액이 충분한지 확인하는 메서드 - private boolean isCashSufficient(String userId, List kakaoSendAdvcListVO) throws Exception { - - - String userMoney = priceAndPoint.getBefCash(userId); - // 쉼표 제거 - userMoney = userMoney.replace(",", ""); - - // 사용자 보유 금액 BigDecimal 변환 (HALF_EVEN 적용) - BigDecimal befCash = new BigDecimal(userMoney).setScale(2, RoundingMode.HALF_EVEN); - - // 총 메시지 금액 계산 (HALF_EVEN 적용) - BigDecimal totalEachPrice = kakaoSendAdvcListVO.stream() - .map(msg -> new BigDecimal(String.valueOf(msg.getEachPrice()))) // 변환 오류 방지 - .reduce(BigDecimal.ZERO, BigDecimal::add) - .setScale(2, RoundingMode.HALF_EVEN); // 일관성 유지 - - // 비교 수행 - return befCash.compareTo(totalEachPrice) >= 0; - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// // 보유 금액이 충분한지 확인하는 메서드 +// private boolean isCashSufficient(String userId, List kakaoSendAdvcListVO) throws Exception { +// +// +// String userMoney = priceAndPoint.getBefCash(userId); +// // 쉼표 제거 +// userMoney = userMoney.replace(",", ""); +// +// // 사용자 보유 금액 BigDecimal 변환 (HALF_EVEN 적용) +// BigDecimal befCash = new BigDecimal(userMoney).setScale(2, RoundingMode.HALF_EVEN); +// +// // 총 메시지 금액 계산 (HALF_EVEN 적용) +// BigDecimal totalEachPrice = kakaoSendAdvcListVO.stream() +// .map(msg -> new BigDecimal(String.valueOf(msg.getEachPrice()))) // 변환 오류 방지 +// .reduce(BigDecimal.ZERO, BigDecimal::add) +// .setScale(2, RoundingMode.HALF_EVEN); // 일관성 유지 +// +// // 비교 수행 +// return befCash.compareTo(totalEachPrice) >= 0; +// } } 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 cf1641b3..9fc1083b 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/KakaoFriendsTalkService.java b/src/main/java/itn/let/kakao/user/kakaoFt/service/KakaoFriendsTalkService.java new file mode 100644 index 00000000..d9392550 --- /dev/null +++ b/src/main/java/itn/let/kakao/user/kakaoFt/service/KakaoFriendsTalkService.java @@ -0,0 +1,12 @@ +package itn.let.kakao.user.kakaoFt.service; + +import javax.servlet.http.HttpServletRequest; + +import itn.let.kakao.kakaoComm.KakaoVO; +import itn.let.mail.service.StatusResponse; + +public interface KakaoFriendsTalkService { + + StatusResponse insertKakaoFtSandAjax_advc(KakaoVO kakaoVO, HttpServletRequest request) throws Exception; + +} 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 new file mode 100644 index 00000000..4be8090e --- /dev/null +++ b/src/main/java/itn/let/kakao/user/kakaoFt/service/impl/KakaoFriendsTalkServiceImpl.java @@ -0,0 +1,261 @@ +package itn.let.kakao.user.kakaoFt.service.impl; + +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +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.utl.fcc.service.EgovStringUtil; +import itn.let.kakao.kakaoComm.KakaoSendAdvcVO; +import itn.let.kakao.kakaoComm.KakaoSendUtil; +import itn.let.kakao.kakaoComm.KakaoVO; +import itn.let.kakao.user.kakaoAt.service.impl.KakaoAlimTalkDAO; +import itn.let.kakao.user.kakaoFt.service.KakaoFriendsTalkService; +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 +@Service("KakaoFriendsTalkService") +public class KakaoFriendsTalkServiceImpl extends EgovAbstractServiceImpl implements KakaoFriendsTalkService{ + + @Resource(name = "egovFriendstalkTemplateIdService") + private EgovIdGnrService idgenFriendTalkTmpId; + + @Resource(name="kakaoFriendsTalkTemplateDAO") + private KakaoFriendsTalkTemplateDAO kakaoFriendsTalkTemplateDAO; + + @Resource(name="mjonMsgDAO") + private MjonMsgDAO mjonMsgDAO; + + /** userManageService */ + @Resource(name = "userManageService") + private EgovUserManageService userManageService; + + @Resource(name = "egovMjonMsgGroupIdGnrService") + private EgovIdGnrService idgenMjonMsgGroupId; + + + @Resource(name="kakaoAlimTalkDAO") + private KakaoAlimTalkDAO kakaoAlimTalkDAO; + + @Resource(name = "MjonMsgDataService") + private MjonMsgDataService mjonMsgDataService; + + @Autowired + KakaoSendUtil kakaoSendUtil; + + @Autowired + private MjonCommon mjonCommon; + + @Autowired + private PriceAndPoint priceAndPoint; + + @Override + public StatusResponse insertKakaoFtSandAjax_advc(KakaoVO kakaoVO, HttpServletRequest request) throws Exception { + StatusResponse statusResponse = new StatusResponse(); + +// log.info(" + kakaoVO.toString() :: [{}]", kakaoVO.toString()); + +// log.info(" + kakaoVO.toString() :: [{}]", kakaoVO.ftToString()); + + + + // 측정할 메소드 호출 전 시간 기록 + Instant start = Instant.now(); +// KakaoSendAdvcVO + + Map returnMap = new HashMap<>(); + + 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); + + /** + * 회원 정지된 상태이면 문자 발송이 안되도록 처리함 현재 로그인 세션도 만료 처리함 + */ + boolean mberSttus = userManageService.selectUserStatusInfo(userId); + if (!mberSttus) { + request.getSession().invalidate(); + // UNAUTHORIZED : 인증되지 않은 사용자가 접근하려고 할 때 + return new StatusResponse(HttpStatus.UNAUTHORIZED, + "현재 고객님께서는 문자온 서비스 이용이 정지된 상태로 친구톡을 발송하실 수 없습니다. 이용정지 해제를 원하시면 고객센터로 연락주시기 바랍니다."); + } + + + /** + * 친구톡은 발송 시간 제약이 있음 + */ + if(kakaoSendUtil.isRestrictedFriendTalkTime(kakaoSendUtil.resolveBaseDate(kakaoVO))) { + // UNAUTHORIZED : 인증되지 않은 사용자가 접근하려고 할 때 + return new StatusResponse(HttpStatus.BAD_REQUEST, + "친구톡은 20시 50분부터 익일 08시까지 발송이 제한됩니다."); + } + + +/** @isHolidayNotified + * @false : 알림 X + * @true : 알림 O */ + boolean isHolidayNotified = mjonCommon.processUserAndCheckFT(kakaoVO); + + + UserManageVO userManageVO = mjonCommon.getUserManageInfo(userId); + + + // 스팸관련 키워드 select + List resultSpamTxt = mjonMsgDataService.selectSpamKeywordList(); + +/** @카카오톡 전송 list 셋팅 -------------------------------------------*/ + 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, "문자 발송에 필요한 보유 잔액이 부족 합니다."); + } + + +/** @json파일이 있을 떄 biz_attachments insert */ + kakaoSendUtil.insertKakaoAtDataJsonInfo_advc(kakaoSendAdvcListVO); + + + + Map> priceGroupedMessages = kakaoSendAdvcListVO.stream() + .collect(Collectors.groupingBy(KakaoSendAdvcVO::getEachPrice)); + // instTotalCnt : 화면에서 보여줄 총 발송건수 + int instTotalCnt = 0; + + + // 임시 + List nextMsgGroupIdA = new ArrayList<>(); + // 대안: entrySet() 직접 사용 + for (Map.Entry> entry : priceGroupedMessages.entrySet()) { + // entry 사용 + + List groupedMsgList = entry.getValue(); // 해당 가격의 메시지 리스트 + + String nextMsgGroupId = idgenMjonMsgGroupId.getNextStringId(); + groupedMsgList.forEach(t -> t.setMsgGroupId(nextMsgGroupId)); + + + // 발송 데이터 삽입 + int instCnt = kakaoSendUtil.insertKakaoData_advc(groupedMsgList); +// int instCnt = 6; + + if(instCnt > 0) { + + instTotalCnt += instCnt; + + KakaoSendAdvcVO sendVO = groupedMsgList.get(0); + +/** @groupData 테이블 insert */ + kakaoSendUtil.insertKakaoGroupDataTb_advc(instCnt, kakaoVO, sendVO); + + + +/** @biz_kakao_price에 insert (대체문자 환불관련 테이블)*/ + priceAndPoint.insertBizFtKakaoPrice(kakaoVO.getUserId(), sendVO.getMsgGroupId()); + + + priceAndPoint.insertCashAndPoint(kakaoVO.getUserId() + , -Float.parseFloat(sendVO.getTotPrice()) + , "카카오 친구톡 총 "+groupedMsgList.size()+"건 중 " + instCnt + "건 발송" + , nextMsgGroupId + ); + + +/** @SLACK발송 */ + /** @발송조건이되면 발송 */ + if(isHolidayNotified + && ("Y".equals(userManageVO.getAtSmishingYn()) || "Y".equals(kakaoVO.getAtDelayYn())) + ) { + mjonCommon.getAdminKakaoAtSendSlack(sendVO); + }else if("Y".equals(kakaoVO.getAtSmishingYn())){ + /** @발송조건이 안되면 DB INSERT */ + mjonMsgDAO.insertSpamPassMsgData(MjonMsgVO.builder() + .msgGroupId(nextMsgGroupId) + .userId(kakaoVO.getUserId()) + .reqDate(kakaoVO.getReqDate()) + .smsTxt(groupedMsgList.get(0).getTemplateContent()) + .totalCallCnt(instCnt) + .callFrom(kakaoVO.getCallFrom()) + .msgType("8") + .reserveYn(kakaoVO.getReserveYn()) + .build() + ); + } + + nextMsgGroupIdA.add(nextMsgGroupId); + + } + + } + + returnMap.put("resultSts", instTotalCnt); + returnMap.put("reserYn", kakaoVO.getReserveYn()); + returnMap.put("groupIds", nextMsgGroupIdA); + + + // 측정할 메소드 호출 후 시간 기록 + Instant end = Instant.now(); + + log.info(" + start :: [{}]", start); + // 실행 시간 계산 (나노초, 밀리초, 초) + long seconds = Duration.between(start, end).getSeconds(); + log.info("메소드 실행 시간 (초): {} s", seconds); + double minutes = seconds / 60.0; // 소수점 포함을 위해 60.0으로 나눔 + + returnMap.put("second", seconds+" s"); + returnMap.put("minutes", minutes+" min"); + + +// System.out.println("메소드 실행 시간 (분): " + minutes + " min"); + + + + +// priceAndPoint.getBefCash(userId); + + + + + statusResponse.setStatus(HttpStatus.OK); + statusResponse.setObject(returnMap); + + 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 0dc23c11..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 @@ -13,9 +13,11 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @@ -29,7 +31,9 @@ import itn.let.kakao.kakaoComm.KakaoSendUtil; import itn.let.kakao.kakaoComm.KakaoVO; import itn.let.kakao.kakaoComm.kakaoApi.service.KakaoApiService; import itn.let.kakao.user.kakaoAt.service.KakaoAlimTalkService; +import itn.let.kakao.user.kakaoFt.service.KakaoFriendsTalkService; import itn.let.kakao.user.kakaoFt.service.KakaoFriendsTalkTemplateService; +import itn.let.mail.service.StatusResponse; import itn.let.mjo.mjocommon.MjonCommon; import itn.let.mjo.mjocommon.MjonHolidayApi; import itn.let.mjo.msgdata.service.MjonMsgDataService; @@ -68,6 +72,9 @@ public class KakaoFriendsTalkSendController { @Resource(name = "kakaoFriendsTalkTemplateService") private KakaoFriendsTalkTemplateService kakaoFtTemplateService; + @Resource(name = "KakaoFriendsTalkService") + private KakaoFriendsTalkService kakaoFriendsTalkService; + /** userManageService */ @Resource(name = "userManageService") private EgovUserManageService userManageService; @@ -113,114 +120,109 @@ public class KakaoFriendsTalkSendController { model.addAttribute("loginVO", loginVO); - try { - if(!userId.equals("") && !author.equals("ROLE_ADMIN")) { + if(!"".equals(userId) && !"ROLE_ADMIN".equals(author)) { + + //사용자 등록 발신프로필 정보 조회해오기 + kakaoVO.setUserId(userId); + List resultProfileList = kakaoApiService.selectKakaoProfileList(kakaoVO); + model.addAttribute("resultProfileList", resultProfileList); - //사용자 등록 발신프로필 정보 조회해오기 - kakaoVO.setUserId(userId); - List resultProfileList = kakaoApiService.selectKakaoProfileList(kakaoVO); - model.addAttribute("resultProfileList", resultProfileList); - - // 특수문자 리스트 불러오기 - MjonSymbolVO symbolVO = new MjonSymbolVO(); - List symbolList = mjonSymbolService.selectMjonSymbolList(symbolVO); - model.addAttribute("symbolList", symbolList); - - //아이디 발신번호 리스트 불러오기. - List resultSendPhonList = mjonMsgDataService.selectSendPhonNumList(userId); - List resultPhonList = new ArrayList(); - MJUtil mjUtil = new MJUtil(); - for(String phone : resultSendPhonList) { - resultPhonList.add(mjUtil.addDash(phone)); - } - model.addAttribute("resultPhonList", resultPhonList); - - - MberManageVO mberManageVO = mjonMsgDataService.selectMberManageInfo(userId); - - model.addAttribute("atSmishingYn", mberManageVO.getAtSmishingYn()); - - //3.사용자 개인단가 정보가 0이 아니면 개인단가 사용, 없으면 시스템 기본 단가 사용 - /*Float shortPrice = mberManageVO.getShortPrice(); - Float longPrice = mberManageVO.getLongPrice(); - Float picturePrice = mberManageVO.getPicturePrice(); - Float picture2Price = mberManageVO.getPicture2Price(); - Float picture3Price = mberManageVO.getPicture3Price();*/ - BigDecimal userMoney = new BigDecimal(mberManageVO.getUserMoney()).setScale(2, RoundingMode.HALF_EVEN); - - model.addAttribute("userMoney", userMoney); - - - ////////////////////////////////////////////////////////////////// - - //최근 전송 내역 - MjonMsgDataVO searchVO = new MjonMsgDataVO(); - Calendar cal = Calendar.getInstance(); - Date now = new Date(); - SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd"); - cal.setTime(now); - cal.add(Calendar.DATE, -3); - String chkDate = format.format(cal.getTime()); - searchVO.setUserId(userId); - searchVO.setMyMsgStDt(chkDate); //검색 시작일 저장 - 현재날짜로 부터 3일 이전 날짜로 시작 - model.addAttribute("resultLatestMsgList", mjonMsgDataService.selectLatestMsgList(searchVO)); - - //자주보내는 번호 - model.addAttribute("resultBookMarkMsgList", mjonMsgDataService.selectBookMarkMsgList(searchVO)); - - // 사용자 정의 단가 정보 불러오기(시스템 단가 혹은 협의 단가) - model.addAttribute("sendPrice", kakaoSendUtil.selectSendPriceOfKakaoAtAndSmsAndMms(userId)); - - - //사용자 템플릿 정보 조회 - String friendId = kakaoVO.getFriendId(); - KakaoVO resultTemplateVO = new KakaoVO(); - - if(friendId != null) { - resultTemplateVO = kakaoFtTemplateService.selectKakaoFriendsTemplateDetail(kakaoVO); - } - model.addAttribute("resultTemplateVO", resultTemplateVO); - - - //친구톡 발송시간 체크 하기 - 20:50 ~ 익일 08:00 사이에는 발송 금지 - - SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - - Date nows = new Date(); - String nowDate = sdf1.format(nows); - cal.setTime(nows); - - int hours = cal.get(Calendar.HOUR_OF_DAY); - int minuts = cal.get(Calendar.MINUTE); + // 특수문자 리스트 불러오기 + MjonSymbolVO symbolVO = new MjonSymbolVO(); + List symbolList = mjonSymbolService.selectMjonSymbolList(symbolVO); + model.addAttribute("symbolList", symbolList); + + //아이디 발신번호 리스트 불러오기. + List resultSendPhonList = mjonMsgDataService.selectSendPhonNumList(userId); + List resultPhonList = new ArrayList(); + MJUtil mjUtil = new MJUtil(); + for(String phone : resultSendPhonList) { + resultPhonList.add(mjUtil.addDash(phone)); + } + model.addAttribute("resultPhonList", resultPhonList); + + + MberManageVO mberManageVO = mjonMsgDataService.selectMberManageInfo(userId); + + model.addAttribute("atSmishingYn", mberManageVO.getAtSmishingYn()); + + //3.사용자 개인단가 정보가 0이 아니면 개인단가 사용, 없으면 시스템 기본 단가 사용 + /*Float shortPrice = mberManageVO.getShortPrice(); + Float longPrice = mberManageVO.getLongPrice(); + Float picturePrice = mberManageVO.getPicturePrice(); + Float picture2Price = mberManageVO.getPicture2Price(); + Float picture3Price = mberManageVO.getPicture3Price();*/ + BigDecimal userMoney = new BigDecimal(mberManageVO.getUserMoney()).setScale(2, RoundingMode.HALF_EVEN); + + model.addAttribute("userMoney", userMoney); + + + ////////////////////////////////////////////////////////////////// + + //최근 전송 내역 + MjonMsgDataVO searchVO = new MjonMsgDataVO(); + Calendar cal = Calendar.getInstance(); + Date now = new Date(); + SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd"); + cal.setTime(now); + cal.add(Calendar.DATE, -3); + String chkDate = format.format(cal.getTime()); + searchVO.setUserId(userId); + searchVO.setMyMsgStDt(chkDate); //검색 시작일 저장 - 현재날짜로 부터 3일 이전 날짜로 시작 +// model.addAttribute("resultLatestMsgList", mjonMsgDataService.selectLatestMsgList(searchVO)); + + //자주보내는 번호 +// model.addAttribute("resultBookMarkMsgList", mjonMsgDataService.selectBookMarkMsgList(searchVO)); + + // 사용자 정의 단가 정보 불러오기(시스템 단가 혹은 협의 단가) + model.addAttribute("sendPrice", kakaoSendUtil.selectSendPriceOfKakaoAtAndSmsAndMms(userId)); + + + //사용자 템플릿 정보 조회 + String friendId = kakaoVO.getFriendId(); + KakaoVO resultTemplateVO = new KakaoVO(); + + if(friendId != null) { + resultTemplateVO = kakaoFtTemplateService.selectKakaoFriendsTemplateDetail(kakaoVO); + } + model.addAttribute("resultTemplateVO", resultTemplateVO); + + + //친구톡 발송시간 체크 하기 - 20:50 ~ 익일 08:00 사이에는 발송 금지 + + SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + Date nows = new Date(); + String nowDate = sdf1.format(nows); + cal.setTime(nows); + + int hours = cal.get(Calendar.HOUR_OF_DAY); + int minuts = cal.get(Calendar.MINUTE); - boolean sendStatus = true; + boolean sendStatus = true; + + if(hours >= 20) { - if(hours >= 20) { + if(minuts >= 50) { - if(minuts >= 50) { - - System.out.println("발송금지 시간" + hours + ":" + minuts); - sendStatus = false; - - } - - } - - if(hours < 8) { - - System.out.println("발송금지 시간" + hours + ":" + minuts); + System.out.println("발송금지 시간" + hours + ":" + minuts); sendStatus = false; } - System.out.println("발송상태는 ::: "+sendStatus); - model.addAttribute("sendStatus", sendStatus); - } - } catch (Exception e) { - System.out.println(" kakaoFriendsTalkMsgDataViewDataRegist Error ::: " + e); + if(hours < 8) { + + System.out.println("발송금지 시간" + hours + ":" + minuts); + sendStatus = false; + + } + + System.out.println("발송상태는 ::: "+sendStatus); + model.addAttribute("sendStatus", sendStatus); + } return "web/kakao/msgdata/ft/KakaoFriendsTalkMsgDataView"; @@ -313,7 +315,29 @@ public class KakaoFriendsTalkSendController { return modelAndView; } - + + /** + * @methodName : sendMsgData_ft_advc + * @author : 이호영 + * @date : 2025. 4. 17. + * @description : 친구톡 발송기능 + * @return : ResponseEntity + * @param kakaoVO + * @param request + * @param model + * @return + * @throws Exception + * + */ + @RequestMapping(value = "/web/mjon/kakao/friendstalk/kakaoFriendsTalkMsgSendAjax_advc.do") + public ResponseEntity kakaoFriendsTalkMsgSendAjax_advc( + @RequestBody KakaoVO kakaoVO, + HttpServletRequest request + ) throws Exception { + System.out.println(" :: sendMsgData_ft_advc :: "); + return ResponseEntity.ok().body(kakaoFriendsTalkService.insertKakaoFtSandAjax_advc(kakaoVO, request)) ; + + } /** * @Method Name : kakaoFriendsTalkMsgSendAjax @@ -687,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 9b9540bd..8bf45081 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 @@ -1,5 +1,6 @@ package itn.let.kakao.user.kakaoFt.web; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -8,11 +9,16 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.servlet.ModelAndView; @@ -21,6 +27,7 @@ import egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper; import egovframework.rte.ptl.mvc.tags.ui.pagination.PaginationInfo; import itn.com.cmm.EgovMessageSource; import itn.com.cmm.LoginVO; +import itn.com.cmm.RestResponse; import itn.com.cmm.service.EgovCmmUseService; import itn.com.utl.fcc.service.EgovStringUtil; import itn.let.kakao.kakaoComm.KakaoReturnVO; @@ -32,10 +39,14 @@ import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiTemplate; import itn.let.kakao.kakaoComm.kakaoApi.KakaoFTJsonSave; import itn.let.kakao.kakaoComm.kakaoApi.service.KakaoApiService; import itn.let.kakao.user.kakaoFt.service.KakaoFriendsTalkTemplateService; +import itn.let.mail.service.StatusResponse; import itn.let.mjo.symbol.service.MjonSymbolService; import itn.let.mjo.symbol.service.MjonSymbolVO; +import itn.let.uss.ion.cnt.service.CntManageVO; import itn.let.uss.umt.service.EgovUserManageService; +import lombok.extern.slf4j.Slf4j; +@Slf4j @Controller public class KakaoFriendsTalkTemplateController { @@ -170,6 +181,63 @@ public class KakaoFriendsTalkTemplateController { return modelAndView; } + + + @RequestMapping(value="/web/pop/ft/kakaoTemplatePop.do") + public String siteContentIntro(@ModelAttribute CntManageVO cntManageVO, HttpServletRequest request, Model model) throws Exception { + + return "/web/pop/kakaoFtPop"; + } + + @ResponseBody + @RequestMapping(value= {"/web/mjon/kakao/template/sendKakaoFriendsTemplateImageUploadAjax_advc.do"}) + public ResponseEntity sendKakaoFriendsTemplateImageUploadAjax_advc( + @ModelAttribute("kakaoVO") KakaoVO kakaoVO + , final MultipartHttpServletRequest multiRequest + ) throws Exception { + ModelAndView modelAndView = new ModelAndView(); + 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() + ) + ); + } + + + + final Map files = multiRequest.getFileMap(); + /* if (!files.isEmpty()){ + + Map resultMap = kakaoApiImageUpload.kakaoApiImageUpload(kakaoVO, files, 0); + + //테스트 용 + modelAndView.addObject("code", resultMap.get("code")); + modelAndView.addObject("msg", resultMap.get("msg")); + modelAndView.addObject("imgUrl", resultMap.get("imgUrl")); + } + + modelAndView.addObject("result", "success");*/ + + return ResponseEntity.ok().body(kakaoApiImageUpload.kakaoApiImageUpload_advc(kakaoVO, files, 0)); + } catch (Exception e) { + e.printStackTrace(); + // TODO: handle exception + return ResponseEntity.ok().body(new StatusResponse( + HttpStatus.BAD_REQUEST + , "오류가 발생하였습니다." + , "" + )); + } + + } // 카카오 친구톡 템플릿 등록요청 @@ -189,9 +257,13 @@ public class KakaoFriendsTalkTemplateController { @ModelAttribute("kakaoVO") KakaoVO kakaoVO , final MultipartHttpServletRequest multiRequest ) throws Exception { + + ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("jsonView"); +// log.info(" + kakaoVO.getAdFlag() :: [{}]", kakaoVO.getAdFlag()); + log.info(" + ImgLink :: [{}]", kakaoVO.getImgLink()); try { LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null; String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId()); @@ -207,16 +279,18 @@ public class KakaoFriendsTalkTemplateController { kakaoVO.setLastUpdusrId(userId); kakaoVO.setSendType("FT"); + /* String imgUrl = kakaoVO.getTemplateImageUrl(); int buttonSize = kakaoVO.getButtonVOList().size(); if(!imgUrl.equals("") || buttonSize > 0) { - + + log.info(" + kakaoVO.getAdFlag() :: [{}]", kakaoVO.getAdFlag()); //json 파일 생성 처리 String resultJsonPath = kakaoFTJsonSave.kakaoApiJsonSave(kakaoVO); kakaoVO.setBizJsonName(resultJsonPath); - } + }*/ int result = kakaoFtTemplateService.insertKakaoFriendsTemplateData(kakaoVO); diff --git a/src/main/java/itn/let/kakao/user/sent/service/KakaoSentVO.java b/src/main/java/itn/let/kakao/user/sent/service/KakaoSentVO.java index 1a2e7682..66a8cc27 100644 --- a/src/main/java/itn/let/kakao/user/sent/service/KakaoSentVO.java +++ b/src/main/java/itn/let/kakao/user/sent/service/KakaoSentVO.java @@ -6,9 +6,11 @@ import java.util.List; import itn.let.uss.umt.service.UserDefaultVO; import lombok.Getter; import lombok.Setter; +import lombok.ToString; @Getter @Setter +@ToString public class KakaoSentVO extends UserDefaultVO{ private static final long serialVersionUID = 1L; @@ -90,7 +92,7 @@ public class KakaoSentVO extends UserDefaultVO{ private String bizKakaoFtPrice; private String bizSmsPrice; private String bizMmsPrice; - + private int successCount; private int waitCount; private int failCount; @@ -112,6 +114,7 @@ public class KakaoSentVO extends UserDefaultVO{ private String successPrice; private String kakaoResendSuccPrice; + private String bizKakaoImageType; private String divideYn; @@ -119,4 +122,6 @@ public class KakaoSentVO extends UserDefaultVO{ private String yellowId; + private String adFlag; + } diff --git a/src/main/java/itn/let/kakao/user/sent/service/impl/KakaoSentServiceImpl.java b/src/main/java/itn/let/kakao/user/sent/service/impl/KakaoSentServiceImpl.java index 7f4e1e1e..0e29d6a9 100644 --- a/src/main/java/itn/let/kakao/user/sent/service/impl/KakaoSentServiceImpl.java +++ b/src/main/java/itn/let/kakao/user/sent/service/impl/KakaoSentServiceImpl.java @@ -39,7 +39,9 @@ import itn.let.kakao.user.sent.service.KakaoSentDetailVO; import itn.let.kakao.user.sent.service.KakaoSentService; import itn.let.kakao.user.sent.service.KakaoSentVO; import itn.let.mjo.msgsent.service.MjonMsgSentVO; +import lombok.extern.slf4j.Slf4j; +@Slf4j @Service("KakaoSentService") public class KakaoSentServiceImpl extends EgovAbstractServiceImpl implements KakaoSentService{ @@ -140,6 +142,9 @@ public class KakaoSentServiceImpl extends EgovAbstractServiceImpl implements Ka List resultList = new ArrayList(); resultList = kakaoSentDAO.selectAllKakaoSentList_advc(kakaoSentVO); + + System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + //totPrice 계산 및 상태코드 set resultList = resultList.stream().map(t -> setPriceNCode(t)).collect(Collectors.toList()); @@ -287,15 +292,27 @@ public class KakaoSentServiceImpl extends EgovAbstractServiceImpl implements Ka * */ private KakaoSentVO setPriceNCode(KakaoSentVO result) { + log.info("=============================== setPriceNCode ================================"); + //성공 건수 세팅 KakaoSentVO eachCnt = new KakaoSentVO(); eachCnt.setMsgGroupId(result.getMsgGroupId()); eachCnt.setBizKakaoResendYn("Y".equals(result.getBizKakaoResendYn()) ? "Y" : "N"); + eachCnt.setMsgType(result.getMsgType()); + eachCnt.setBizKakaoImageType(result.getBizKakaoImageType()); + eachCnt.setBizKakaoResendType(result.getBizKakaoResendType()); + try { + log.info("eachCnt.getMsgType() :: [{}]", eachCnt.getMsgType()); + log.info("eachCnt.getBizKakaoImageType() :: [{}]", eachCnt.getBizKakaoImageType()); + log.info("eachCnt.getBizKakaoResendType() :: [{}]", eachCnt.getBizKakaoResendType()); + eachCnt = kakaoSentDAO.selectKakaoSentCntEachCnt_advc(eachCnt); } catch (Exception e) { System.out.println("setPriceNCode error!!"); } + log.info(" + eachCnt.toString() :: [{}]", eachCnt.toString()); +// log.info(" + eachCnt.getSuccessPrice() :: [{}]", eachCnt.getSuccessPrice()); result.setSuccessCount(eachCnt.getSuccessCount()); result.setWaitCount(eachCnt.getWaitCount()); @@ -328,9 +345,9 @@ public class KakaoSentServiceImpl extends EgovAbstractServiceImpl implements Ka //총금액 시작 //======================================================= - // TotPrice : 성공건수에 대한 금액 곱하기 - BigDecimal atPrice = new BigDecimal(successPrice); - BigDecimal kakaoResendPrice = new BigDecimal(kakaoResendSuccPrice); + // TotPrice : 성공건수에 대한 금액 곱하기 ? : null 처리 + BigDecimal atPrice = successPrice != null ? new BigDecimal(successPrice) : BigDecimal.ZERO; + BigDecimal kakaoResendPrice = kakaoResendSuccPrice != null ? new BigDecimal(kakaoResendSuccPrice) : BigDecimal.ZERO; BigDecimal totalPrice = atPrice.add(kakaoResendPrice); // 소수점 한 자리로 설정 (반올림)// totalPrice 값을 소수점 한 자리까지 반올림하여 roundedTotalPrice에 저장 // RoundingMode.HALF_UP: 반올림 방식으로, 소수점 기준 5 이상이면 올림, 그렇지 않으면 내림 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 5dc1b8a4..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 @@ -2,6 +2,7 @@ package itn.let.kakao.user.sent.web; import java.io.FileReader; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import itn.com.cmm.util.DateUtils; import java.text.SimpleDateFormat; @@ -38,6 +39,7 @@ import itn.com.cmm.LoginVO; import itn.com.cmm.util.StringUtil; import itn.com.cmm.util.StringUtil2; import itn.com.utl.fcc.service.EgovStringUtil; +import itn.let.cmm.vo.FileInfoVO; import itn.let.kakao.admin.kakaoAt.service.MjonKakaoATVO; import itn.let.kakao.kakaoComm.KakaoButtonVO; import itn.let.kakao.kakaoComm.KakaoReturnVO; @@ -46,13 +48,20 @@ import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiTemplate; import itn.let.kakao.user.sent.service.KakaoSentDetailVO; import itn.let.kakao.user.sent.service.KakaoSentService; import itn.let.kakao.user.sent.service.KakaoSentVO; +import itn.let.mjo.msgsent.service.MjonMsgSentVO; +import itn.let.mjo.msgsent.service.impl.MjonMsgSentDAO; +import lombok.extern.slf4j.Slf4j; +@Slf4j @Controller public class KakaoSentController { @Resource(name = "KakaoSentService") private KakaoSentService kakaoSentService; + @Resource(name="MjonMsgSentDAO") + private MjonMsgSentDAO mjonMsgSentDAO; + @Autowired KakaoApiTemplate kakaoApiTemplate; @@ -182,7 +191,7 @@ public class KakaoSentController { //전체 발송 리스트 불러오기 List resultAllSentList = kakaoSentService.selectAllKakaoSentList(kakaoSentVO); - System.out.println("??"); + model.addAttribute("resultAllSentList", resultAllSentList); // model.addAttribute("resultAllSentCnt", resultAllSentList.size()); @@ -263,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", ""); @@ -890,22 +918,21 @@ public class KakaoSentController { KakaoReturnVO returnVO = new KakaoReturnVO(); try { - String tmpContent = kakaoATVO.getSmsTxtTrans(); - String jsonFilePath = kakaoATVO.getBizKakaoJsonFile(); + String jsonContents = kakaoATVO.getContents(); //친구톡 이미지 또는 버튼 정보가 있다면 실행 - if(jsonFilePath != null && jsonFilePath.length() > 0) { + if(jsonContents != null && jsonContents.length() > 0) { - FileReader reader = new FileReader(jsonFilePath); + /*FileReader reader = new FileReader(jsonFilePath); int ch; String resultStr = ""; while ((ch = reader.read()) != -1) { resultStr = resultStr + (char)ch; } - + */ JSONParser parser = new JSONParser(); - Object obj = parser.parse(resultStr); + Object obj = parser.parse(jsonContents); JSONObject object = (JSONObject) obj; String image = (object.get("image") == null) ? null : object.get("image").toString(); @@ -964,7 +991,7 @@ public class KakaoSentController { } //친구톡 내용 셋팅 - returnVO.setTemplateContent(tmpContent); + returnVO.setTemplateContent(kakaoATVO.getSmsTxt()); } catch (Exception e) { e.printStackTrace(); @@ -1037,42 +1064,70 @@ public class KakaoSentController { - //발송 관리 문자발송 내용 상세보기 팝업 => 문자내용(MJ_MSG_DATA) - MjonKakaoATVO mjonKakaoATResultVO = kakaoSentService.selectKakaoSentDetailDataAjax(mjonKakaoATVO); - // 대체문자 엔터키 치환 - mjonKakaoATResultVO.setSmsTxt(StringUtil2.replaceBR(mjonKakaoATResultVO.getSmsTxt())); - model.addAttribute("resultMsgDetail", mjonKakaoATResultVO); + try { - String msgType = mjonKakaoATResultVO.getMsgType(); + //발송 관리 문자발송 내용 상세보기 팝업 => 문자내용(MJ_MSG_DATA) + MjonKakaoATVO mjonKakaoATResultVO = kakaoSentService.selectKakaoSentDetailDataAjax(mjonKakaoATVO); + // 대체문자 엔터키 치환 + if(StringUtils.isNotEmpty(mjonKakaoATResultVO.getSmsTxt())) { + mjonKakaoATResultVO.setSmsTxt(StringUtil2.replaceBR(mjonKakaoATResultVO.getSmsTxt())); + } + model.addAttribute("resultMsgDetail", mjonKakaoATResultVO); + + String msgType = mjonKakaoATResultVO.getMsgType(); + + if(msgType.equals("8")) {//카카오 알림톡인 경우 상세정보 처리 + + // 템플릿 api 가져오기 + KakaoVO kakaoVO = new KakaoVO(); + kakaoVO.setSenderKey(mjonKakaoATResultVO.getMsgNoticetalkSenderKey()); + kakaoVO.setTemplateCode(mjonKakaoATResultVO.getMsgNoticetalkTmpKey()); + + KakaoReturnVO kakaoTemplateInfo =kakaoApiTemplate.selectKakaoApiTemplateDetail(kakaoVO); + + model.addAttribute("kakaoTemplateInfo", kakaoTemplateInfo); + // //템플릿 api 가져오기 + + }else if(msgType.equals("9")) {//카카오 친구톡인 경우 상세정보 처리 + + //String smsTxt = mjonKakaoATResultVO.getSmsTxt(); + + KakaoReturnVO kakaoTemplateInfo = getKakaoFTSendTemplateInfo(mjonKakaoATResultVO); + 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); + } + //kakaoTemplateInfo.setTemplateContent(smsTxt); + + + }else { + + model.addAttribute("kakaoTemplateInfo", ""); + + } + model.addAttribute("msgType", msgType); - if(msgType.equals("8")) {//카카오 알림톡인 경우 상세정보 처리 - - // 템플릿 api 가져오기 - KakaoVO kakaoVO = new KakaoVO(); - kakaoVO.setSenderKey(mjonKakaoATResultVO.getMsgNoticetalkSenderKey()); - kakaoVO.setTemplateCode(mjonKakaoATResultVO.getMsgNoticetalkTmpKey()); - - KakaoReturnVO kakaoTemplateInfo =kakaoApiTemplate.selectKakaoApiTemplateDetail(kakaoVO); - - model.addAttribute("kakaoTemplateInfo", kakaoTemplateInfo); - // //템플릿 api 가져오기 - - }else if(msgType.equals("9")) {//카카오 친구톡인 경우 상세정보 처리 - - //String smsTxt = mjonKakaoATResultVO.getSmsTxt(); - - KakaoReturnVO kakaoTemplateInfo = getKakaoFTSendTemplateInfo(mjonKakaoATResultVO); - //kakaoTemplateInfo.setTemplateContent(smsTxt); - - model.addAttribute("kakaoTemplateInfo", kakaoTemplateInfo); - - }else { - - model.addAttribute("kakaoTemplateInfo", ""); + } catch (Exception e) { + e.printStackTrace(); + // TODO: handle exception } - - model.addAttribute("msgType", msgType); - 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/mail/service/StatusResponse.java b/src/main/java/itn/let/mail/service/StatusResponse.java index 50649c95..91844fda 100644 --- a/src/main/java/itn/let/mail/service/StatusResponse.java +++ b/src/main/java/itn/let/mail/service/StatusResponse.java @@ -5,6 +5,7 @@ import java.time.LocalDateTime; import org.springframework.http.HttpStatus; import itn.let.mjo.pay.service.RefundVO; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; 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 0e93135a..ab597df2 100644 --- a/src/main/java/itn/let/mjo/msg/service/MjonMsgVO.java +++ b/src/main/java/itn/let/mjo/msg/service/MjonMsgVO.java @@ -93,6 +93,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; // 전송 배분률 @@ -165,6 +166,7 @@ public class MjonMsgVO extends ComDefaultVO{ private float smsPrice; // sms 단가 private float mmsPrice; // mms 단가 + private float picturePrice; // mms 단가 private float kakaoAtPrice; // 카카오 알림톡 단가 private float kakaoFtPrice; // 카카오 친구톡 단가 private float kakaoFtImgPrice;// 카카오 이미지 단가 @@ -301,6 +303,8 @@ public class MjonMsgVO extends ComDefaultVO{ private String bizLogCallStatusCode; //다우기술 biz_log 테이블의 발송결과 코드 값 성공/실패/대기 코드값 변환(성공:S, 대기:W, 실패:F). private String bizLogCallStatusTxt; //다우기술 biz_log 테이블의 발송결과 내용 텍스트. private String bizLogStatus; //다우기술 biz_log 테이블의 전송상태값 + + private String bizKakaoImageType; // 비즈 발송 img 값 private String accessKey; // 'API Key', @@ -313,5 +317,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/msg/service/impl/MjonMsgDAO.java b/src/main/java/itn/let/mjo/msg/service/impl/MjonMsgDAO.java index 5108b0ac..0c688dd0 100644 --- a/src/main/java/itn/let/mjo/msg/service/impl/MjonMsgDAO.java +++ b/src/main/java/itn/let/mjo/msg/service/impl/MjonMsgDAO.java @@ -455,6 +455,11 @@ public class MjonMsgDAO extends EgovAbstractDAO { update("mjonMsgDAO.updateKakaoAtDelayCancelMsgDataFlag", mjonMsgVO); } + // mj_msg_data 테이블 지연 알림톡 취소 값 수정 + public void updateRefundY(MjonMsgVO mjonMsgVO) { + update("mjonMsgDAO.updateRefundY", mjonMsgVO); + } + // mj_msg_group_data 테이블 지연 알림톡 취소 값 수정 public void updateKakaoAtDelayCancelMsgGroupDataFlag(MjonMsgVO mjonMsgVO) { update("mjonMsgDAO.updateKakaoAtDelayCancelMsgGroupDataFlag", mjonMsgVO); 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/msgsent/service/MjonMsgDetailSentDTO.java b/src/main/java/itn/let/mjo/msgsent/service/MjonMsgDetailSentDTO.java new file mode 100644 index 00000000..f37e7961 --- /dev/null +++ b/src/main/java/itn/let/mjo/msgsent/service/MjonMsgDetailSentDTO.java @@ -0,0 +1,22 @@ +package itn.let.mjo.msgsent.service; + +import java.util.List; + +import itn.let.cmm.vo.FileInfoVO; +import itn.let.uss.umt.service.UserDefaultVO; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class MjonMsgDetailSentDTO extends UserDefaultVO{ + + private static final long serialVersionUID = 1L; + + + private String userId; + private String callTo; + private String statusTxt; + + +} diff --git a/src/main/java/itn/let/mjo/msgsent/service/MjonMsgSentService.java b/src/main/java/itn/let/mjo/msgsent/service/MjonMsgSentService.java index ca2dbe0f..1e989d85 100644 --- a/src/main/java/itn/let/mjo/msgsent/service/MjonMsgSentService.java +++ b/src/main/java/itn/let/mjo/msgsent/service/MjonMsgSentService.java @@ -65,7 +65,7 @@ public interface MjonMsgSentService { public Map selectAllMsgSentDetailView(MjonMsgDetailSentVO mjonMsgDetailSentVO) throws Exception; - public List findByMsgDetailListAjax(MjonMsgDetailSentVO mjonMsgDetailSentVO); + public List findByMsgDetailListAjax(MjonMsgDetailSentVO mjonMsgDetailSentVO); public void msgSentExcelDownLoad(MjonMsgSentVO mjonMsgSentVO, HttpServletResponse response) throws IOException, Exception; diff --git a/src/main/java/itn/let/mjo/msgsent/service/impl/MjonMsgSentDAO.java b/src/main/java/itn/let/mjo/msgsent/service/impl/MjonMsgSentDAO.java index 7e1e84ae..3c1bfe6d 100644 --- a/src/main/java/itn/let/mjo/msgsent/service/impl/MjonMsgSentDAO.java +++ b/src/main/java/itn/let/mjo/msgsent/service/impl/MjonMsgSentDAO.java @@ -9,6 +9,7 @@ import egovframework.rte.psl.dataaccess.EgovAbstractDAO; import itn.let.fax.addr.service.FaxAddrGroupVO; import itn.let.mjo.addr.service.AddrGroupVO; import itn.let.mjo.block.service.MjonBlockVO; +import itn.let.mjo.msgsent.service.MjonMsgDetailSentDTO; import itn.let.mjo.msgsent.service.MjonMsgDetailSentVO; import itn.let.mjo.msgsent.service.MjonMsgSWFDTO; import itn.let.mjo.msgsent.service.MjonMsgSentVO; @@ -182,9 +183,9 @@ public class MjonMsgSentDAO extends EgovAbstractDAO { return (MjonMsgDetailSentVO) select("MjonMsgSentDAO.selectAllMsgSentDetailView", mjonMsgDetailSentVO); } - public List findByMsgDetailListAjax(MjonMsgDetailSentVO mjonMsgDetailSentVO) { + public List findByMsgDetailListAjax(MjonMsgDetailSentVO mjonMsgDetailSentVO) { - return (List) list("MjonMsgSentDAO.findByMsgDetailListAjax", mjonMsgDetailSentVO); + return (List) list("MjonMsgSentDAO.findByMsgDetailListAjax", mjonMsgDetailSentVO); } public List findByReqDateWhereMsgGroupId(String msgGroupId) { diff --git a/src/main/java/itn/let/mjo/msgsent/service/impl/MjonMsgSentServiceImpl.java b/src/main/java/itn/let/mjo/msgsent/service/impl/MjonMsgSentServiceImpl.java index 037f6548..d25a9490 100644 --- a/src/main/java/itn/let/mjo/msgsent/service/impl/MjonMsgSentServiceImpl.java +++ b/src/main/java/itn/let/mjo/msgsent/service/impl/MjonMsgSentServiceImpl.java @@ -39,6 +39,7 @@ import itn.let.cmm.vo.FileInfoVO; import itn.let.fax.addr.service.FaxAddrGroupVO; import itn.let.mjo.addr.service.AddrGroupVO; import itn.let.mjo.block.service.MjonBlockVO; +import itn.let.mjo.msgsent.service.MjonMsgDetailSentDTO; import itn.let.mjo.msgsent.service.MjonMsgDetailSentVO; import itn.let.mjo.msgsent.service.MjonMsgSWFDTO; import itn.let.mjo.msgsent.service.MjonMsgSentService; @@ -474,9 +475,9 @@ public class MjonMsgSentServiceImpl extends EgovAbstractServiceImpl implements } @Override - public List findByMsgDetailListAjax(MjonMsgDetailSentVO mjonMsgDetailSentVO) { + public List findByMsgDetailListAjax(MjonMsgDetailSentVO mjonMsgDetailSentVO) { - List list = mjonMsgSentDAO.findByMsgDetailListAjax(mjonMsgDetailSentVO); + List list = mjonMsgSentDAO.findByMsgDetailListAjax(mjonMsgDetailSentVO); list.stream().forEach(t->{ t.setCallTo(StringUtil2.formatPhone(t.getCallTo())); }); diff --git a/src/main/java/itn/let/mjo/msgsent/web/MjonMsgSentController.java b/src/main/java/itn/let/mjo/msgsent/web/MjonMsgSentController.java index c33fe418..fbe0e39a 100644 --- a/src/main/java/itn/let/mjo/msgsent/web/MjonMsgSentController.java +++ b/src/main/java/itn/let/mjo/msgsent/web/MjonMsgSentController.java @@ -50,6 +50,7 @@ import itn.let.mjo.addr.service.AddrService; import itn.let.mjo.addr.service.AddrVO; import itn.let.mjo.apikey.service.ApiKeyMngService; import itn.let.mjo.apikey.service.ApiKeyVO; +import itn.let.mjo.msgsent.service.MjonMsgDetailSentDTO; import itn.let.mjo.msgsent.service.MjonMsgDetailSentVO; import itn.let.mjo.msgsent.service.MjonMsgSentCntVO; import itn.let.mjo.msgsent.service.MjonMsgSentService; @@ -191,7 +192,17 @@ private static final Logger logger = LoggerFactory.getLogger(MjonMsgSentControll public ResponseEntity findByMsgDetailListAjax(MjonMsgDetailSentVO mjonMsgDetailSentVO) throws Exception { - List resultList = mjonMsgSentService.findByMsgDetailListAjax(mjonMsgDetailSentVO); + List resultList = new ArrayList<>(); + try { + + resultList = mjonMsgSentService.findByMsgDetailListAjax(mjonMsgDetailSentVO); + } catch (Exception e) { + e.printStackTrace(); + // TODO: handle exception + } + log.info("resultList :: [{}]", resultList.size()); +// resultList = resultList.subList(0, 275000); +// log.info("resultList :: [{}]", resultList.size()); return ResponseEntity.ok().body(new StatusResponse(HttpStatus.OK, "", resultList)); diff --git a/src/main/java/itn/let/mjo/pay/service/MjonPayVO.java b/src/main/java/itn/let/mjo/pay/service/MjonPayVO.java index 7c750698..f6a39f41 100644 --- a/src/main/java/itn/let/mjo/pay/service/MjonPayVO.java +++ b/src/main/java/itn/let/mjo/pay/service/MjonPayVO.java @@ -236,6 +236,8 @@ public class MjonPayVO extends ComDefaultVO{ private int remainPoint; + private String userData; + private String totChgPay; // 간편결제분류 diff --git a/src/main/java/itn/let/mjo/pay/service/impl/MjonPayDAO.java b/src/main/java/itn/let/mjo/pay/service/impl/MjonPayDAO.java index d7e60f92..d82c45e8 100644 --- a/src/main/java/itn/let/mjo/pay/service/impl/MjonPayDAO.java +++ b/src/main/java/itn/let/mjo/pay/service/impl/MjonPayDAO.java @@ -5,6 +5,7 @@ import java.util.List; import org.springframework.stereotype.Repository; import egovframework.rte.psl.dataaccess.EgovAbstractDAO; +import itn.let.kakao.kakaoComm.BizKakaoPriceVO; import itn.let.mjo.pay.service.MjonPayVO; import itn.let.mjo.pay.service.MjonVaMsgLogVO; import itn.let.mjo.pay.service.RefundVO; @@ -45,6 +46,10 @@ public class MjonPayDAO extends EgovAbstractDAO { public MjonPayVO selectCashVO(MjonPayVO mjonPayVO) throws Exception{ return (MjonPayVO)select("mjonPayDAO.selectCashVO", mjonPayVO); } + + public BizKakaoPriceVO selectBizKakaoPrice(String msgGroupId) throws Exception{ + return (BizKakaoPriceVO)select("mjonPayDAO.selectBizKakaoPrice", msgGroupId); + } public void insertCash(MjonPayVO mjonPayVO) throws Exception{ 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 52b9d57d..d7f27bf4 100644 --- a/src/main/java/itn/let/mjo/pay/web/MjonPayController.java +++ b/src/main/java/itn/let/mjo/pay/web/MjonPayController.java @@ -4645,10 +4645,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 d4f190f1..4d9f0943 100644 --- a/src/main/java/itn/let/module/base/PriceAndPoint.java +++ b/src/main/java/itn/let/module/base/PriceAndPoint.java @@ -5,18 +5,27 @@ import java.math.RoundingMode; import javax.annotation.Resource; +import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import egovframework.rte.fdl.cmmn.exception.FdlException; import egovframework.rte.fdl.idgnr.EgovIdGnrService; +import itn.let.kakao.kakaoComm.KakaoSendAdvcVO; +import itn.let.kakao.kakaoComm.KakaoSendUtil; +import itn.let.kakao.kakaoComm.KakaoVO; +import itn.let.kakao.user.kakaoAt.service.impl.KakaoAlimTalkDAO; import itn.let.mjo.event.service.MjonEventService; import itn.let.mjo.event.service.MjonEventVO; import itn.let.mjo.event.service.impl.MjonEventDAO; import itn.let.mjo.msg.service.MjonMsgVO; +import itn.let.mjo.msgdata.service.MjonMsgDataService; import itn.let.mjo.msgdata.service.impl.MjonMsgDataDAO; import itn.let.mjo.pay.service.MjonPayVO; import itn.let.mjo.pay.service.impl.MjonPayDAO; +import itn.let.sym.site.service.JoinSettingVO; import itn.let.uss.umt.service.MberManageVO; +import lombok.extern.slf4j.Slf4j; /** * @@ -32,6 +41,7 @@ import itn.let.uss.umt.service.MberManageVO; * * */ +@Slf4j @Component public class PriceAndPoint { @@ -46,6 +56,11 @@ public class PriceAndPoint { @Resource(name = "egovMjonCashIdGnrService") private EgovIdGnrService idgenMjonCashId; + + @Resource(name="kakaoAlimTalkDAO") + private KakaoAlimTalkDAO kakaoAlimTalkDAO; + + /** * @methodName : getBefCash @@ -114,19 +129,120 @@ public class PriceAndPoint { , String msgGroupId ) throws Exception { - MjonPayVO mjonPayVO = new MjonPayVO(); - mjonPayVO.setCashId(idgenMjonCashId.getNextStringId()); - mjonPayVO.setUserId(userId); - System.out.println(" + totPrice :: "+ totPrice); - mjonPayVO.setCash(totPrice); - mjonPayVO.setFrstRegisterId(userId); - mjonPayVO.setMemo(memo); - mjonPayVO.setMsgGroupId(msgGroupId); +// MjonPayVO mjonPayVO = new MjonPayVO(); +// mjonPayVO.setCashId(idgenMjonCashId.getNextStringId()); +// mjonPayVO.setUserId(userId); +// System.out.println(" + totPrice :: "+ totPrice); +// mjonPayVO.setCash(totPrice); +// mjonPayVO.setFrstRegisterId(userId); +// mjonPayVO.setMemo(memo); +// mjonPayVO.setMsgGroupId(msgGroupId); + insertCashAndPoint(userId, totPrice, memo, msgGroupId, null); + +// mjonPayDAO.insertCash(mjonPayVO); //캐시 +// mjonPayDAO.updateMemberCash(mjonPayVO); //회원정보 업데이트 + + } + /** + * @methodName : insertCashAndPoint + * @author : 이호영 + * @date : 2025. 7. 17. + * @description : insertCashAndPoint 에서 환불으로 인해 userData 추가 + * @return : void + * @param userId + * @param totPrice + * @param memo + * @param msgGroupId + * @param userData + * @throws Exception + * + */ + public void insertCashAndPoint( + 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); //캐시 mjonPayDAO.updateMemberCash(mjonPayVO); //회원정보 업데이트 } - + + private MjonPayVO buildPayVO(String userId, float totPrice, String memo, String msgGroupId) throws FdlException { + MjonPayVO vo = new MjonPayVO(); + vo.setCashId(idgenMjonCashId.getNextStringId()); + vo.setUserId(userId); + vo.setCash(totPrice); + vo.setFrstRegisterId(userId); + vo.setMemo(memo); + vo.setMsgGroupId(msgGroupId); + System.out.println(" + totPrice :: " + totPrice); + return vo; + } + + public void insertBizFtKakaoPrice(String userId, String msgGroupId) throws Exception { + KakaoVO kakaoVO = new KakaoVO(); + + System.out.println("======================="); + // 사용자 개인 단가 정보 불러오기 + MberManageVO mberManageVO = mjonMsgDataDAO.selectMberManageInfo(userId); + // 시스템 기본 단가 정보 불러오기 + JoinSettingVO sysJoinSetVO = mjonMsgDataDAO.selectJoinSettingInfo(); + KakaoSendUtil.getValidPrice(mberManageVO.getShortPrice(), sysJoinSetVO.getShortPrice()); + // TODO Auto-generated method stub + kakaoVO.setMsgGroupId(msgGroupId); + + kakaoVO.setSmsPrice(KakaoSendUtil.getValidPrice(mberManageVO.getShortPrice(), sysJoinSetVO.getShortPrice())); + kakaoVO.setMmsPrice(KakaoSendUtil.getValidPrice(mberManageVO.getLongPrice(), sysJoinSetVO.getLongPrice())); + kakaoVO.setPicturePrice(KakaoSendUtil.getValidPrice(mberManageVO.getPicturePrice(), sysJoinSetVO.getPicturePrice())); + + kakaoVO.setKakaoFtPrice(KakaoSendUtil.getValidPrice(mberManageVO.getKakaoFtPrice(), sysJoinSetVO.getKakaoFtPrice())); + kakaoVO.setKakaoFtImgPrice(KakaoSendUtil.getValidPrice(mberManageVO.getKakaoFtImgPrice(), sysJoinSetVO.getKakaoFtImgPrice())); + kakaoVO.setKakaoFtWideImgPrice(KakaoSendUtil.getValidPrice(mberManageVO.getKakaoFtWideImgPrice(), sysJoinSetVO.getKakaoFtWideImgPrice())); + + + + 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 ada754d1..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/java/itn/let/sym/site/service/JoinSettingVO.java b/src/main/java/itn/let/sym/site/service/JoinSettingVO.java index a76eca53..f64ba44f 100644 --- a/src/main/java/itn/let/sym/site/service/JoinSettingVO.java +++ b/src/main/java/itn/let/sym/site/service/JoinSettingVO.java @@ -1,5 +1,12 @@ package itn.let.sym.site.service; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + /** * 로그인정책에 대한 VO 클래스를 정의한다. * 로그인정책정보의 목록 항목을 관리한다. @@ -18,13 +25,18 @@ package itn.let.sym.site.service; * * */ + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +@ToString public class JoinSettingVO { /** * serialVersionUID */ - @SuppressWarnings("unused") - private static final long serialVersionUID = 1L; private float shortPrice; // 단문 단가 private float longPrice; //장문 단가 @@ -37,6 +49,9 @@ public class JoinSettingVO { private float customTextPrice; // 텍스트 단순수정 private float kakaoAtPrice; // 카카오 알림톡 단가 private float kakaoFtPrice; // 카카오 친구톡 단가 + private float kakaoFtImgPrice; // 카카오 친구톡 이미지 단가 + private float kakaoFtWideImgPrice; // 카카오 친구톡 와이드 단가 + private float faxPrice; // 팩스 단가 private float refundPer; //환불 비율 @@ -51,188 +66,5 @@ public class JoinSettingVO { private String smishingNoti; //첫결제(카드제외) 스미싱의심 알림 여부 private String holiSmishingNoti; //야간 스미싱알림 여부 - public String getSmishingNoti() { - return smishingNoti; - } - - public void setSmishingNoti(String smishingNoti) { - this.smishingNoti = smishingNoti; - } - - public float getShortPrice() { - return shortPrice; - } - - public void setShortPrice(float shortPrice) { - this.shortPrice = shortPrice; - } - - public float getLongPrice() { - return longPrice; - } - - public void setLongPrice(float longPrice) { - this.longPrice = longPrice; - } - - public float getPicturePrice() { - return picturePrice; - } - - public void setPicturePrice(float picturePrice) { - this.picturePrice = picturePrice; - } - - public float getPicture2Price() { - return picture2Price; - } - - public void setPicture2Price(float picture2Price) { - this.picture2Price = picture2Price; - } - - public float getPicture3Price() { - return picture3Price; - } - - public void setPicture3Price(float picture3Price) { - this.picture3Price = picture3Price; - } - - public float getCustomSamplePrice() { - return customSamplePrice; - } - - public void setCustomSamplePrice(float customSamplePrice) { - this.customSamplePrice = customSamplePrice; - } - - public float getCustomEditPrice() { - return customEditPrice; - } - - public void setCustomEditPrice(float customEditPrice) { - this.customEditPrice = customEditPrice; - } - - public float getCustomEdit3Price() { - return customEdit3Price; - } - - public void setCustomEdit3Price(float customEdit3Price) { - this.customEdit3Price = customEdit3Price; - } - - public float getCustomTextPrice() { - return customTextPrice; - } - - public void setCustomTextPrice(float customTextPrice) { - this.customTextPrice = customTextPrice; - } - - public float getRefundPer() { - return refundPer; - } - - public void setRefundPer(float refundPer) { - this.refundPer = refundPer; - } - - public float getJoinCash() { - return joinCash; - } - - public void setJoinCash(float joinCash) { - this.joinCash = joinCash; - } - - public float getPointPer() { - return pointPer; - } - - public void setPointPer(float pointPer) { - this.pointPer = pointPer; - } - - public String getLasUpdusrId() { - return lasUpdusrId; - } - - public void setLasUpdusrId(String lasUpdusrId) { - this.lasUpdusrId = lasUpdusrId; - } - - public String getLastUpdtPnttm() { - return lastUpdtPnttm; - } - - public void setLastUpdtPnttm(String lastUpdtPnttm) { - this.lastUpdtPnttm = lastUpdtPnttm; - } - - public String getJoinCertType() { - return joinCertType; - } - - public void setJoinCertType(String joinCertType) { - this.joinCertType = joinCertType; - } - - public String getSmsNoti() { - return smsNoti; - } - - public void setSmsNoti(String smsNoti) { - this.smsNoti = smsNoti; - } - - public String getEmailNoti() { - return emailNoti; - } - - public void setEmailNoti(String emailNoti) { - this.emailNoti = emailNoti; - } - - public String getSlackNoti() { - return slackNoti; - } - - public void setSlackNoti(String slackNoti) { - this.slackNoti = slackNoti; - } - - public float getKakaoAtPrice() { - return kakaoAtPrice; - } - - public void setKakaoAtPrice(float kakaoAtPrice) { - this.kakaoAtPrice = kakaoAtPrice; - } - - public float getKakaoFtPrice() { - return kakaoFtPrice; - } - - public void setKakaoFtPrice(float kakaoFtPrice) { - this.kakaoFtPrice = kakaoFtPrice; - } - - public float getFaxPrice() { - return faxPrice; - } - - public void setFaxPrice(float faxPrice) { - this.faxPrice = faxPrice; - } - - public String getHoliSmishingNoti() { - return holiSmishingNoti; - } - - public void setHoliSmishingNoti(String holiSmishingNoti) { - this.holiSmishingNoti = holiSmishingNoti; - } } 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/KakaoSent_SQL_Mysql.xml b/src/main/resources/egovframework/sqlmap/let/mjo/kakao/KakaoSent_SQL_Mysql.xml index c8930144..c5119e08 100644 --- a/src/main/resources/egovframework/sqlmap/let/mjo/kakao/KakaoSent_SQL_Mysql.xml +++ b/src/main/resources/egovframework/sqlmap/let/mjo/kakao/KakaoSent_SQL_Mysql.xml @@ -909,7 +909,7 @@ + /* KakaoSentDAO.selectKakaoSentDetailViewPhoneAjax */ SELECT MGD.MSG_GROUP_ID as msgGroupId 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 4f1cfa20..654dd60a 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 @@ -72,12 +72,16 @@ , SMS_TXT , BIZ_KAKAO_TITLE + , AD_FLAG + , FILE_PATH1 , BIZ_KAKAO_RESEND_YN , BIZ_KAKAO_RESEND_DATA , BIZ_KAKAO_RESEND_TYPE , BIZ_KAKAO_JSON_FILE , REQ_DATE + + , FILE_CNT )VALUES ( @@ -95,12 +99,16 @@ , #[].templateContent# , #[].templateTitle# + , #[].adFlag# + , #[].filePath1# , #[].subMsgSendYn# , #[].subMsgTxt# , #[].subMsgType# , #[].bizJsonName# , #[].reqDate# + + , #[].fileCnt# ) @@ -131,6 +139,7 @@ REQ_DATE, MSG_GROUP_CNT, MSG_TYPE, + AD_FLAG, AGENT_CODE, EACH_PRICE, @@ -142,7 +151,8 @@ AT_DELAY_YN, BIZ_KAKAO_RESEND_ORGNL_TXT, - BIZ_KAKAO_RESEND_TYPE + BIZ_KAKAO_RESEND_TYPE, + BIZ_KAKAO_IMAGE_TYPE )VALUES ( #msgGroupId#, @@ -153,6 +163,7 @@ #reqDate#, #msgGroupCnt#, #msgType#, + #adFlag#, #agentCode#, #eachPrice#, @@ -164,7 +175,8 @@ #atDelayYn#, #bizKakaoResendOrgnlTxt#, - #bizKakaoResendType# + #bizKakaoResendType#, + #bizKakaoImageType# ) @@ -178,6 +190,7 @@ , BIZ_KAKAO_FT_WIDE_IMG_PRICE , BIZ_SMS_PRICE , BIZ_MMS_PRICE + , BIZ_PICTURE_PRICE ) VALUES ( @@ -188,14 +201,18 @@ ,#kakaoFtWideImgPrice# ,#smsPrice# ,#mmsPrice# + ,#picturePrice# ) - 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 , MMD.USERDATA AS userData , MMD.REFUND_YN AS refundYn , MMD.RSLT_CODE AS rsltCode @@ -205,42 +222,21 @@ , DATE_FORMAT(MMD.RSLT_DATE,'%Y-%m-%d %T') AS rsltDate , MMD.BIZ_KAKAO_RESEND_YN AS subMsgSendYn , 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 ON MMD.USER_ID = MB.MBER_ID + INNER JOIN mj_msg_group_data MMGD + on MMD.MSG_GROUP_ID = MMGD.MSG_GROUP_ID WHERE 1=1 AND MMD.CUR_STATE = '3' AND MMD.REFUND_YN = 'N' AND MMD.RESERVE_C_YN = 'N' - AND MMD.MSG_TYPE = 8 - - - + + {call kakaoAt_Send(#userId#, #msgGroupId#, #userData#)} @@ -271,7 +276,7 @@ - {call kakaoFt_Send(#userId#, #msgGroupId#, #userData#)} + {call kakaoFt_Send(#userId#, #msgGroupId#, #userData#, #fileCnt#, #bizKakaoResendType#, #bizKakaoImageType#)} diff --git a/src/main/resources/egovframework/sqlmap/let/mjo/kakao/Kakao_FT_SQL_Mysql.xml b/src/main/resources/egovframework/sqlmap/let/mjo/kakao/Kakao_FT_SQL_Mysql.xml index e2a3a345..1f9a1186 100644 --- a/src/main/resources/egovframework/sqlmap/let/mjo/kakao/Kakao_FT_SQL_Mysql.xml +++ b/src/main/resources/egovframework/sqlmap/let/mjo/kakao/Kakao_FT_SQL_Mysql.xml @@ -37,7 +37,7 @@ VALUES ( #friendId# , #userId# - , #bizJsonName# + , #atchFileId# , #templateName# , #imageFileName# , #templateImageUrl# @@ -200,6 +200,7 @@ A.IMAGE_TYPE AS imageType, A.IMAGE_TITLE AS imgTitle, A.IMAGE_LINK AS imgLink, + A.ATCH_FILE_ID AS atchFileId, A.TEMPLATE_CONTENTS AS templateContent, A.AD_FLAG AS adFlag, DATE_FORMAT(A.FRST_REGIST_PNTTM, '%Y-%m-%d %T') AS frstRegistPnttm, @@ -215,6 +216,7 @@ KFT.IMAGE_TYPE, KFT.IMAGE_TITLE, KFT.IMAGE_LINK, + KFT.ATCH_FILE_ID, KFT.TEMPLATE_CONTENTS, KFT.AD_FLAG, KFT.FRST_REGIST_PNTTM, diff --git a/src/main/resources/egovframework/sqlmap/let/msg/MjonMsgData_SQL_mysql.xml b/src/main/resources/egovframework/sqlmap/let/msg/MjonMsgData_SQL_mysql.xml index a531664e..08ef7a37 100644 --- a/src/main/resources/egovframework/sqlmap/let/msg/MjonMsgData_SQL_mysql.xml +++ b/src/main/resources/egovframework/sqlmap/let/msg/MjonMsgData_SQL_mysql.xml @@ -2151,6 +2151,8 @@ , POINT_PER AS pointPer , KAKAO_AT_PRICE AS kakaoAtPrice , KAKAO_FT_PRICE AS kakaoFtPrice + , KAKAO_FT_IMG_PRICE AS kakaoFtImgPrice + , KAKAO_FT_WIDE_IMG_PRICE AS kakaoFtWideImgPrice , FAX_PRICE AS faxPrice FROM MJ_MBER_SETTING @@ -2169,6 +2171,8 @@ , PICTURE3_PRICE AS picture3Price , KAKAO_AT_PRICE AS kakaoAtPrice , KAKAO_FT_PRICE AS kakaoFtPrice + , KAKAO_FT_IMG_PRICE AS kakaoFtImgPrice + , KAKAO_FT_WIDE_IMG_PRICE AS kakaoFtWideImgPrice , FAX_PRICE AS faxPrice , USER_MONEY AS userMoney , USER_POINT AS userPoint @@ -3601,9 +3605,9 @@ , SUM(IF(M.msgTypeName = '알림톡', 1, 0)) AS atSendCount , SUM(IF(M.msgTypeName = '친구톡', 1, 0)) AS ftSendCount - , ifnull(TRUNCATE(SUM(M.EACH_PRICE) , 0), 0) AS supplyPrice + , ifnull(TRUNCATE(SUM(M.EACH_PRICE) , 1), 0) AS supplyPrice , 0 AS vatPrice - , ifnull(TRUNCATE(SUM(M.EACH_PRICE) , 0), 0) AS totalPrice + , ifnull(TRUNCATE(SUM(M.EACH_PRICE) , 1), 0) AS totalPrice , M.MSG_TYPE FROM ( SELECT @@ -3641,8 +3645,6 @@ AND A.MSG_GROUP_ID = B.MSG_GROUP_ID AND A.USER_ID = #userId# AND B.USER_ID = #userId# - AND B.DEL_FLAG = 'N' - AND IFNULL(B.DEL_FLAG,'N') = 'N' AND B.RESERVE_C_YN = 'N' @@ -3670,6 +3672,9 @@ AND B.MSG_TYPE = '8' + + AND B.MSG_TYPE = '9' + ) M WHERE 1=1 @@ -3685,9 +3690,9 @@ , IFNULL(MIN(DATE_FORMAT(M.REQ_DATE, '%Y-%m-%d' )), 0) AS minRegDate , M.msgTypeName , IFNULL(SUM(SentEA), 0) AS ftSendCount - , ifnull(TRUNCATE(SUM(supplyPrice) , 0), 0) AS supplyPrice + , ifnull(TRUNCATE(SUM(supplyPrice) , 1), 0) AS supplyPrice , 0 AS vatPrice - , ifnull(TRUNCATE(SUM(M.TOT_PRICE) , 0), 0) AS totalPrice + , ifnull(TRUNCATE(SUM(M.TOT_PRICE) , 1), 0) AS totalPrice FROM ( SELECT pf.ReqDate AS REGDATE , pf.ReqDate AS REQ_DATE @@ -7435,6 +7440,17 @@ + + + UPDATE MJ_MSG_DATA + SET REFUND_YN = 'Y' + WHERE + USER_ID = #userId# + AND USERDATA = #userData# + AND MSG_GROUP_ID = #msgGroupId# + + + UPDATE @@ -8248,5 +8264,35 @@ + + + + + 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/msg/MjonMsgSent_SQL_mysql.xml b/src/main/resources/egovframework/sqlmap/let/msg/MjonMsgSent_SQL_mysql.xml index 752eec93..b93540e7 100644 --- a/src/main/resources/egovframework/sqlmap/let/msg/MjonMsgSent_SQL_mysql.xml +++ b/src/main/resources/egovframework/sqlmap/let/msg/MjonMsgSent_SQL_mysql.xml @@ -7,6 +7,7 @@ + @@ -389,7 +390,7 @@ - /* MjonMsgSentDAO.findByMsgDetailListAjax*/ SELECT diff --git a/src/main/resources/egovframework/sqlmap/let/pay/MjonPay_SQL_mysql.xml b/src/main/resources/egovframework/sqlmap/let/pay/MjonPay_SQL_mysql.xml index 15d5b3b8..66b242c2 100644 --- a/src/main/resources/egovframework/sqlmap/let/pay/MjonPay_SQL_mysql.xml +++ b/src/main/resources/egovframework/sqlmap/let/pay/MjonPay_SQL_mysql.xml @@ -3,10 +3,11 @@ ========= ======= ================================================= 2021.03.01 신명섭 --> - + + @@ -608,6 +609,7 @@ MEMO, ORDER_ID, MSG_GROUP_ID + )VALUES ( #userId#, @@ -626,6 +628,22 @@ + + + + INSERT INTO MJ_PG ( 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 b250df27..d2ca05c5 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/KaKaoAlimtalkSubMenuTap.jsp b/src/main/webapp/WEB-INF/jsp/web/kakao/include/KaKaoAlimtalkSubMenuTap.jsp index 57fc628d..391fbd4e 100644 --- a/src/main/webapp/WEB-INF/jsp/web/kakao/include/KaKaoAlimtalkSubMenuTap.jsp +++ b/src/main/webapp/WEB-INF/jsp/web/kakao/include/KaKaoAlimtalkSubMenuTap.jsp @@ -90,6 +90,6 @@ function fnLinkPageTab(tabInfo){
  • -
  • +
  • \ No newline at end of file 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 d0e25dd8..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,10 +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/msgdata/at/KakaoAlimtalkMsgDataView.jsp b/src/main/webapp/WEB-INF/jsp/web/kakao/msgdata/at/KakaoAlimtalkMsgDataView.jsp index d5b2e0da..754529ff 100644 --- a/src/main/webapp/WEB-INF/jsp/web/kakao/msgdata/at/KakaoAlimtalkMsgDataView.jsp +++ b/src/main/webapp/WEB-INF/jsp/web/kakao/msgdata/at/KakaoAlimtalkMsgDataView.jsp @@ -762,7 +762,7 @@ function sendTemplateInfo(){ // $('.loading_layer').removeClass('active'); // 프로그래스 바 종료 - progressComplete();; + progressComplete(); } ,error: function (e) { console.log("ERROR : ", e); diff --git a/src/main/webapp/WEB-INF/jsp/web/kakao/msgdata/ft/KakaoFriendsTalkMsgDataView.jsp b/src/main/webapp/WEB-INF/jsp/web/kakao/msgdata/ft/KakaoFriendsTalkMsgDataView.jsp index ab93209a..968da1ce 100644 --- a/src/main/webapp/WEB-INF/jsp/web/kakao/msgdata/ft/KakaoFriendsTalkMsgDataView.jsp +++ b/src/main/webapp/WEB-INF/jsp/web/kakao/msgdata/ft/KakaoFriendsTalkMsgDataView.jsp @@ -5,15 +5,17 @@ <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="ec" uri="/WEB-INF/tld/ecnet_tld.tld"%> <%@ page import="itn.com.cmm.LoginVO" %> - + - + - + + + @@ -1695,6 +1666,19 @@ function msgResultLink(){
    + +
    +
    +

    0%

    +
    + +
    +
    +
    +
    + +
    +
    @@ -1702,8 +1686,9 @@ function msgResultLink(){
    -

    친구톡 전송

    - +

    친구톡 전송

    + +
    @@ -1711,8 +1696,12 @@ function msgResultLink(){ + + + +
    @@ -1722,9 +1711,12 @@ function msgResultLink(){ - + + + + @@ -1753,9 +1745,8 @@ function msgResultLink(){ - - - + + @@ -1786,63 +1777,76 @@ function msgResultLink(){ 템플릿명 - -

    최대 50자, 템플릿 관리용

    +
    + + + + + + +
    이미지 첨부 -
    - checked > - checked > - checked > -
    -

    * 이미지 첨부 안내

    -
      -
    • - 권장사이즈 : 720px * 720px
    • + + + + + + + +
      +

      * 이미지 첨부 안내

      +
        +
      • - 권장사이즈 : 800px * 400px
      • - 제한사이즈 : 가로 500px 미만, 가로:세로 비율이 2:1 미만 또는 3:4 초과시 업로드 불가
      • -
      • - 파일형식 : jpg, png (최대 500kb)
      • -
      • - 이미지 첨부시 메시지 내용은 최대 400자까지 입력할 수 있습니다.
      • -
      -
      -
      -

      * 와이드 이미지 첨부 안내

      -
        -
      • - 권장사이즈 : 800px * 600px
      • - -
      • - 파일형식 : jpg, png (최대 2mb)
      • -
      • - 와이드 이미지 첨부시 메시지 내용은 최대 76자, 버튼 1개까지 입력할 수 있습니다.
      • -
      -
      -
    -
    -
      -
    • -

      이미지 제목

      - -
    • -
    • -

      이미지 클릭시 이동할 URL

      - -
    • -
    • -

      첨부파일 이미지

      - -
    • +
    • - 파일형식 : jpg, png (최대 5MB)
    • +
    • - 이미지 첨부 시 메시지 내용은 최대 400자, 버튼 5개까지 입력할 수 있습니다.
    - -
    +
    +

    * 와이드 이미지 첨부 안내

    +
      +
    • - 권장사이즈 : 800px * 600px
    • +
    • - 파일형식 : jpg, png (최대 5MB)
    • +
    • - 와이드 이미지 첨부시 메시지 내용은 최대 76자, 버튼 1개까지 입력할 수 있습니다.
    • +
    + + +
    +
      +
    • + + +
      +

      이미지 없음

      + +
      +
    • +
    • +

      이미지 클릭시 이동할 URL

      + +
    • +
    + 광고포함 여부 - checked > - <%-- checked > --%> + + @@ -1850,14 +1854,14 @@ function msgResultLink(){
    -
    -

    (광고) 채널ID

    +
    +

    (광고) 채널ID

    -
    -

    수신거부 : 홈 > 채널차단

    +
    +

    수신거부 : 홈 > 채널차단

    0 /1000

    @@ -1960,13 +1964,13 @@ function msgResultLink(){

    주소록, 엑셀에 입력된 내용을 이용해 수신자마다 다른 내용의 메시지를 발송하는 기능

    - +
    - - - - + + + +
    @@ -1980,25 +1984,16 @@ function msgResultLink(){
    - - - - - - - -
    - - - - - - - - - +
    @@ -2009,16 +2004,13 @@ function msgResultLink(){ -

    - * 버튼 타입중 봇키워드, 메시지전달카카오톡 채널 관리자센터(https://center-pf.kakao.com)에서 설정을 직접 한 후 이용하셔야 동작합니다. (최대 5개까지 등록가능) -

    -
    +
    @@ -2153,7 +2145,7 @@ function msgResultLink(){
    - + * 중복번호는 한번만 발송됩니다.
    @@ -2183,7 +2175,7 @@ function msgResultLink(){
    - +
    @@ -2191,13 +2183,13 @@ function msgResultLink(){
    -
    +
    @@ -2280,11 +2272,26 @@ function msgResultLink(){
    -
      - +
        + + +
      - + +
      +

      (광고)

      +
      +
      +
      +

      무료거부 0808800858

      +

      0 / @@ -2296,7 +2303,7 @@ function msgResultLink(){

      - +
      @@ -2310,7 +2317,7 @@ function msgResultLink(){
      -
      +

      @@ -2318,9 +2325,9 @@ function msgResultLink(){

      -

      - (광고) - 채널ID +

      + + (광고)

      - <%--
      +

      친구톡

      -

      +

      0

      대기
      -
      +
      0
      성공
      -
      +
      0
      실패
      -
      +
      0
      -
      --%> +
        -
      • active">
      • -
      • active">
      • - <%-- -
      • active">
      • -
        --%> +
      • +
      • +
      diff --git a/src/main/webapp/WEB-INF/jsp/web/kakao/template/ft/KakaoFriendstalkTemplateList.jsp b/src/main/webapp/WEB-INF/jsp/web/kakao/template/ft/KakaoFriendstalkTemplateList.jsp index 5e6bf1a3..3f03b04a 100644 --- a/src/main/webapp/WEB-INF/jsp/web/kakao/template/ft/KakaoFriendstalkTemplateList.jsp +++ b/src/main/webapp/WEB-INF/jsp/web/kakao/template/ft/KakaoFriendstalkTemplateList.jsp @@ -400,7 +400,8 @@ function fnGoSampleTemplate(){

      카카오톡 설정

      - + +
      @@ -436,7 +437,7 @@ function fnGoSampleTemplate(){
      - +
      diff --git a/src/main/webapp/WEB-INF/jsp/web/kakao/template/ft/KakaoFriendstalkTemplateListAjax.jsp b/src/main/webapp/WEB-INF/jsp/web/kakao/template/ft/KakaoFriendstalkTemplateListAjax.jsp index cdefd3a5..6615ecb6 100644 --- a/src/main/webapp/WEB-INF/jsp/web/kakao/template/ft/KakaoFriendstalkTemplateListAjax.jsp +++ b/src/main/webapp/WEB-INF/jsp/web/kakao/template/ft/KakaoFriendstalkTemplateListAjax.jsp @@ -132,7 +132,7 @@ $(function(){
      등록일
      - +<%-- --%>
      diff --git a/src/main/webapp/WEB-INF/jsp/web/msgdata/include/msgDataIncludeExcel.jsp b/src/main/webapp/WEB-INF/jsp/web/msgdata/include/msgDataIncludeExcel.jsp index 7561e7df..8ea20ea4 100644 --- a/src/main/webapp/WEB-INF/jsp/web/msgdata/include/msgDataIncludeExcel.jsp +++ b/src/main/webapp/WEB-INF/jsp/web/msgdata/include/msgDataIncludeExcel.jsp @@ -943,19 +943,6 @@ $(document).on('click', '#errorExcelBtn', function() {
      -
      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/WEB-INF/jsp/web/pop/kakaoFtPop.jsp b/src/main/webapp/WEB-INF/jsp/web/pop/kakaoFtPop.jsp new file mode 100644 index 00000000..b8a993da --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/web/pop/kakaoFtPop.jsp @@ -0,0 +1,30 @@ + +<%@ page contentType="text/html; charset=utf-8"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="ec" uri="/WEB-INF/tld/ecnet_tld.tld"%> + + + +
      + +
      +
        + +
      • 친구톡은 알림톡과 달리 별도의 템플릿 심사가 필요하지 않습니다.
      • +
      • 등록된 템플릿은 자유롭게 삭제가 가능합니다.
      • +
      • 문자온이 제공하지 않는 이모티콘, 이모지를 포함하여 템플릿을 등록할 경우, 친구톡 발송이 불가합니다.
      • +
      +
      +
      + \ No newline at end of file diff --git a/src/main/webapp/js/kakao/at/addr.js b/src/main/webapp/js/kakao/at/addr.js index 6463f4c7..8863488d 100644 --- a/src/main/webapp/js/kakao/at/addr.js +++ b/src/main/webapp/js/kakao/at/addr.js @@ -202,55 +202,63 @@ function addrToList_advc(type){ } function loadAddrList(){ - console.log(' loadAddrList() '); - /* - serialize 를 사용할때는 processData, contentType 옵션 제가할것 - */ - var data = $("#searchAddrGrpForm").serialize(); + /* + serialize 를 사용할때는 processDa ta, contentType 옵션 제가할것 + */ + var data = $("#searchAddrGrpForm").serialize(); - // var url = "/web/mjon/msgdata/selectMsgAddrListAjax.do"; var url = "/web/mjon/msgdata/selectMsgAddrListAjax_advc.do"; - - $.ajax({ + + $.ajax({ type: "POST", url: url, data: data, dataType:'json', - async: false, + async: true, cache: false, success: function (data) { - console.log('data : ', data); - if(data.status == "OK"){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나 - - var addrList = data.object; + console.log('data : ', data); + if(data.status == "OK"){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나 - if(addrList.length == 0){ + var addrList = data.object; - alert("주소록 정보가 없습니다."); -// tableAddr.setData([]); - return false; - } - tableAddr.setData(addrList); - } - else - { - alert("주소록 불러오기에 실패하였습니다. !!"); - } + if(addrList.length == 0){ + + alert("주소록 정보가 없습니다."); +// tableAddr.setData([]); + return false; + } + +// console.log('data : ', data); + tableAddr.setData(addrList); + } + else + { + alert("주소록 불러오기에 실패하였습니다. !!"); + } }, - error: function (e) { - alert("주소록 불러오기에 실패하였습니다."); console.log("ERROR : ", e); - } - , beforeSend : function(xmlHttpRequest) { - //로딩창 show + error: function (jqXHR, textStatus, errorThrown) { + alert("주소록 불러오기에 실패하였습니다."); + console.error("Error:", jqXHR.status, textStatus, errorThrown); + console.error("Response Text:", jqXHR.responseText); + try { + let json = JSON.parse(jqXHR.responseText); + console.log("Parsed JSON Response:", json); + } catch (e) { + console.error("JSON Parse Error:", e); + } + }, + beforeSend : function(xmlHttpRequest) { + //로딩창 show $('.loading_layer').addClass('active'); - } - , complete : function(xhr, textStatus) { + }, + complete : function(xhr, textStatus) { //로딩창 hide $('.loading_layer').removeClass('active'); } }); - + } function fnAddrSearch(){ diff --git a/src/main/webapp/js/kakao/ft/addr.js b/src/main/webapp/js/kakao/ft/addr.js new file mode 100644 index 00000000..2962a0e8 --- /dev/null +++ b/src/main/webapp/js/kakao/ft/addr.js @@ -0,0 +1,538 @@ +$(document).on('click', '.addressregi_btn', function() { + var tableData = tableL.getRows(); + var dataLen = tableL.getRows().length; + if(dataLen == 0){ + alert("연락처 정보를 등록해 주세요."); + return false; + }else{ + $('.addressregi_layer').css({'width':'680px','display':'block','left':'50%','top':'50%','transform':'translate(-50%,-50%)'}); + setTimeout(function(){ + $('.addressregi_layer').css({'opacity':'1'}); + },150); + $('.mask').addClass('on'); + getAddrGroupList(); + } +}); + +$(document).on('click', '.addressregi_layer .tooltip-close', function() { + $('.addressregi_layer').attr('style',''); + $("#addrGrpNm").val(""); +}); + +$(document).on('change', '#addrGrpIdInfo', function() { + if ($("#addrGrpIdInfo option:selected").val() != "NEW") { + $("#addrGrpNm").val(""); // 새그룹명 Clear; + } +}); + +//주소록 그룹정보 불러오기 +function getAddrGroupList() { + $.ajax({ + type : "POST", + async : false, + url : "/web/mjon/addr/addrGroupListAjax.do", + data : {}, + dataType:'json', + success : function(data) { + //alert(JSON.stringify(data.addrGroupList)); + + // Show Html + getAddrGroupListShow(data.addrGroupList); + }, + error : function(xhr, status, error) { + alert(error); + return false; + } + }); +} + +//Show Html +function getAddrGroupListShow(jsonList) { + var sHtml = ""; + sHtml += ""; + sHtml += ""; + sHtml += ""; + for (var j = 0; j < jsonList.length; j++) { + sHtml += " "; + } + + $("#addrGrpIdInfo").html(sHtml); +} + +//주소록 그룹 중복체크 +function getAddrGroupDuplCheckAjax(addrGrpNm) { + console.log('addrGrpNm : ', addrGrpNm) + console.log('getAddrGroupDuplCheckAjax()') + var isReturn = true; + + $.ajax({ + url : "", + type : 'POST', + data : {"addrGrpNm" : addrGrpNm}, + dataType:'json', + async: false, // 동기 + success : function(data, status){ + if(data.isSuccess == true) { + if(data.isDupl == true) { + //alert("중복된 그룹명입니다."); + isReturn = false; + } + } + else { + //alert("Message : " + msg); + } + }, + error: function (e) { + //alert("주소록 중복체크에 실패했습니다."); + } + }); + + return isReturn; +} + +//주소록 팝업 닫기 기능 +function addrClose(){ + + $(".closeAddr").trigger("click"); + + //주소록 레이어 팝업의 Tabulator 데이터 지워주기 + tableAddr.clearData(); + +} + +//주소록 불러오기에서 수신자 리스트 추가해 주기 +/* +function addrToList(){ + + var selectedData = tableAddr.getSelectedRows(); + var tableData = []; + + if(selectedData == "" || selectedData == null){ + + alert("주소록을 선택해 주세요."); + return false; + + }else{ // 선택한 Row 데이터 저장해주기 + + // 선택한 Row 데이터 저장해주기 +// if(selectedData.length > 500){ +// alert("최대 발송 건수는 500 입니다."); +// return false; +// }else{ + for(var i=0; i < selectedData.length; i++){ + + //좌측 받는사람 리스트를 담아둔 배열에 데이터를 추가해 준다. + tableData.push({ + phone: removeDash(selectedData[i].getData().addrPhone) + , name: selectedData[i].getData().addrName + // , rep1: selectedData[i].getData().addrRep1 + // , rep2: selectedData[i].getData().addrRep2 + // , rep3: selectedData[i].getData().addrRep3 + // , rep4: selectedData[i].getData().addrRep4 + }); + + } + //선택한 데이터 받는사람 리스트에 추가해 주기 + addPhoneInfo(tableData); + $(".closeAddr").trigger("click"); + + //주소록 레이어 팝업의 Tabulator 데이터 지워주기 + tableAddr.clearData(); +// } + } + +} +*/ + +//주소록 불러오기에서 수신자 리스트 추가해 주기 +function addrToList_advc(type){ + + + // 선택된 데이터 또는 전체 데이터 변수 초기화 + let selectedData = type === 'select' ? tableAddr.getSelectedRows() : tableAddr.getData(); + + // 데이터가 비어있으면 경고 후 종료 + if (!selectedData || selectedData.length < 1) { + + if(tableAddr.getDataCount() < 1){ + alert("주소록을 선택해 주세요."); + }else{ + alert("전화번호를 선택해 주세요."); + } + + return false; + } + + + // 데이터 변환 로직 + const addrData = selectedData.map(row => { + const rowData = type === 'select' ? row.getData() : row; // 'select'는 행 객체에서 데이터 추출 + return { + name: rowData.name, + phone: removeDash(rowData.phone), + rep1: rowData.rep1, + rep2: rowData.rep2, + rep3: rowData.rep3, + rep4: rowData.rep4 + }; + }) + .filter(row => checkHpNum(row.phone)); // 유효한 번호만 필터링; + + + // 기존 tableL의 데이터를 가져옵니다. + var existingData = tableL.getData(); + // 기존 데이터와 새로운 데이터를 합칩니다. + var combinedData = existingData.concat(addrData); + + // @ phone을 기준으로 중복 제거 및 갯수 계산 + const result = removeDuplicatesAndCount(combinedData, 'phone'); + + + + // 총 30만건이 넘으면 false + if (!validateRowLimit(result.uniqueCount)) { + return false; + } + + setAllCntData(result); + + + // 미리보기 버튼 활성화 + + + $(".closeAddr").trigger("click"); + //주소록 레이어 팝업의 Tabulator 데이터 지워주기 + tableAddr.clearData(); + //결제 금액 구하기 + totalFtPriceSum(tableL.getRows().length); + // fn_priceClclt(result.uniqueCount); +} + +function loadAddrList(){ + + /* + serialize 를 사용할때는 processDa ta, contentType 옵션 제가할것 + */ + var data = $("#searchAddrGrpForm").serialize(); + + var url = "/web/mjon/msgdata/selectMsgAddrListAjax_advc.do"; + + $.ajax({ + type: "POST", + url: url, + data: data, + dataType:'json', + async: true, + cache: false, + success: function (data) { + console.log('data : ', data); + if(data.status == "OK"){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나 + + var addrList = data.object; + + if(addrList.length == 0){ + + alert("주소록 정보가 없습니다."); +// tableAddr.setData([]); + return false; + } + +// console.log('data : ', data); + tableAddr.setData(addrList); + } + else + { + alert("주소록 불러오기에 실패하였습니다. !!"); + } + }, + error: function (jqXHR, textStatus, errorThrown) { + alert("주소록 불러오기에 실패하였습니다."); + console.error("Error:", jqXHR.status, textStatus, errorThrown); + console.error("Response Text:", jqXHR.responseText); + try { + let json = JSON.parse(jqXHR.responseText); + console.log("Parsed JSON Response:", json); + } catch (e) { + console.error("JSON Parse Error:", e); + } + }, + beforeSend : function(xmlHttpRequest) { + //로딩창 show + $('.loading_layer').addClass('active'); + }, + complete : function(xhr, textStatus) { + //로딩창 hide + $('.loading_layer').removeClass('active'); + } + }); + +} + +function fnAddrSearch(){ + + var form = document.searchAddrGrpForm; + form.searchKeyword.value = form.searchAddrKeyword.value; + form.searchCondition.value = form.searchAddrCondition.value; + + loadAddrList(); + +} + +//주소록 불러오기 팝업의 그룹 선택시 우측에 주소록 불러오기 +function fnSelectAddrList(type,addrGrpId,item){ + + // 주소록 그룹 열림, 닫힘 폴더이미지 초기화 + $(".adr_pop_list div p").each(function (index, item) { + $(item).find("img").attr("src", "/publish/images/content/close_folder2.png"); + $(item).find("img").attr("alt", "폴더 닫힘"); + }); + + var form = document.searchAddrGrpForm; + form.type.value = type; + form.searchAddrGrpId.value = addrGrpId; + form.searchKeyword.value = ""; + form.searchCondition.value = form.searchAddrCondition.value; + + //왼쪽 그룹리스트의 그룸명을 선택시 검색어를 초기화해준다. + form.searchAddrKeyword.value=""; + + /* + $(item).toggleClass("open"); + if ($(item).hasClass("open") === true) { + $(item).find("img").attr("src", "/publish/images/content/open_folder2.png"); + $(item).find("img").attr("alt", "폴더 열림"); + } + else { + $(item).find("img").attr("src", "/publish/images/content/close_folder2.png"); + $(item).find("img").attr("alt", "폴더 닫힘"); + } + */ + + $(item).find("img").attr("src", "/publish/images/content/open_folder2.png"); + $(item).find("img").attr("alt", "폴더 열림"); + + loadAddrList(); + +} + +//주소록 불러오기 그룹명 검색 기능처리 +function fnAddrGrpSearch(){ + + var form = document.searchAddrGrpForm; + form.searchKeyword.value = form.searchGrpKeyword.value; + form.searchCondition.value = ""; + + var sendData = $(document.searchAddrGrpForm).serializeArray(); + + $("#addrGroupLoad").load("/web/mjon/msgdata/selectAddrGroupListAjax.do", sendData ,function(response, status, xhr){ + //리스트 스크롤 처리해주기 + $(".adr_pop_list").mCustomScrollbar({ + axis: 'y', + scrollbarPosition: "outside", + theme: "dark", + autoHideScrollbar: false + }); + }); + +} +/* +//문자발송 받는사람 목록 주소록에 등록하기 기능 처리 +$('.registAddr').click(function(){ + + var tableData = tableL.getRows(); + var dataLen = tableL.getRows().length; + + var nameList = []; //치환문자 이름 + var phoneNum = []; //받는사람 + var rep1List = []; //치환문자1 + var rep2List = []; //치환문자2 + var rep3List = []; //치환문자3 + var rep4List = []; //치환문자4 + + if(dataLen > 0){ + + for(var i=0; i < dataLen; i++){ + + var name = tableData[i].getData().name; + var phone = removeDash(tableData[i].getData().phone); + var rep1 = tableData[i].getData().rep1; + var rep2 = tableData[i].getData().rep2; + var rep3 = tableData[i].getData().rep3; + var rep4 = tableData[i].getData().rep4; + + if(phone == "" || phone == null){ + + alert("수신 목록에 핸드폰 번호가 없는 항목이 있습니다."); + return false; + + }else if(!checkHpNum(phone)){ + + alert("수신 목록에 잘 못된 핸드폰 번호가 있습니다. 핸드폰 번호 : " + phone + " 입니다."); + return false; + + } + + nameList[i] = name; + phoneNum[i] = phone; + + if(rep1 == "" || rep1 == null){ + rep1List[i] = "-"; + }else{ + rep1List[i] = rep1; + } + + if(rep2 == "" || rep2 == null){ + rep2List[i] = "-"; + }else{ + rep2List[i] = rep2; + } + + if(rep3 == "" || rep3 == null){ + rep3List[i] = "-"; + }else{ + rep3List[i] = rep3; + } + + if(rep4 == "" || rep4 == null){ + rep4List[i] = "-"; + }else{ + rep4List[i] = rep4; + } + + if(name == "" || name == null){ + + alert("수신 목록에 이름이 없는 항목이 있습니다. 이름을 입력해 주세요"); + return false; + + }else{ + + nameList[i] = name; + phoneNum[i] = phone; + + if(rep1 == "" || rep1 == null){ + rep1List[i] = "-"; + }else{ + rep1List[i] = rep1; + } + + if(rep2 == "" || rep2 == null){ + rep2List[i] = "-"; + }else{ + rep2List[i] = rep2; + } + + if(rep3 == "" || rep3 == null){ + rep3List[i] = "-"; + }else{ + rep3List[i] = rep3; + } + + if(rep4 == "" || rep4 == null){ + rep4List[i] = "-"; + }else{ + rep4List[i] = rep4; + } + + } + + } + + //주소록 정보를 Form에 넣어준다. + + var form = document.msgForm; + form.callToList.value = phoneNum; + form.nameList.value = nameList; + form.rep1List.value = rep1List; + form.rep2List.value = rep2List; + form.rep3List.value = rep3List; + form.rep4List.value = rep4List; + form.addrGrpId.value = $("#addrGrpIdInfo").val(); + form.addrGrpNm.value = $("#addrGrpNm").val(); + + if ($("#addrGrpIdInfo option:selected").val() == "NEW" && ($("#addrGrpNm").val() == "" || $("#addrGrpNm").val() == null || $("#addrGrpNm").val() == undefined)) { + alert("저장할 그룹을 선택하거나 새 그룹명을 입력해주세요."); + return false; + }else if ($("#addrGrpIdInfo option:selected").val() == "NEW" && $("#addrGrpNm").val() != "") { + //주소록 중복체크 + if (getAddrGroupDuplCheckAjax() == false) { + alert("중복된 그룹명입니다. 새 그룹명을 입력해주세요."); + return false; + } + } + if(confirm("연락처 정보를 주소록에 등록 하시겠습니까?")){ + + var data = new FormData(form); + var url = "/web/mjon/msgdata/insertMsgAddrListAjax.do"; + + $.ajax({ + type: "POST", + enctype: 'multipart/form-data', + url: url, + data: data, + dataType:'json', + async: true, + processData: false, + contentType: false, + cache: false, + //timeout: 600000, + success: function (returnData, status) { + if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나 + + if(returnData.result == "success"){ + var alertMsg = "총 " + returnData.resultCnt + "건의 " +returnData.message; + + if(returnData.dupliCnt > 0) { + alertMsg += "\n"+numberWithCommas(returnData.dupliCnt) + "건은 이미 등록되어있는 번호입니다."; + } + + alert(alertMsg); + $("#addrGrpNm").val(""); + $('.addressregi_layer').attr('style',''); + $('.mask').removeClass('on'); + return false; + + }else if(returnData.result == "allDupl") { + alert("요청하신 "+returnData.dupliCnt+"건의 번호가 주소록에 이미 등록되어있습니다."); + $("#addrGrpNm").val(""); + $('.addressregi_layer').attr('style',''); + $('.mask').removeClass('on'); + return false; + }else{ + alert(returnData.message); + $("#addrGrpNm").val(""); + $('.addressregi_layer').attr('style',''); + $('.mask').removeClass('on'); + return false; + + } + + } else if(status== 'fail'){ + alert("주소록 등록에 실패하였습니다. !!"); + } + }, + error: function (e) { + alert("주소록 등록에 실패하였습니다."); + console.log("ERROR : ", e); + }, + beforeSend : function(xmlHttpRequest) { + //로딩창 show + $('.loading_layer').addClass('active'); + }, + complete : function(xhr, textStatus) { + //로딩창 hide + $('.loading_layer').removeClass('active'); + } + }); + + } + + }else{ + + alert("연락처 정보를 등록해 주세요."); + return false; + + } + + +}); +*/ diff --git a/src/main/webapp/js/kakao/ft/ftPriceClclt.js b/src/main/webapp/js/kakao/ft/ftPriceClclt.js index 6a55e149..a55d9c00 100644 --- a/src/main/webapp/js/kakao/ft/ftPriceClclt.js +++ b/src/main/webapp/js/kakao/ft/ftPriceClclt.js @@ -13,6 +13,18 @@ * */ +//카카오 mms sms 단가 셋팅 +var KAKAO_FT_PRICE = ''; +var SHORT_PRICE = ''; +var LONG_PRICE = ''; +$('document').ready(function(){ + + KAKAO_FT_PRICE = Number($('#kakaoFtPrice').val()); + SHORT_PRICE = Number($('#shortPrice').val()); + LONG_PRICE = Number($('#longPrice').val()); + console.log('SHORT_PRICE: ', SHORT_PRICE); + console.log('LONG_PRICE: ', LONG_PRICE); +}); /** * @@ -21,67 +33,59 @@ * 대체 문자 X * 카카오 금액 * 수신자 수 계산 */ -function totalFtPriceSum(totRows){ - - var collNumCnt = parseInt(totRows); //받는사람 건수 - var price = $("#kakaoFtPrice").val(); //개별 건수 금액 - var totalPrice = 0; //전체 금액 - var totalStr = "0"; //전체 합계 금액 - var userMoney = $('#hdUserMoney').text(); //헤더 영역 보유 금액 불러오기 - - if(!userMoney > 0){ - - userMoney = 0; - - } - //헤더 영역 보유 금액 콤마 문자 제거 - if(userMoney != ''){ - - userMoney = userMoney.replaceAll("," , ""); - - } - - //대체문자가 있는 경우 대체문자의 단/장문에 따른 금액 계산 - var subMsgSts = $("#send_fail_check").is(":checked"); - - if(subMsgSts){ - - var conLeng = conByteLeng($('#smsTxtArea').val()); // 내용 문자 입력 바이트 수 계산하기 - if(conLeng > 90){ - price = $("#longPrice").val(); - }else{ - price = $("#shortPrice").val(); +function totalFtPriceSum(totRows) { + console.log(' :totalFtPriceSum: '); + // 수신자 수 계산 + var count = parseInt(totRows); + + // 기본 단가는 일반 친구톡 이미지 없는 가격 + var price = KAKAO_FT_PRICE; + + // 선택된 이미지 유형에 따라 단가 변경 + var imgTypeId = $("input[name='img_file_add']:checked").attr("id"); + if (imgTypeId === "img_file_1") price = KAKAO_FT_IMG_PRICE; + else if (imgTypeId === "img_file_2") price = KAKAO_FT_WIDE_IMG_PRICE; + + // 대체문자 발송 옵션이 체크된 경우, 메시지 종류별로 단가 재계산 + if ($("#send_fail_check").is(":checked")) { + if (imgTypeId === "img_file_0") { + // 장문/단문 여부에 따라 가격 비교 후 더 큰 값으로 설정 + + var contents = adYChkAndMakeContents($('#smsTxtArea').val()); + + var len = conByteLeng(contents); + var long = parseFloat($("#longPrice").val()); + var short = parseFloat($("#shortPrice").val()); + price = Math.max(price, len > 90 ? long : short); + } else { + // 이미지 대체문자의 경우 별도 이미지 가격과 비교 + var picture = parseFloat($('#picturePrice').val()); + price = Math.max(price, picture); } - } - - totalPrice = price * collNumCnt; - - // 소수점 첫째자리 까지 표시 - totalPrice = totalPrice.toFixed(1); - - if(totalPrice > 0){ - - //totalStr = totalPrice.toFixed(2); - totalStr = totalPrice; - - } - - //개별 문자 단가 파라미터에 입력 + + // 총 금액 계산 (단가 * 수신자 수) + var totalPrice = (price * count).toFixed(1); + var totalStr = totalPrice > 0 ? totalPrice : "0"; + + // 사용자 보유 금액 텍스트에서 콤마 제거 (표시 용도일 뿐 실제 계산엔 안 씀) + var userMoney = $('#hdUserMoney').text().replaceAll(",", "") || 0; + + // 개별 단가, 총 금액을 input/화면에 반영 $('#eachPrice').val(numberWithCommas(price)); - - //결제금액 합계 파라이터에 입력 $('#totPrice').val(numberWithCommas(totalStr)); - - //결제금액 합계 화면에 표시 $('#totalPriceTxt').text(numberWithCommas(totalStr)); - - $('#repPriceTxt').hide(); - - return totalStr; - + $('#repPriceTxt').hide(); // 기존 합계 표시 숨김 + + return totalStr; // 계산된 총 금액 반환 } +function adYChkAndMakeContents(contents){ + if ($("#ad_Y").is(":checked")) { + contents = "(광고)"+contents+"\n무료거부 0808800858" + } + return contents; +} /* @@ -89,10 +93,6 @@ function totalFtPriceSum(totRows){ * * */ -//카카오 mms sms 단가 셋팅 -var KAKAO_FT_PRICE = ''; -var SHORT_PRICE = ''; -var LONG_PRICE = ''; /*$(document).ready(function(){ @@ -153,14 +153,17 @@ var LONG_PRICE = ''; /** * @description 금액 계산 function */ -function fn_priceClclt(){ +function fn_priceClclt(phoneSu = 0){ + console.log('fn_priceClclt : ', phoneSu); // 미리보기 텍스트 var templateHtml = $('#smsTxtArea').val(); // var templateHtml = $('.template_text').html(); // 수신 번호 개수 - var phoneSu = $('.phoneArea').length; + if(phoneSu == 0){ + phoneSu = $('.phoneArea').length; + } // 대체문자 있는지 확인 var isSendFailChecked = $("#send_fail_check").is(":checked"); // 치환문자 여부 확인 @@ -183,12 +186,13 @@ function fn_priceClclt(){ * 카카오 금액 * 수신자 수 계산 */ function fn_sendFailUnChecked(phoneSu){ + console.log('phoneSu; ', phoneSu); // 카카오 금액 * 수신자 수 // fn_writePriceText() 첫 파라미터가 null이면 카카오 전송으로 인식 fn_writePriceText('', phoneSu); // $('#totalPriceTxt').text((KAKAO_AT_PRICE * phoneSu).toFixed(1)); - fn_priceText('알림톡', phoneSu); + fn_priceText('친구톡', phoneSu); } /** @@ -279,9 +283,9 @@ function fn_writePriceText(msgTypeText, phoneSu){ msgTypeText = msgTypeText.trim(); if(msgTypeText == '단문') price = SHORT_PRICE * phoneSu; else if(msgTypeText == '장문') price = LONG_PRICE * phoneSu; - else price = KAKAO_AT_PRICE * phoneSu; // 카카오 + else price = KAKAO_FT_PRICE * phoneSu; // 카카오 - $('#totalPriceTxt').text((price).toFixed(1)); + $('#totalPriceTxt').text(numberWithCommas((price).toFixed(1))); } diff --git a/src/main/webapp/js/kakao/ft/ftTabulator.js b/src/main/webapp/js/kakao/ft/ftTabulator.js index 537eef95..763ba41e 100644 --- a/src/main/webapp/js/kakao/ft/ftTabulator.js +++ b/src/main/webapp/js/kakao/ft/ftTabulator.js @@ -20,40 +20,41 @@ $(document).ready(function (){ tableL = new Tabulator(".callList_box", { height:"255px", layout:"fitColumns", - //data:tabledata, - //autoColumns:true, headerHozAlign:"center", validationMode:"highlight", - //clipboard:false, - //clipboardCopySelector:"table", - //clipboardPasteAction:"insert", // insert, update, replace placeholder:"복사(Ctrl+C)한 내용을 여기에 붙여넣기(Ctrl+V) 해주세요.", //fit columns to width of table (optional) resizableColumns:false, + columnDefaults:{ // 공통설정 + hozAlign: "center", + headerHozAlign: "center", + editor: false, + editor: false + }, columns:[ //Define Table Columns - {formatter:"rowSelection", titleFormatter:"rowSelection",clipboard:false, hozAlign:"center", headerSort:false, cellClick:function(e, cell){ - cell.getRow().toggleSelect(); - }}, - {title:"이름", hozAlign:"center", field:"name", editor:"input", validator:["maxLength:12"], cellEdited:function(cell){ + {formatter:"rowSelection", headerHozAlign:"center", titleFormatter:"rowSelection",clipboard:false, hozAlign:"center", width:5, headerSort:false, cellClick:function(e, cell){ + cell.getRow().toggleSelect(); + }}, + {title:"이름", hozAlign:"center", field:"name", validator:["maxLength:12"], cellEdited:function(cell){ //cell - cell component fnReplCell(); }}, - {title:"휴대폰", hozAlign:"center", field:"phone", editor:"input", width:100, validator:["required","minLength:10", "maxLength:12"], cellEdited:function(cell){ + {title:"휴대폰", hozAlign:"center", field:"phone", width:100, validator:["required","minLength:10", "maxLength:12"], cellEdited:function(cell){ //cell - cell component fnDuplPhone(); }}, - {title:"[*1*]", hozAlign:"center", field:"rep1", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){ + {title:"[*1*]", hozAlign:"center", field:"rep1", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){ //cell - cell component fnReplCell(); }}, - {title:"[*2*]", hozAlign:"center", field:"rep2", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){ + {title:"[*2*]", hozAlign:"center", field:"rep2", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){ //cell - cell component fnReplCell(); }}, - {title:"[*3*]", hozAlign:"center", field:"rep3", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){ + {title:"[*3*]", hozAlign:"center", field:"rep3", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){ //cell - cell component fnReplCell(); }}, - {title:"[*4*]", hozAlign:"center", field:"rep4", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){ + {title:"[*4*]", hozAlign:"center", field:"rep4", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){ //cell - cell component fnReplCell(); }}, @@ -88,7 +89,7 @@ $(document).ready(function (){ }); - + /* //주소록 불러오기 팝업 내용 //Tabulator AJAX Data Loading tableAddr = new Tabulator(".callAddr_box", { @@ -126,7 +127,61 @@ $(document).ready(function (){ return value % parameters.addrPhone; }, - }); + });*/ + + + // Tabulator 초기화 + tableAddr = new Tabulator(".callAddr_box", { + height: "255px", + layout: "fitData", + headerHozAlign: "center", + validationMode: "highlight", + resizableColumns: true, + progressiveLoad:"scroll", + progressiveRender: true, // 렌더링 최적화 활성화 + progressiveRenderSize: 100, // 한 번에 렌더링할 행 수를 줄임 + placeholder: "주소록 그룹을 선택해 주세요.", + columns: [ +// {formatter: "rowSelection", clipboard: false, hozAlign: "center", headerSort: false}, + {formatter: "rowSelection", titleFormatter: "rowSelection", hozAlign: "center", headerSort: false, + cellClick: function(e, cell) { + fn_loadAddActive(); // 로딩 활성화 + setTimeout(() => { + tableAddr.blockRedraw(); // 렌더링 차단 + cell.getRow().toggleSelect(); // 선택 상태 토글 + tableAddr.restoreRedraw(); // 렌더링 재개 + fn_loadRemoveActive(); // 로딩 비활성화 + }, 0); // 비동기적으로 실행 + } + }, + {title: "No", hozAlign: "center", formatter: "rownum", align: "center", headerHozAlign: "center", width: 60}, + {title: "그룹명", hozAlign: "center", field: "addrGroupNm", editor: false, width: 100}, + {title: "이름", hozAlign: "center", field: "name", editor: false, width: 100}, + {title: "휴대폰번호", hozAlign: "center", field: "phone", editor: false, width: 100}, + {title: "[*1*]", hozAlign: "center", field: "rep1", editor: false, width: 84}, + {title: "[*2*]", hozAlign: "center", field: "rep2", editor: false, width: 84}, + {title: "[*3*]", hozAlign: "center", field: "rep3", editor: false, width: 84}, + {title: "[*4*]", hozAlign: "center", field: "rep4", editor: false, width: 84}, + ], + validationFailed: function(cell, value, parameters) { + var valid = cell.isValid(); + var fieldNm = cell.getField(); + if (!valid) { + if (fieldNm == "addrName") { + alert("받는사람 이름은 최대 12글자까지만 입력 가능합니다."); + } else if (fieldNm == "addrPhone") { + alert("휴대폰번호는 하이픈(-)을 제외한 숫자만 정확히 입력해 주세요."); + } else if (fieldNm == "addrGroupNm") { + alert("그룹명을 정확히 입력해 주세요. 2 ~ 40글자 이내로 입력 가능합니다."); + } else { + alert("치환문자를 정확히 입력해 주세요. 100글자 이내로 입력 가능합니다."); + } + cell.setValue(""); + } + console.log('parameters : ', parameters); + return value % parameters.addrPhone; + }, + }); //받는사람 번호 버튼 클릭시 Tabulator에 데이터 넣어주기 @@ -186,6 +241,9 @@ $(document).ready(function (){ addPhoneInfo(tabledata); $('#callTo').val(""); + + + fn_priceText('친구톡', tableL.getDataCount()); } @@ -496,6 +554,210 @@ $(document).ready(function (){ }); + + + + + //받는사람 목록에 복사/붙여넣기 기능 처리 + $('.callList_box').on('paste', function (e) { + console.log(' :: callList _box :: '); + + var element = e.originalEvent.clipboardData.getData('text'); // 클립보드에 복사한 데이터 가져오기 + + var elmSplit= []; + + elmSplit = element.split("\n"); + + var elmLen = elmSplit.length; + + + if(elmLen < 0){ + + alert("붙여넣을 연락처를 복사해주세요."); + return false; + + }else{ + tableErrorData.length = 0; // 오류 번호 배열 초기화 + + var splitData = []; + var realPhone = []; + for(var i=0; i < elmLen; i++){ + + var splitStr = elmSplit[i]; + var tabData = []; + var comData = []; + + if(splitStr.indexOf('\t') != -1){ + splitData = splitStr.split('\t'); //탭 구분으로 데이터 분할 + }else if(splitStr.indexOf(',') != -1){ + splitData = splitStr.split(','); //콤마 구분으로 데이터 분할 + }else{ + splitData = splitStr.split(' '); + } + + + if(splitData.length == 0){// 데이터가 없는경우 + + alert("탭으로 구분하여 데이터를 복사해 주세요."); + return false; + + }else if(splitData.length == 1){// 데이터가 탭으로 구분이 없는 경우 + + for(var j=0; j < splitData.length; j++){ + if(checkHpNum(splitData[j].trim())){//핸드폰 양식이 맞는지 확인 + //배열 끝에 데이터 추가해 주기 + realPhone.push({phone: removeDash(splitData[j].trim()), name: ""}); + } + else { + if (splitData[j].trim() != '' && splitData[j].trim() != null && splitData[j].trim() != undefined) { + tableErrorData.push(splitData[j].trim()); + } + } + } + + }else{//데이터가 탭으로 구분되어 이름, 연락처로 구분된 경우 + + var phone = ""; //핸드폰번호 + var name = ""; //이름 + var rep1 = ""; //치환문자1 + var rep2 = ""; //치환문자2 + var rep3 = ""; //치환문자3 + var rep4 = ""; //치환문자4 + var isPhoneValid = false; + for(var j=0; j < splitData.length; j++){ + + if(j == 0){ + + name = splitData[j].trim(); + + } + + if(j == 1){ + + if(checkHpNum(splitData[j].trim())){//핸드폰 양식이 맞는지 확인 + phone = removeDash(splitData[j].trim()); + isPhoneValid = true; + }else{ + if (splitData[j].trim() != '' && splitData[j].trim() != null && splitData[j].trim() != undefined) { + tableErrorData.push(splitData[j].trim()); + } + } + + } + + if(j == 2){ //치환문자1 + + rep1 = splitData[j].trim(); + + } + + if(j == 3){ //치환문자2 + + rep2 = splitData[j].trim(); + + } + + if(j == 4){ //치환문자3 + + rep3 = splitData[j].trim(); + + } + + if(j == 5){ //치환문자4 + + rep4 = splitData[j].trim(); + + } + + } + + if (isPhoneValid == true) { + //배열 끝에 데이터 추가해 주기 + realPhone.push({phone: phone, name: name, rep1 : rep1, rep2 : rep2, rep3 : rep3, rep4 : rep4 }); + } + + }//else end + + } + + var recTableData = tableL.getRows(); // 받는사람 리스트의 전체 목록을 저장 + var tableData = []; + + //기존 받는사람 리스트를 배열에 미리 담아둔다. + if(recTableData.length > 0){ + + for(var j=0; j < recTableData.length; j++){ + + tableData.push({phone: removeDash(recTableData[j].getData().phone.trim()) , name: recTableData[j].getData().name, rep1: recTableData[j].getData().rep1, rep2: recTableData[j].getData().rep2, rep3: recTableData[j].getData().rep3, rep4: recTableData[j].getData().rep4, }); + + } + + } + + if(realPhone.length > 0){ + + for(var j=0; j < realPhone.length; j++){ + + tableData.push({phone: removeDash(realPhone[j].phone.trim()) , name: realPhone[j].name, rep1: realPhone[j].rep1, rep2: realPhone[j].rep2, rep3: realPhone[j].rep3, rep4: realPhone[j].rep4}); + + } + + } + + //tableData.push(realPhone); + + //중복 연락처 1개만 남기고 삭제하기 + var removeDuplPhone = dupliPhoneData(tableData); + + //수신자 리스트에 전화번호 추가해주기 + //tableL.addData(removeDuplPhone); + tableL.setData(removeDuplPhone); + + totRows = tableL.getRows().length; + updateTotCnt(totRows); //전체 데이터 갯수 구하기 + + var smsTxtArea = $('#smsTxtArea').val(); + + //일괄변환 문구 결제금액 처리 + if(smsTxtArea.indexOf("[*이름*]") > -1 + || smsTxtArea.indexOf("[*1*]") > -1 + || smsTxtArea.indexOf("[*2*]") > -1 + || smsTxtArea.indexOf("[*3*]") > -1 + || smsTxtArea.indexOf("[*4*]") > -1){ + + fnReplCell_advc(); + }else{ + //결제 금액 구하기 +// totalPriceSum(totRows); + // 붙여넣기 했을때 금액 구하는 함수 + totalFtPriceSum(totRows); + } + + if (tableErrorData.length > 0) { + alert("올바르지 않은 휴대폰 번호가 "+ tableErrorData.length +" 건 있습니다."); + } + + + // 미리보기 버튼 활성화 +// updateButtons(0); + + + } + + }); + + + + + + + + + + + + + }); var tableErrorData = []; @@ -506,9 +768,9 @@ var totRows = 0; // 좌측 받는사람 총 갯수 * 토탈 카운트 화면에 노출 * 변수 없는 리스트만 체크 */ -function updateTotCnt(){ +function updateTotCnt(cnt){ - $("#rowTotCnt").text($('#wrap01_body .list_body').length); + $("#rowTotCnt").text(cnt); } @@ -867,3 +1129,8 @@ $('.check_validity').click(function(){ } }); + + + + + diff --git a/src/main/webapp/js/kakao/ft/templateComm.js b/src/main/webapp/js/kakao/ft/templateComm.js new file mode 100644 index 00000000..9fbe80ed --- /dev/null +++ b/src/main/webapp/js/kakao/ft/templateComm.js @@ -0,0 +1,127 @@ +/** + * 알림톡 템플릿 내용 글자수 체크 및 표시, 미리보기 내용 표시 + * + * + */ + +function setContentsLeng(contents){ + + + if ($("#ad_Y").is(":checked")) { + contents = "(광고)"+contents+"\n무료거부 0808800858" + } + + var conLeng = strMaxCharacterCnt(contents); + + if ($("#ad_Y").is(":checked")) { + // 광고문구 제거 + contents = contents + .replace(/^\(광고\)/, '') // 맨 앞의 (광고) 제거 + .replace(/\n무료거부\s*0808800858\s*$/, ''); // 맨 뒤의 '무료거부 0808800858' 제거 + + } + + + if(conLeng > 1000){ + + alert("알림톡 내용은 1000자를 넘을 수 없습니다."); + var splicecon = strMaxLengthSubstring(contents, 999); + $('#inputTemplateContent').val(splicecon); + return false; + + }else{//현재 입력한 글자수 우측 하단에 표시해 주기 + + var repContent = ""; + repContent = contents.replace(/(?:\r\n|\r|\n)/g, '
      '); + + $('.nowChar').text(conLeng + " /"); + $('.template_text').show(); + if(repContent != ''){ + $('.template_text').html(repContent); + }else{ + $('.template_text').html("내용 미리보기"); + } + + } + +} + +/** + * 친구톡 템플릿 내용 글자수 체크 및 표시, 미리보기 내용 표시 + * + * + */ + +function setContentsLengForFriends(contents){ + + +// if ($("#ad_Y").is(":checked")) { +// contents = "(광고)"+contents+"\n무료거부 0808800858" +// } + + var conLeng = strMaxCharacterCnt(contents); + +// if ($("#ad_Y").is(":checked")) { +// // 광고문구 제거 +// contents = contents +// .replace(/^\(광고\)/, '') // 맨 앞의 (광고) 제거 +// .replace(/\n무료거부\s*0808800858\s*$/, ''); // 맨 뒤의 '무료거부 0808800858' 제거 +// +// } + + + var imageType = $("input[name=img_file_add]:checked").val(); + var limitLeng = 1000; + + if(imageType == 'I'){ + + limitLeng = 400; + + if(conLeng > limitLeng){ + + alert("일반 이미지 첨부시 친구톡 내용은 400자를 넘을 수 없습니다."); + + } + + }else if(imageType == 'W'){ + + limitLeng = 76; + + if(conLeng > limitLeng){ + + alert("와이드 이미지 첨부시 친구톡 내용은 76자를 넘을 수 없습니다."); + + } + + }else if(conLeng > 1000){ + + alert("친구톡 내용은 1000자를 넘을 수 없습니다."); + + } + + //제한글자수를 넘겼을 경우 최대 글자수까지 잘라주고 미리보기 및 글자수 표시처리 + if(conLeng > limitLeng){ + + var splicecon = strMaxLengthSubstring(contents, limitLeng-1); + $('#inputTemplateContent').val(splicecon); + contents = splicecon; + conLeng = strMaxCharacterCnt(contents); + + } + + var repContent = ""; + repContent = contents.replace(/(?:\r\n|\r|\n)/g, '
      '); + + $('.nowChar').text(conLeng + " /"); + $('.totChar').text(" "+limitLeng); + $('.template_text').show(); + if(repContent != ''){ + $('.template_text').html(repContent); + $('#smsTxtArea').val( + $('.template_text').html().trim().replace(/(
      ||
      )/g, '\r\n') + ); + }else{ + $('.template_text').html("내용 미리보기"); + } + +} \ No newline at end of file diff --git a/src/main/webapp/publish/css/common.css b/src/main/webapp/publish/css/common.css index 68682db9..a7e3f153 100644 --- a/src/main/webapp/publish/css/common.css +++ b/src/main/webapp/publish/css/common.css @@ -206,7 +206,7 @@ caption, .label {position: absolute;width: 1px;height: 1px;margin: -1px;border: /* 사이트맵 */ .layer_sitemap {overflow:hidden;position:relative;display:block;width:100%;height:0;border-bottom:1px solid #d5d5d5;background:#fff;z-index:16;/*transition:height 0.4s;*/} -.layer_sitemap.active {height:635px;box-shadow:0px 20px 30px 0px rgba(0, 0, 0, 0.1);} +.layer_sitemap.active {height:670px;box-shadow:0px 20px 30px 0px rgba(0, 0, 0, 0.1);} .layer_sitemap .inner {padding:0;letter-spacing:-0.025em;} .layer_sitemap .menu {display:flex;justify-content:space-between;} /*.layer_sitemap .menu > li {width:calc(100%/7);}*/ diff --git a/src/main/webapp/publish/css/content.css b/src/main/webapp/publish/css/content.css index 9d4aac9f..e5c38cf0 100644 --- a/src/main/webapp/publish/css/content.css +++ b/src/main/webapp/publish/css/content.css @@ -1652,18 +1652,18 @@ button.check_validity:hover {border: 1px solid #a3a3a3;box-shadow: 0px 0px 5px .kakao_wrap .img_add_info_wrap .info_text{font-size: 15px; color: #555;} .kakao_wrap .img_add_info_wrap .info_text li{margin: 3px 0 0 0;} .kakao_wrap .img_file_add_wrap .info_title_text{font-weight: 500;margin:0 0 5px 0;} -.kakao_wrap .img_file_add_wrap .btn_img_upload{width: 251px;} -.kakao_wrap .img_file_add_wrap .img_file_info_wrap{width: 100%; max-width: 623px; border: 1px solid #e5e5e5; border-radius: 5px;} -.kakao_wrap .img_file_add_wrap .img_file_info_wrap li{display: flex;min-height: 60px;padding: 10px 20px; border-bottom: 1px solid #e5e5e5;justify-content: space-between; align-items: center; box-sizing: border-box;} -.kakao_wrap .img_file_add_wrap .img_file_info_wrap li:last-child{border-bottom: 0;} -.kakao_wrap .img_file_add_wrap .file_name{font-size: 16px; font-weight: 500;} -.kakao_wrap .img_file_add_wrap .btn_del{width: 30px;height: 30px;border: 1px solid #002c9a;border-radius: 5px;} -.kakao_wrap .img_file_add_wrap .img_url{width: calc(100% - 190px);} -.kakao_wrap .img_file_add_wrap .info_text{margin:0 0 10px 0;} -.kakao_wrap .img_file_add_wrap .info_text li{list-style:1.4;} -.kakao_wrap .img_file_add_wrap .img_file_wrap{display:inline-flex;width:calc(100% - 200px);} -.kakao_wrap .img_file_add_wrap .img_file_wrap .file_name{width:calc(100% - 28px);} -.kakao_wrap .img_file_add_wrap .img_file_wrap .file_name.file_none{color:#666;font-weight:300;line-height:1.8;} +.kakao_wrap .img_file_info_wrap .btn_img_upload{width: 251px;} +.kakao_wrap .img_file_info_wrap{display:none;width: 100%; max-width: 623px; border: 1px solid #e5e5e5; border-radius: 5px;margin:15px 0 0 0;} +.kakao_wrap .img_file_info_wrap li{display: flex;min-height: 60px;padding: 10px 20px; border-bottom: 1px solid #e5e5e5;justify-content: space-between; align-items: center; box-sizing: border-box;} +.kakao_wrap .img_file_info_wrap li:last-child{border-bottom: 0;} +.kakao_wrap .img_file_info_wrap .file_name{font-size: 16px; font-weight: 500;} +.kakao_wrap .img_file_info_wrap .btn_del{width: 30px;height: 30px;border: 1px solid #002c9a;border-radius: 5px;} +.kakao_wrap .img_file_info_wrap .img_url{width: calc(100% - 190px);} +.kakao_wrap .img_file_info_wrap .info_text{margin:0 0 10px 0;} +.kakao_wrap .img_file_info_wrap .info_text li{list-style:1.4;} +.kakao_wrap .img_file_info_wrap .img_file_wrap{display:inline-flex;width:calc(100% - 200px);} +.kakao_wrap .img_file_info_wrap .img_file_wrap .file_name{width:calc(100% - 28px);} +.kakao_wrap .img_file_info_wrap .img_file_wrap .file_name.file_none{color:#666;font-weight:300;line-height:1.8;} .kakaotalkset_cont .kakao_wrap .template_category{width: 270px;} .kakaotalkset_cont .kakao_wrap .emphasis_select{width: 250px;} 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;} diff --git a/src/main/webapp/publish/js/content.js b/src/main/webapp/publish/js/content.js index fa03c0e8..6062e5d0 100644 --- a/src/main/webapp/publish/js/content.js +++ b/src/main/webapp/publish/js/content.js @@ -1,3 +1,4 @@ + $(document).ready(function () { // 문자작성 영역 클릭시 textarea 활성화 @@ -522,15 +523,15 @@ $(document).ready(function () { $("input[name='img_file_add']").change(function () { if ($("input[name='img_file_add']:checked").attr("id") == "img_file_1") { $(".basic_img_add_wrap").show().siblings(".wide_img_add_wrap").hide(); - //$(".img_file_add_wrap").show(); + $(".img_file_info_wrap").show(); $(".kakao_image img").show().attr("src", "/publish/images/content/kakao_img_basic.jpg"); } else if ($("input[name='img_file_add']:checked").attr("id") == "img_file_2") { $(".wide_img_add_wrap").show().siblings(".basic_img_add_wrap").hide(); $(".kakao_image img").show().attr("src", "/publish/images/content/kakao_img_wide.jpg"); - //$(".img_file_add_wrap").show(); + $(".img_file_info_wrap").show(); } else { $(".img_add_info_wrap, .img_file_add_wrap").hide(); - $(".kakao_image img").hide(); + $(".kakao_image img, .img_file_info_wrap").hide(); } }); @@ -1661,31 +1662,45 @@ function friendTemplateButtonAdd() { } var buttonText; var buttonView; - //템플릿 버튼은 buttonVO의 buttonVOList 변수에 셋팅해서 넘겨주게 만들었음 + //템플릿 버튼은 buttonVO의 buttonVOList 변수에 셋팅해서 넘겨주게 만들었음 if (buttonType == "button_type_1") { - buttonText = '
      배송조회

      *이용가능 택배사 : KG로지스, 우체국택배,일양로지스, GTX로지스, FedEx, 경동택배, 합동택배, 롯데택배

      '; + buttonText = '
      배송조회
      ' + +'' + +'

      *이용가능 택배사 : KG로지스, 우체국택배,일양로지스, GTX로지스, FedEx, 경동택배, 합동택배, 롯데택배

      '; buttonView = ''; } else if (buttonType == "button_type_2") { - buttonText = '
      웹링크
      '; + buttonText = '
      웹링크
      ' + +'
      • ' + +'
      • ' + +'
      • ' + +'
      '; buttonView = ''; } else if (buttonType == "button_type_3") { - buttonText = '
      앱링크
      '; + buttonText = '
      앱링크
      ' + +'
      • ' + +'
      • ' + +'
      • ' + +'
      '; buttonView = ''; } else if (buttonType == "button_type_4") { - buttonText = '
      봇키워드
      '; + buttonText = '
      봇키워드
      ' + +'
      '; buttonView = ''; } else if (buttonType == "button_type_5") { - buttonText = '
      메시지전달
      '; + buttonText = '
      메시지전달
      ' + +'
      '; buttonView = ''; } else if (buttonType == "button_type_6") { - buttonText = '
      상담톡전환
      '; + buttonText = '
      상담톡전환
      ' + +'
      '; buttonView = ''; } else if (buttonType == "button_type_7") { - buttonText = '
      챗봇전환
      '; + buttonText = '
      챗봇전환
      ' + +'
      '; buttonView = ''; } else {} - $(".button_add_wrap").prepend(buttonText); - $(".btnViewArea").prepend(buttonView); + $(".button_add_wrap").append(buttonText); + $(".btnViewArea").append(buttonView); } //관리자 카카오톡 알림톡 샘플 템플릿 등록 - 버튼 추가 diff --git a/src/main/webapp/publish/kakao_friendtalk_send.html b/src/main/webapp/publish/kakao_friendtalk_send.html index c103b5ae..18350a07 100644 --- a/src/main/webapp/publish/kakao_friendtalk_send.html +++ b/src/main/webapp/publish/kakao_friendtalk_send.html @@ -101,6 +101,7 @@ +

      * 이미지 첨부 안내

        diff --git a/src/main/webapp/publish/payment1.html b/src/main/webapp/publish/payment1.html index 183dafa6..c5d8a21a 100644 --- a/src/main/webapp/publish/payment1.html +++ b/src/main/webapp/publish/payment1.html @@ -469,6 +469,38 @@ * 텍스트 용량(Byte)에 대한 안내 : 한글2Byte, 영문·숫자 1Byte를 차지. + +

        알림톡 아이콘 이미지 친구톡

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        구분특징가격
        친구톡(텍스트)카카오톡을 통해 채널 친구 대상으로 발송이 가능한 광고성 메시지
        (1,000자 이하의 텍스트 및 이미지 발송 가능)
        13.8
        친구톡(이미지)19.9
        친구톡(와이드 이미지)22.9
        +

        팩스 아이콘 이미지 팩스

        diff --git a/src/main/webapp/publish/textingmsg_detail_friendtalk.html b/src/main/webapp/publish/textingmsg_detail_friendtalk.html index 7b4383b6..2a9d56b4 100644 --- a/src/main/webapp/publish/textingmsg_detail_friendtalk.html +++ b/src/main/webapp/publish/textingmsg_detail_friendtalk.html @@ -732,11 +732,13 @@

        (광고)

        -
        + +

        홍길동 고객님 안녕하세요. 문자온입니다. 문자온에서는 재결제 고객님들께 다양한 이벤트를 준비하였으니, 방문하셔서 혜택 놓치지 마세요.

        +

        수신거부 : 홈 > 채널차단