이호영 이호영 2025-07-16
친구톡 환불로직 진행중
@1f0c38b791ef287a2897937b64294d9e52e6997c
src/main/java/itn/let/kakao/kakaoComm/KakaoSendAdvcVO.java
--- src/main/java/itn/let/kakao/kakaoComm/KakaoSendAdvcVO.java
+++ src/main/java/itn/let/kakao/kakaoComm/KakaoSendAdvcVO.java
@@ -59,6 +59,7 @@
 	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 단가
@@ -68,6 +69,8 @@
 	private String atDelayYn;	// 카카오 알림톡 단가
 	private String bizKakaoResendOrgnlTxt;	// 카카오 알림톡 단가
 	private String bizKakaoResendType;	// 카카오 알림톡 단가
+	private String filePath1;	// 대체문자 이미지 
+	private String fileCnt;	// 파일 카운트
 	
 	
 	
@@ -109,6 +112,7 @@
 			"\n , atDelayYn=[" + atDelayYn + "]" +
 			"\n , bizKakaoResendOrgnlTxt=[" + bizKakaoResendOrgnlTxt + "]" +
 			"\n , bizKakaoResendType=[" + bizKakaoResendType + "]" +
+			"\n , filePath1=[" + filePath1 + "]" +
 			"\n ]";
 	}
 
src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java
--- src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java
+++ src/main/java/itn/let/kakao/kakaoComm/KakaoSendUtil.java
@@ -34,6 +34,7 @@
 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;
@@ -53,6 +54,9 @@
 	
 	@Resource(name = "MjonMsgDataService")
 	private MjonMsgDataService mjonMsgDataService;
+
+	@Resource(name = "mjonMsgDAO")
+	private MjonMsgDAO mjonMsgDAO;
 	
 	@Autowired
 	KakaoApiTemplate kakaoApiTemplate;
@@ -367,15 +371,25 @@
 		Float kakaoFtPrice = 
 				getValidPrice(kakaoMemberFtPrice, kakaoSysJoinFtPrice);
 		
-//		imageType
-		// 친구통 금액 
-		
 		// 대체문자가 있을경우 사용 
 		float shortPrice = getValidPrice(mberManageVO.getShortPrice(), sysJoinSetVO.getShortPrice());
 		float longPrice = getValidPrice(mberManageVO.getLongPrice(), sysJoinSetVO.getLongPrice());
-		String shortPStr = Float.toString(shortPrice);
-		String mmsPStr = Float.toString(longPrice);
+		float picturePrice = getValidPrice(mberManageVO.getPicturePrice(), sysJoinSetVO.getPicturePrice());
+//		String shortPStr = Float.toString(shortPrice);
+//		String mmsPStr = Float.toString(longPrice);
+//		String imgPrice = Float.toString(picturePrice);
 
+		
+		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());
@@ -390,8 +404,9 @@
 
 			KakaoSendAdvcVO sendVO = createFTSendVO(kakaoVO, calendar);
 			// 공통 가격 설정
-			sendVO.setSmsPrice(shortPStr);
-			sendVO.setMmsPrice(mmsPStr);
+			sendVO.setSmsPrice(Float.toString(shortPrice));
+			sendVO.setMmsPrice(Float.toString(longPrice));
+			sendVO.setPicturePrice(Float.toString(picturePrice));
 
 			sendVO.setCallTo(mjonFTSendVO.getPhone());
 			sendVO.setMsgId(idList.get(i));
@@ -443,17 +458,39 @@
 			//대체문자가 있으면
 			// Step 1-4: 실패 대체 문자 치환데이터 설정
 			if(StringUtils.isNotEmpty(subMsgTxtTemp)) { // 대체문자가 있나?
-				int smsTxtByte = mjonCommon.getSmsTxtBytes(subMsgTxtTemp);
-				String sendType = getMsgType(smsTxtByte);
-				sendVO.setSubMsgType(sendType);
+				
+				String sendType =  "MMS";
+				if(StringUtils.isEmpty(imgFilePath)) {
+					int smsTxtByte = mjonCommon.getSmsTxtBytes(subMsgTxtTemp);	// 문자 byte 수 계산
+					sendType = getMsgType(smsTxtByte);					// 문자 타입(SHORT / MMS) 판별
+				}
+				sendVO.setSubMsgType(sendType);								// 실패 대체 문자 타입 설정
 
 				if ("INVALID".equals(sendType)) {
-					statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "전송 문자 길이를 초과하였습니다.");return kakaoSendAdvcListVO;
+					// INVALID 타입이면 길이 초과 에러 응답 후 리턴
+					statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "전송 문자 길이를 초과하였습니다.");
+					return kakaoSendAdvcListVO;
 				}
