diff --git a/src/main/java/com/wb/domainserver/domain/admin/instcSle/mtng/service/BOMaMtngService.java b/src/main/java/com/wb/domainserver/domain/admin/instcSle/mtng/service/BOMaMtngService.java index 34acc6c7..516115a0 100644 --- a/src/main/java/com/wb/domainserver/domain/admin/instcSle/mtng/service/BOMaMtngService.java +++ b/src/main/java/com/wb/domainserver/domain/admin/instcSle/mtng/service/BOMaMtngService.java @@ -282,6 +282,9 @@ public class BOMaMtngService { int useMlgAmt = Integer.parseInt(goodsList.get(0).getUseMlgAmt()); int useCashMlgAmt = Integer.parseInt(goodsList.get(0).getUseCashMlgAmt()); Set validKeys = new HashSet<>(); // 변경 구매정보 리스트 + InventoryShortageMessage inventoryMessage = new InventoryShortageMessage(); + Set validationKeys = Arrays.stream(PurchsValidCode.values()) + .map(PurchsValidCode::getCode).collect(Collectors.toSet()); //마일리지 잔액 확인 BOMlgSrchVO mlgVo = new BOMlgSrchVO(); @@ -317,12 +320,14 @@ public class BOMaMtngService { // 값이 1인 항목 == 변경항목 List rs = resultValid.stream() .flatMap(map -> map.entrySet().stream()) + .filter(entry -> validationKeys.contains(entry.getKey())) .filter(entry -> "1".equals(StringUtil.isNullToString(entry.getValue()))) .map(entry -> StringUtil.isNullToString(entry.getKey())) .toList(); //구매정보 변경유형 저장 validKeys.addAll(rs); + inventoryMessage.add(goods, resultValid); } @@ -338,7 +343,9 @@ public class BOMaMtngService { StringBuilder returnMsg = new StringBuilder(); //상품구매수량제한걸렸을 경우 - if(validKeys.contains("purchsQyLmtt")){ + if (inventoryMessage.hasShortages()) { + returnMsg.append(inventoryMessage.render()); + }else if(validKeys.contains("purchsQyLmtt")){ returnMsg.append("구매수량 제한 상품입니다."); returnMsg.append(System.lineSeparator()); //줄바꿈 @@ -519,6 +526,8 @@ public class BOMaMtngService { BOPreOrderValidVO.builder() .sopmalCd(StringUtil.isNullToString(goods.get("sopmalCd"))) .goodsInnb(StringUtil.isNullToString(goods.get("goodsInnb"))) + .goodsNm(StringUtil.isNullToString(goods.get("goodsNm"))) + .optionNm(StringUtil.isNullToString(goods.get("option"))) .goodsOptnInnb(StringUtil.isNullToString(goods.get("goodsOptnInnb"))) .subsvcInnb(StringUtil.isNullToString(goods.get("subsvcInnb"))) .mbrInnb(StringUtil.isNullToString(goods.get("mbrInnb"))) diff --git a/src/main/java/com/wb/domainserver/domain/admin/instcSle/mtng/service/InventoryShortageMessage.java b/src/main/java/com/wb/domainserver/domain/admin/instcSle/mtng/service/InventoryShortageMessage.java new file mode 100644 index 00000000..3e079c1c --- /dev/null +++ b/src/main/java/com/wb/domainserver/domain/admin/instcSle/mtng/service/InventoryShortageMessage.java @@ -0,0 +1,103 @@ +package com.wb.domainserver.domain.admin.instcSle.mtng.service; + +import com.wb.domainserver.domain.admin.instcSle.mtng.vo.BOPreOrderValidVO; +import com.wb.domainserver.util.dataaccess.DataMap; +import org.springframework.util.StringUtils; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** 재고 판정은 변경하지 않고 조회된 재고 수량으로 안내문만 구성한다. */ +final class InventoryShortageMessage { + private final Map goodsById = new LinkedHashMap<>(); + + void add(BOPreOrderValidVO request, List rows) { + if (rows.isEmpty()) { + return; + } + boolean subscription = StringUtils.hasText(request.getSubsvcInnb()); + String key = request.getSopmalCd() + ":" + (subscription + ? "subscription:" + request.getSubsvcInnb() : "goods:" + request.getGoodsInnb()); + Goods goods = goodsById.computeIfAbsent(key, ignored -> new Goods()); + goods.name = StringUtils.hasText(request.getGoodsNm()) ? request.getGoodsNm() + : "상품번호 " + request.getGoodsInnb(); + goods.requested = request.getGoodsTotalQy(); + goods.unit = "SK".equals(request.getSopmalCd()) ? "병" : "개"; + String optionKey = subscription ? request.getSubsvcInnb() : request.getGoodsOptnInnb(); + Option option = goods.options.computeIfAbsent(optionKey, ignored -> new Option()); + option.name = StringUtils.hasText(request.getOptionNm()) ? request.getOptionNm() + : "옵션번호 " + request.getGoodsOptnInnb(); + option.requested += Long.parseLong(request.getQy()); + for (DataMap row : rows) { + if (row.get("stockGoodsNm") != null && StringUtils.hasText(row.get("stockGoodsNm").toString())) { + goods.name = String.valueOf(row.get("stockGoodsNm")); + } + goods.shortage |= "1".equals(String.valueOf(row.get("invntry"))) + || "1".equals(String.valueOf(row.get("invntryPolicy"))); + option.available = minimum(option.available, row.get("optionAvailableQy")); + goods.available = minimum(goods.available, row.get("goodsAvailableQy")); + } + } + + boolean hasShortages() { + return goodsById.values().stream().anyMatch(goods -> goods.shortage); + } + + String render() { + StringBuilder message = new StringBuilder("다음 상품의 구매 가능한 재고가 부족합니다."); + boolean sharedLimit = false; + for (Goods goods : goodsById.values()) { + if (!goods.shortage) { + continue; + } + message.append("\n\n· ").append(goods.name); + if (goods.options.size() == 1) { + Option option = goods.options.values().iterator().next(); + message.append("\n 주문 수량: ").append(goods.requested) + .append(goods.unit).append(" / 현재 구매 가능: ") + .append(quantity(minimum(option.available, goods.available), goods.unit)); + } else { + sharedLimit = true; + message.append("\n 총 주문 수량: ").append(goods.requested) + .append(goods.unit).append(" / 상품 전체 재고 한도: ").append(quantity(goods.available, goods.unit)); + for (Option option : goods.options.values()) { + message.append("\n - ").append(option.name).append(": 주문 ") + .append(option.requested).append(goods.unit).append(" / 옵션별 구매 가능 ") + .append(quantity(minimum(option.available, goods.available), goods.unit)); + } + } + } + if (sharedLimit) { + message.append("\n\n옵션별 가능 수량은 상품 전체 재고 한도 안에서 함께 적용됩니다."); + } + return message.append("\n\n주문 수량을 줄이거나 해당 상품을 제외한 후 다시 주문해 주세요.").toString(); + } + + private static Long minimum(Long current, Object value) { + if (value == null) { + return current; + } + long quantity = Math.max(0L, Long.parseLong(value.toString())); + return current == null ? quantity : Math.min(current, quantity); + } + + private static String quantity(Long value, String unit) { + return value == null ? "확인 불가" : value + unit; + } + + private static final class Goods { + String name; + String unit; + long requested; + Long available; + boolean shortage; + final Map options = new LinkedHashMap<>(); + } + + private static final class Option { + String name; + long requested; + Long available; + } +} diff --git a/src/main/java/com/wb/domainserver/domain/admin/instcSle/mtng/vo/BOPreOrderValidVO.java b/src/main/java/com/wb/domainserver/domain/admin/instcSle/mtng/vo/BOPreOrderValidVO.java index 5a5191da..2e61e291 100644 --- a/src/main/java/com/wb/domainserver/domain/admin/instcSle/mtng/vo/BOPreOrderValidVO.java +++ b/src/main/java/com/wb/domainserver/domain/admin/instcSle/mtng/vo/BOPreOrderValidVO.java @@ -21,6 +21,10 @@ public class BOPreOrderValidVO { /*상품고유번호*/ private String goodsInnb; + private String goodsNm; + + private String optionNm; + /*상품옵션고유번호*/ private String goodsOptnInnb; diff --git a/src/main/java/com/wb/domainserver/domain/gcone/goods/purchs/service/BOOrderService.java b/src/main/java/com/wb/domainserver/domain/gcone/goods/purchs/service/BOOrderService.java index f262969b..bfd05b65 100644 --- a/src/main/java/com/wb/domainserver/domain/gcone/goods/purchs/service/BOOrderService.java +++ b/src/main/java/com/wb/domainserver/domain/gcone/goods/purchs/service/BOOrderService.java @@ -7,6 +7,8 @@ import com.wb.domainserver.domain.gcone.bbs.cnslt.vo.BOCnsltVO; import com.wb.domainserver.domain.gcone.common.service.BOCommonService; import com.wb.domainserver.domain.gcone.goods.purchs.mapper.BOPurchsMapper; import com.wb.domainserver.domain.gcone.goods.purchs.vo.*; +import com.wb.domainserver.domain.gcone.goods.subsvc.service.BOSubsvcService; +import com.wb.domainserver.domain.gcone.goods.subsvc.vo.BOSubsvcVO; import com.wb.domainserver.domain.gcone.ordr.ordr.mapper.BOOrdrMapper; import com.wb.domainserver.domain.gcone.ordr.ordr.vo.BOOrderRestAmtVO; import com.wb.domainserver.exception.WnbtRestException; @@ -51,6 +53,9 @@ public class BOOrderService { @Autowired private BOOrderNoService orderNoService; + @Autowired + private BOSubsvcService subsvcService; + /** * 관리자 주문 > 주문 등록 * @param param @@ -976,6 +981,10 @@ public class BOOrderService { ***************************************** */ BOOrderSetleVO setleVO = insertSetle(orderVO, setle, insertedGoodsList, enuri, purchsr); // 결제 정보 등록 + if (orderVO.getSubsvcInnb() == null && "stripe".equals(setleVO.getPgCmpnyNm())) { + setleVO.setGoodsNm(buildStripeGoodsName(insertedGoodsList.get(0).getGoodsNm(), goodsList)); + } + // 결제금액 원화로 변경 // setleVO.setSetleAmt(setleVO.getWonSetleAmt()); @@ -987,6 +996,13 @@ public class BOOrderService { return content; } + static String buildStripeGoodsName(String firstGoodsName, List goodsList) { + long totalQuantity = goodsList.stream() + .mapToLong(goods -> ((Number) goods.get("qy")).longValue()) + .sum(); + return totalQuantity > 1 ? firstGoodsName + " 외 " + (totalQuantity - 1) + "병" : firstGoodsName; + } + @Transactional public void insertCnsltMemo(String sopmalCd, BigInteger ordrInnb, LinkedHashMap purchsr, LinkedHashMap enuri, AnonymousUser user) { try{ @@ -1231,7 +1247,16 @@ public class BOOrderService { String goodsNm = ""; - if (insertedGoodsList.size() > 1) { + if (orderVO.getSubsvcInnb() != null) { + BOSubsvcVO subscription = new BOSubsvcVO(); + subscription.setSopmalCd(sopmalCd); + subscription.setSubsvcInnb(orderVO.getSubsvcInnb().toString()); + DataMap detail = subsvcService.selectBOSubsvcDetail(subscription); + goodsNm = detail == null ? "" : StringUtil.isNullToString(detail.get("subsvcNm")); + if (!StringUtils.hasText(goodsNm)) { + throw new WnbtRestException("구독서비스명을 확인할 수 없습니다. 다시 시도해 주세요."); + } + } else if (insertedGoodsList.size() > 1) { goodsNm = insertedGoodsList.get(0).getGoodsNm() + " 외" + (insertedGoodsList.size() - 1); } else { goodsNm = insertedGoodsList.get(0).getGoodsNm(); @@ -2589,4 +2614,4 @@ public class BOOrderService { -} \ No newline at end of file +} diff --git a/src/main/java/com/wb/domainserver/domain/sopmal/login/controller/LoginController.java b/src/main/java/com/wb/domainserver/domain/sopmal/login/controller/LoginController.java index 31cabbb9..a94a346a 100644 --- a/src/main/java/com/wb/domainserver/domain/sopmal/login/controller/LoginController.java +++ b/src/main/java/com/wb/domainserver/domain/sopmal/login/controller/LoginController.java @@ -153,6 +153,8 @@ public class LoginController { CookieUtils.deleteCookie("token_expire", "/", request, response); response.sendRedirect("/sopmal/login/page/" + RealmContextHolder.getRealm() + "?redirect_uri=" + URLEncoder.encode(request.getParameter("redirect_uri"), StandardCharsets.UTF_8)); + // 로그인 이동을 확정한 뒤 원래 URL로 다시 리다이렉트하지 않는다. + return; }else{ //리프레쉬 토큰 있을 경우(존재한다는 자체가 refresh토큰이 만료된 상태가 아님) diff --git a/src/main/java/com/wb/domainserver/domain/sopmal/stripe/controller/StripeController.java b/src/main/java/com/wb/domainserver/domain/sopmal/stripe/controller/StripeController.java index 7bd85420..309f2d2f 100644 --- a/src/main/java/com/wb/domainserver/domain/sopmal/stripe/controller/StripeController.java +++ b/src/main/java/com/wb/domainserver/domain/sopmal/stripe/controller/StripeController.java @@ -23,13 +23,18 @@ import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.util.UriComponentsBuilder; +import org.springframework.web.server.ResponseStatusException; +import org.springframework.http.HttpStatus; import java.util.HashMap; import java.util.Map; @@ -47,6 +52,14 @@ public class StripeController { private Util utilClass; + @Value("${stripe.checkout.return-base-url:}") + private String stripeReturnBaseUrl = ""; + + String resolveStripeReturnBaseUrl(String shopDomain) { + String baseUrl = stripeReturnBaseUrl.isBlank() ? shopDomain : stripeReturnBaseUrl.trim(); + return baseUrl.replaceAll("/+$", ""); + } + /** * stripe 결제 Url 호출 * @return selectStripeTest.jsp @@ -57,8 +70,7 @@ public class StripeController { BOMaSopmalVO sopmalVO = new BOMaSopmalVO(); sopmalVO.setSopmalCd(request.getParameter("sopmalCd")); DataMap sopmalInfo = boMaSopmalService.selectBOSopmalUpdtForm(sopmalVO).get(0); - String domnAdres = sopmalInfo.get("pcDomnAdres").toString(); -// domnAdres = "http://loc.soju1sake1.com:18500"; + String domnAdres = resolveStripeReturnBaseUrl(sopmalInfo.get("pcDomnAdres").toString()); StripeClient stripeClient = payService.createStripeClient(request.getParameter("sopmalCd")); SessionCreateParams.Builder paramsBuilder = SessionCreateParams.builder() @@ -71,6 +83,11 @@ public class StripeController { .build() ); + String customerEmail = request.getParameter("ordrrEmail"); + if (customerEmail != null && !customerEmail.isBlank()) { + paramsBuilder.setCustomerEmail(customerEmail.trim()); + } + paramsBuilder.addLineItem( SessionCreateParams.LineItem.builder() .setQuantity(1L) @@ -149,6 +166,10 @@ public class StripeController { DataMap result = new DataMap(); result.put("checkoutUrl", session.getUrl()); + result.put("redirectUrl", UriComponentsBuilder.fromPath(request.getContextPath() + "/sopmal/stripe/checkoutRedirect") + .queryParam("sessionId", session.getId()) + .queryParam("sopmalCd", request.getParameter("sopmalCd")) + .build().encode().toUriString()); WnbtResponseBody body = new WnbtResponseBody(result); WnbtResponse response = WnbtResponse.builder().resBody(body).build(); @@ -156,6 +177,23 @@ public class StripeController { return ResponseEntity.ok(response); } + /** Stripe 진입 이력을 GET으로 남겨 뒤로가기 시 주문 POST를 재전송하지 않는다. */ + @Policy(AuthPolicy.RESTRICTED) + @GetMapping("/checkoutRedirect") + public String checkoutRedirect(ModelMap model, @RequestParam("sessionId") String sessionId, + @RequestParam("sopmalCd") String sopmalCd) throws StripeException { + Session session = payService.createStripeClient(sopmalCd).v1().checkout().sessions().retrieve(sessionId); + AnonymousUser user = MemberJwtContextHolder.getMemberInfo(); + if (!String.valueOf(user.getUserInnb()).equals(session.getMetadata().get("mbrInnb")) + || !sopmalCd.equals(session.getMetadata().get("sopmalCd"))) { + throw new ResponseStatusException(HttpStatus.FORBIDDEN); + } + model.addAttribute("checkoutUrl", "open".equals(session.getStatus()) ? session.getUrl() : ""); + model.addAttribute("sessionId", sessionId); + model.addAttribute("sopmalCd", sopmalCd); + return "sopmal/ordr/StripeRedirectR"; + } + @Policy(AuthPolicy.RESTRICTED) @RequestMapping(value = "/stripeSuccess") public String stripeSuccess(ModelMap model, @RequestParam("sessionId") String sessionId, @RequestParam("sopmalCd") String sopmalCd) throws StripeException { @@ -214,12 +252,16 @@ public class StripeController { @Policy(AuthPolicy.RESTRICTED) @RequestMapping(value = "/stripeCancel") - public String stripeCancel(ModelMap model, @RequestParam("sessionId") String sessionId, @RequestParam("sopmalCd") String sopmalCd) throws StripeException { + public String stripeCancel(HttpServletRequest request, ModelMap model, @RequestParam("sessionId") String sessionId, @RequestParam("sopmalCd") String sopmalCd) throws StripeException { StripeClient stripeClient = payService.createStripeClient(sopmalCd); Session session = stripeClient.v1().checkout().sessions().retrieve(sessionId); String status = session.getStatus(); String paymentStatus = session.getPaymentStatus(); + if (!("complete".equals(status) && "paid".equals(paymentStatus))) { + model.addAttribute("mobile", "sopmal_m".equals(Util.getDeviceType(request))); + return "sopmal/ordr/StripeCancelR"; + } JsonObject customerDetails = null; JsonObject rawJson = session.getRawJsonObject(); if (rawJson != null @@ -252,6 +294,6 @@ public class StripeController { model.addAttribute("sesionId", session.getMetadata().get("sesionId")); model.addAttribute("subsvcInnb", session.getMetadata().get("subsvcInnb")); - return "sopmal/ordr/PayStripeCnclC"; + return "sopmal/ordr/PayStripeSucsC"; } } diff --git a/src/main/resources/mybatis/xml/mapper/admin/instcSle/mtng/BOMtngMapper.xml b/src/main/resources/mybatis/xml/mapper/admin/instcSle/mtng/BOMtngMapper.xml index 2aaffb9d..680f13f4 100644 --- a/src/main/resources/mybatis/xml/mapper/admin/instcSle/mtng/BOMtngMapper.xml +++ b/src/main/resources/mybatis/xml/mapper/admin/instcSle/mtng/BOMtngMapper.xml @@ -402,6 +402,9 @@ WHEN (IFNULL(GOODS.REST_INVNTRY_QY, 0) - IFNULL(GOODS.AVLINV_LMTT_QY, 0)) >= #{goodsTotalQy} THEN 0 ELSE 1 END END AS INVNTRY_POLICY -- 상품별 옵션 수량합산 재고유무 + , MAX(GOODS.GOODS_NM) AS STOCK_GOODS_NM + , MIN(GREATEST(0, IFNULL(OPTN.INVNTRY_QY, 0) - IFNULL(OPTN.USEFUL_INVNTRY_QY, 0))) AS OPTION_AVAILABLE_QY + , MIN(GREATEST(0, IFNULL(GOODS.REST_INVNTRY_QY, 0) - IFNULL(GOODS.AVLINV_LMTT_QY, 0))) AS GOODS_AVAILABLE_QY , CASE WHEN IFNULL(OPTN.SLEPRIC, 0) = #{slepric} THEN 0 ELSE 1 END AS SELPRIC -- 판매가 변경여부 , CASE WHEN OPTN.COMPNB_DSCNT_AT = #{compnbDscntAt} AND OPTN.SCTN_DSCNT_AT = #{sctnDscntAt} THEN 0 @@ -430,6 +433,7 @@ , IFNULL(EVT_DUPL_COUPON.DPLCT_LMTT_COUPON, 0) AS DPLCT_LMTT_COUPON -- 이벤트 중복제한 쿠폰 존재여부 , CASE WHEN OPTN.OPTN_EXPSR_AT = 'Y' THEN 0 ELSE 1 END AS OPTN_EXPSR_AT FROM (SELECT GG.GOODS_INNB -- 상품 고유번호 + , GG.GOODS_NM , GG.SOPMAL_CD -- 쇼핑몰코드 , GG.DLVY_GROUP_INNB -- 배송그룹고유번호 , GG.GOODS_KND_CD -- 상품구분 01 상품 @@ -801,6 +805,9 @@ ELSE 1 END END AS INVNTRY_POLICY, -- 상품별 옵션 수량합산 재고유무 + MAX(GOODS.GOODS_NM) AS STOCK_GOODS_NM, + MIN(GREATEST(0, GOODS.INVNTRY_QY - IFNULL(GOODS.USEFUL_INVNTRY_QY, 0))) AS OPTION_AVAILABLE_QY, + MIN(GREATEST(0, IFNULL(GOODS.REST_INVNTRY_QY, 0) - IFNULL(GOODS.AVLINV_LMTT_QY, 0))) AS GOODS_AVAILABLE_QY, CASE WHEN IFNULL(GOODS.SUBSVC_CT, 0) = #{slepric} THEN 0 ELSE 1 @@ -817,6 +824,7 @@ FROM ( SELECT GS.SUBSVC_INNB, -- 구독서비스 고유번호 + GG.GOODS_NM, GG.GOODS_INNB, -- 상품 고유번호 GS.SOPMAL_CD, -- 쇼핑몰코드 GS.SUBSVC_CT, -- 구독료 diff --git a/src/main/resources/static/js/sopmal/refund-popup.js b/src/main/resources/static/js/sopmal/refund-popup.js new file mode 100644 index 00000000..786c1cb1 --- /dev/null +++ b/src/main/resources/static/js/sopmal/refund-popup.js @@ -0,0 +1,46 @@ +/* 결제취소 화면 조회 전용. 실제 취소/환불 요청은 처리하지 않는다. */ +async function fn_load_refund_popup(url, data, onReady) { + const requestUrl = new URL(url, window.location.href); + Object.entries(data).forEach(([key, value]) => requestUrl.searchParams.set(key, value)); + + const loginRequired = function () { + window.alert('로그인 시간이 만료되었습니다. 다시 로그인해 주세요.'); + const loginUrl = new URL('/sopmal/login', window.location.href); + // 로그인 후 AJAX 팝업 주소가 아닌 원래 주문 상세로 돌아온다. + loginUrl.searchParams.set('redirect_uri', window.location.href); + window.location.assign(loginUrl.href); + }; + + try { + // 갱신 후 리다이렉트에서도 주문 조회 조건이 유지되도록 GET으로 요청한다. + const response = await fetch(requestUrl.href, { + method: 'GET', + credentials: 'same-origin', + cache: 'no-store', + headers: {'X-Requested-With': 'XMLHttpRequest'} + }); + const finalUrl = new URL(response.url || requestUrl.href, window.location.href); + if (response.status === 401 || (response.redirected && + /^\/sopmal\/(login(?:\/|$)|logout(?:\/|$)|main(?:\/|$))/.test(finalUrl.pathname))) { + loginRequired(); + return; + } + if (!response.ok || finalUrl.origin !== requestUrl.origin || finalUrl.pathname !== requestUrl.pathname) { + throw new Error('Unexpected refund popup response'); + } + + // 로그인 HTML이나 빈 응답은 화면에 넣지 않는다. 반환된 스크립트도 실행하지 않는다. + const html = await response.text(); + const parsed = new DOMParser().parseFromString(html, 'text/html'); + const popup = parsed.querySelector('#refund-pop'); + if (!popup) { + throw new Error('Missing refund popup'); + } + popup.querySelectorAll('script').forEach(script => script.remove()); + $('#refund-pop').remove(); + $('#refundPopupDiv').empty().append(popup); + onReady($(popup)); + } catch (error) { + window.alert('결제취소 화면을 불러오지 못했습니다. 잠시 후 다시 시도해 주세요.'); + } +} diff --git a/src/main/webapp/WEB-INF/views/sopmal/mpage/ordr/OrdrDtlR.jsp b/src/main/webapp/WEB-INF/views/sopmal/mpage/ordr/OrdrDtlR.jsp index 9b8efd0d..6d497fde 100644 --- a/src/main/webapp/WEB-INF/views/sopmal/mpage/ordr/OrdrDtlR.jsp +++ b/src/main/webapp/WEB-INF/views/sopmal/mpage/ordr/OrdrDtlR.jsp @@ -33,6 +33,7 @@ + + -
-

결제 성공

+
+ +

결제 결과를 확인하고 있습니다.

+

잠시만 기다려 주세요.

diff --git a/src/main/webapp/WEB-INF/views/sopmal/ordr/StripeCancelR.jsp b/src/main/webapp/WEB-INF/views/sopmal/ordr/StripeCancelR.jsp new file mode 100644 index 00000000..861aca86 --- /dev/null +++ b/src/main/webapp/WEB-INF/views/sopmal/ordr/StripeCancelR.jsp @@ -0,0 +1,51 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + + + + + + + + + + + + + 결제 중단 안내 + + +
+ + +
+ +
+ +
+ + + +
+
+
+
+
+
+

결제를 중단하셨습니다.

+

이 결제창에서 결제를 완료하지 않았습니다.
주문/배송조회에서 주문 상태를 확인한 뒤 다시 결제해 주세요.

+
+ +
+
+
+
+ + + +
+ + diff --git a/src/main/webapp/WEB-INF/views/sopmal/ordr/StripeRedirectR.jsp b/src/main/webapp/WEB-INF/views/sopmal/ordr/StripeRedirectR.jsp new file mode 100644 index 00000000..8e0b48dc --- /dev/null +++ b/src/main/webapp/WEB-INF/views/sopmal/ordr/StripeRedirectR.jsp @@ -0,0 +1,35 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + + + + + + + + + + 결제창으로 이동 + + + +

결제창으로 이동하고 있습니다.

+ 결제창 열기 + 결제 중단 + + diff --git a/src/main/webapp/WEB-INF/views/sopmal/ordr/SubsvcPurchsC.jsp b/src/main/webapp/WEB-INF/views/sopmal/ordr/SubsvcPurchsC.jsp index 6aaf74e4..be023b22 100644 --- a/src/main/webapp/WEB-INF/views/sopmal/ordr/SubsvcPurchsC.jsp +++ b/src/main/webapp/WEB-INF/views/sopmal/ordr/SubsvcPurchsC.jsp @@ -524,7 +524,7 @@ });*/ /* 결제정보 결제수단 버튼 선택 이벤트 */ - $('input[name="pg"]').on('click', function() { + $('input[name="pg"]').on('click', function(event, skipDefaultMethod) { const form = $(this).closest('#setleForm') const id = $(this).attr('id'); const pgCmpnyNm = $(this).val(); @@ -585,6 +585,14 @@ $('.order-method-normal__btn').removeClass('active'); $('.order-method-normal__content').hide(); } + + // 통화를 선택하면 사용 가능한 첫 결제수단을 기존 클릭 처리로 선택한다. + // 결제수단 버튼에서 라디오를 갱신할 때는 재귀 선택을 생략한다. + if (!skipDefaultMethod && ['st01', 'pg03', 'pg04', 'pg06'].includes(id)) { + $(form).find('#' + id + 'Content') + .find('.order-method-normal__btn:visible:not(:disabled)') + .first().trigger('click'); + } }); /* 결제정보 > 일반결제 > 결제수단 버튼 선택 이벤트 */ @@ -593,11 +601,8 @@ const content = $('.order-method-normal__content'); const useCashMlgAmt = $('#useCashMlgAmt').val(); - //$('#setleSetupTyCd').val() === '01' ? $('#pg04').click() : $('#pg03').click(); - if ($('#st01').is(':checked')){$('#st01').click();} - else if($('#setleSetupTyCd').val() === '01'){$('#pg04').click();} - else if($('#setleSetupTyCd').val() === '02'){$('#pg03').click();} - else if($('#setleSetupTyCd').val() === '03'){$('#pg06').click();} + const pgId = $(this).closest('.pgContent').attr('id').replace(/Content$/, ''); + $('#' + pgId).trigger('click', [true]); $('.order-method-normal__btn').removeClass('active'); $(this).addClass('active'); @@ -4213,7 +4218,7 @@
- +