-	
-				boolean isMms = "MMS".equals(sendType);
-				sendVO.setEachPrice(isMms ? mmsPStr : shortPStr);
+
+				float chosenPrice = 0f;
+
+				if(StringUtils.isNotEmpty(imgFilePath)) {
+					chosenPrice = Math.max(picturePrice, kakaoFtPrice);
+					sendVO.setFilePath1(imgFilePath);
+					sendVO.setFileCnt("1");			
+					
+				}else if ("MMS".equals(sendType)) {
+					// MMS 타입일 경우: longPrice(장문 가격)와 카카오톡 단가 중 큰 값을 선택
+					chosenPrice = Math.max(longPrice, kakaoFtPrice);
+				} else {
+					// SHORT 타입일 경우: shortPrice(단문 가격)와 카카오톡 단가 중 큰 값을 선택
+					chosenPrice = Math.max(shortPrice, kakaoFtPrice);
+				}
+				sendVO.setEachPrice(Float.toString(chosenPrice));	// 선택된 단가 설정
+				
+				
 			}else {
+				// 대체문자가 없으면 카카오톡 단가 그대로 사용
 				sendVO.setEachPrice( Float.toString(kakaoFtPrice) );
 			}
 
@@ -990,7 +1027,9 @@
 		// 사용자 개인 단가가 없으면 시스템 단가로
 		if(mberManageVO.getLongPrice() == 0.0f)
 			mberManageVO.setLongPrice(sysJoinSetVO.getLongPrice());
-		
+
+		if(mberManageVO.getPicturePrice() == 0.0f)
+			mberManageVO.setPicturePrice(sysJoinSetVO.getPicturePrice());
 
 		return mberManageVO;
 	}
src/main/java/itn/let/kakao/kakaoComm/KakaoVO.java
--- src/main/java/itn/let/kakao/kakaoComm/KakaoVO.java
+++ src/main/java/itn/let/kakao/kakaoComm/KakaoVO.java
@@ -260,6 +260,9 @@
 	private String msgResendAllGroupId;
 	private String msgResendAllTmpKey;
 	private String msgResendAllYellowId;
+	
+	private String bizKakaoResendType;
+	private String fileCnt;
 
 	private List<Map<String, String>> varListMap;
 
src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiImageUpload.java
--- src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiImageUpload.java
+++ src/main/java/itn/let/kakao/kakaoComm/kakaoApi/KakaoApiImageUpload.java
@@ -5,8 +5,10 @@
 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;
@@ -38,6 +40,7 @@
 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;
@@ -64,7 +67,17 @@
 	
     @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
@@ -293,118 +306,162 @@
 	 * @param files
 	 * @param i
 	 * @return
+	 * @throws Exception 
 	 * 
 	 */
-	public StatusResponse kakaoApiImageUpload_advc(KakaoVO kakaoVO, Map<String, MultipartFile> files, int fileKeyParam) {
-		try {
+	public StatusResponse kakaoApiImageUpload_advc(KakaoVO kakaoVO, Map<String, MultipartFile> 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()) {
-				if (file.isEmpty()) continue;
+//			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()) continue;
+			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, "지원하지 않는 이미지 형식입니다.");
+			}
 
-				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 사이즈만 허용됩니다.");
 				}
-
-				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;
+			} 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 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<String, Object> returnMap = new HashMap<>();
-						returnMap.put("imgUrl", object.get("image").toString());
-						returnMap.put("fileName", originalName);
-						
-						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());
+				if (width < 500 || ratio < 0.75 || ratio > 2.0) {
+					return new StatusResponse(HttpStatus.BAD_REQUEST, "일반 이미지는 가로 500px 이상, 비율 2:1 이상 또는 3:4 이하만 허용됩니다.");
 				}
 			}
-		} catch (Exception e) {
-			log.error("kakaoApiImageUpload_advc API Error", e);
-			return new StatusResponse(HttpStatus.BAD_REQUEST, "친구톡 이미지 등록에 실패했습니다.", LocalDateTime.now());
-		}
-		return new StatusResponse(HttpStatus.BAD_REQUEST, "유효한 이미지 파일이 없습니다.", LocalDateTime.now());
+			
+			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<String, Object> 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<String, MultipartFile> 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<FileVO> result = fileUtil.parseImageFileInf(files, KeyStr, 0, atchFileId, imagePath, isThumbFile);
+			atchFileId = fileMngService.insertFileInfs(result);
+		}
+		
+		
+		return atchFileId;
+	}
+
+
+
+
 	/**
 	* @Method Name : kakaoApiTemplateImageUpload
 	* @작성일 : 2023. 2. 16.
src/main/java/itn/let/kakao/user/kakaoFt/service/impl/KakaoFriendsTalkServiceImpl.java
--- src/main/java/itn/let/kakao/user/kakaoFt/service/impl/KakaoFriendsTalkServiceImpl.java
+++ src/main/java/itn/let/kakao/user/kakaoFt/service/impl/KakaoFriendsTalkServiceImpl.java
@@ -177,9 +177,10 @@
 
 /** @biz_kakao_price에 insert (대체문자 환불관련 테이블)*/ 
 				kakaoVO.setMsgGroupId(sendVO.getMsgGroupId());
-				kakaoVO.setKakaoAtPrice(Float.parseFloat(sendVO.getEachPrice()));
+				kakaoVO.setKakaoFtPrice(Float.parseFloat(sendVO.getEachPrice()));
 				kakaoVO.setSmsPrice(Float.parseFloat(sendVO.getSmsPrice()));
 				kakaoVO.setMmsPrice(Float.parseFloat(sendVO.getMmsPrice()));
+				kakaoVO.setPicturePrice(Float.parseFloat(sendVO.getPicturePrice()));
 				
 				kakaoAlimTalkDAO.insertKakaoSendPrice(kakaoVO);
 				
src/main/java/itn/let/mjo/msg/service/MjonMsgVO.java
--- src/main/java/itn/let/mjo/msg/service/MjonMsgVO.java
+++ src/main/java/itn/let/mjo/msg/service/MjonMsgVO.java
@@ -165,6 +165,7 @@
 	
 	private float smsPrice;		// sms 단가
 	private float mmsPrice;		// mms 단가
+	private float picturePrice;		// mms 단가
 	private float kakaoAtPrice;	// 카카오 알림톡 단가
 	private float kakaoFtPrice;	// 카카오 친구톡 단가
 	private float kakaoFtImgPrice;// 카카오 이미지 단가
src/main/resources/egovframework/sqlmap/let/mjo/kakao/Kakao_AT_SQL_Mysql.xml
--- src/main/resources/egovframework/sqlmap/let/mjo/kakao/Kakao_AT_SQL_Mysql.xml
+++ src/main/resources/egovframework/sqlmap/let/mjo/kakao/Kakao_AT_SQL_Mysql.xml
@@ -73,12 +73,15 @@
 			, 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
 		<iterate conjunction=",">
 		(
@@ -97,12 +100,15 @@
 			, #[].templateContent#
 			, #[].templateTitle#
 			, #[].adFlag#
+			, #[].filePath1#
 			
 			, #[].subMsgSendYn#
 			, #[].subMsgTxt#
 			, #[].subMsgType#
 			, #[].bizJsonName#
 			, #[].reqDate#
+			
+			, #[].fileCnt#
 		)
 		</iterate>
 	</insert>
@@ -178,20 +184,18 @@
 			MSG_GROUP_ID
 			, BIZ_KAKAO_AT_PRICE
 			, BIZ_KAKAO_FT_PRICE
-			, BIZ_KAKAO_FT_IMG_PRICE
-			, BIZ_KAKAO_FT_WIDE_IMG_PRICE
 			, BIZ_SMS_PRICE
 			, BIZ_MMS_PRICE
+			, BIZ_PICTURE_PRICE
 		)
 		VALUES
 		(
 			#msgGroupId#
 			,#kakaoAtPrice#
 			,#kakaoFtPrice#
-			,#kakaoFtImgPrice#
-			,#kakaoFtWideImgPrice#
 			,#smsPrice#
 			,#mmsPrice#
+			,#picturePrice#
 		)
 	</insert>
 	
@@ -235,6 +239,8 @@
 			, 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_KAKAO_RESEND_TYPE  				AS bizKakaoResendType
 			
 		FROM
 			MJ_MSG_DATA MMD
@@ -275,7 +281,7 @@
 	
 	<!-- 카카오 친구톡 전송 환불 프로시저 실행 (카카오 전송 성공 관련 - 대체문자 선택시 차액 환불 처리) -->
 	<procedure id="kakaoAlimTalkDAO.updateKakaoFtSend" parameterClass="kakaoVO">
-		{call kakaoFt_Send(#userId#, #msgGroupId#, #userData#)}
+		{call kakaoFt_Send(#userId#, #msgGroupId#, #userData#, #fileCnt#, #bizKakaoResendType#)}
 	</procedure>
 	
 	<!-- 카카오 친구톡 전송 환불 프로시저 실행 (카카오 전송 실패시 대체문자 관련 - 대체문자 발송 완료 된 경우) -->
src/main/webapp/WEB-INF/jsp/web/kakao/msgdata/ft/KakaoFriendsTalkMsgDataView.jsp
--- src/main/webapp/WEB-INF/jsp/web/kakao/msgdata/ft/KakaoFriendsTalkMsgDataView.jsp
+++ src/main/webapp/WEB-INF/jsp/web/kakao/msgdata/ft/KakaoFriendsTalkMsgDataView.jsp
@@ -180,6 +180,7 @@
 		if ($('#sendFailImgSrc').attr('src') != null) {
 			$('#sendFailImg').hide();
 			$('#sendFailImgSrc').attr('src', '');
+			$('#atchFileId').val('');
 		}
 		
 		
@@ -599,6 +600,9 @@
 					$(".kakao_image").css("display", "block");
 					$("#kakaoImg").attr("src", returnData.object.imgUrl);
 					
+					
+					// 대체문자 이미지
+					$("#atchFileId").val(returnData.object.atchFileId);
 					// 대체문자
 					$('#sendFailImg').show();
 					$('#sendFailImgSrc').attr('src', returnData.object.imgUrl);
@@ -1619,6 +1623,7 @@
 			<input type="hidden" id="kakaoFtWideImgPrice" value="<c:out value='${sendPrice.kakaoFtWideImgPrice}' />"> <!-- 친구톡 와이드이미지 단가  -->
 			<input type="hidden" id="longPrice" value="<c:out value='${sendPrice.longPrice}' />"> <!-- mms 단가  -->
 			<input type="hidden" id="shortPrice" value="<c:out value='${sendPrice.shortPrice}' />"> <!-- sms 단가  -->
+			<input type="hidden" id="picturePrice" value="<c:out value='${sendPrice.picturePrice}' />"> <!-- sms 단가  -->
 			
 			<form id="bizForm" name="bizForm" method="multipart/form-data">
 				<input type="hidden" id="menuTopTab" name="menuTopTab" value="tabFriend">
@@ -1631,6 +1636,9 @@
 				<input type="hidden" id="adFlag" name="adFlag" value="<c:out value='${resultTemplateVO.adFlag}' default='Y'/>">
 				<input type="hidden" id="templateContent" name="templateContent" value=""/>
 				
+				<!-- 이미지 있을때 대체문자 발송 참고 이미지 -->
+				<input type="hidden" id="atchFileId" name="atchFileId" value=""/>
+				
 				<!-- 예약발송 여부 -->
 				<input type="hidden" id="reserveYn" name="reserveYn" value="N"/>
 				<input type="hidden" id="reqDate" name="reqDate" value=""/>
src/main/webapp/js/kakao/ft/ftPriceClclt.js
--- src/main/webapp/js/kakao/ft/ftPriceClclt.js
+++ src/main/webapp/js/kakao/ft/ftPriceClclt.js
@@ -33,80 +33,52 @@
  * 				대체 문자 X
  * 				카카오 금액 * 수신자 수 계산
  */
-function totalFtPriceSum(totRows){
-	
-	var collNumCnt = parseInt(totRows); 	//받는사람 건수
-	var price;
-	
+function totalFtPriceSum(totRows) {
+	// 수신자 수 계산
+	var count = parseInt(totRows);
 
-	if ($("input[name='img_file_add']:checked").attr("id") == "img_file_1") {
-		price = KAKAO_FT_IMG_PRICE;		
-	} else if ($("input[name='img_file_add']:checked").attr("id") == "img_file_2") {
-		price = KAKAO_FT_WIDE_IMG_PRICE;		
-	} else {
-		price = KAKAO_FT_PRICE;							//개별 건수 금액
-	}
-	
-	
-	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();
+	// 기본 단가는 일반 친구톡 이미지 없는 가격
+	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 len = conByteLeng($('#smsTxtArea').val());
+			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; // 계산된 총 금액 반환
 }
 
 
 
+
 /*
  * ======================================================================================================================
  * 
Add a comment
List