๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ–ฅ๏ธ ๋ฐฑ์—”๋“œ/SpringBoot

[KakaoPay] ์นด์นด์˜คํŽ˜์ด ๋‹จ๊ฑด ๊ฒฐ์ œ ์ปจํŠธ๋กค๋Ÿฌ ์˜ˆ์‹œ

by OR15A 2024. 3. 29.
์•ˆ๋‚ด๊ธ€
  • ๊ฒฐ์ œ ํ๋ฆ„์„ ๋ณด๊ธฐ ์œ„ํ•ด debug ๋ชจ๋“œ์˜ ๋กœ๊ทธ ์ถœ๋ ฅ์ด ๋งŽ์Šต๋‹ˆ๋‹ค
  • ๊ตฌํ˜„ ์ดˆ๊ธฐ์˜ ์ฝ”๋“œ๋ผ ๋ถ€์กฑํ•œ ๋ถ€๋ถ„์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–‘ํ•ดํ•ด์ฃผ์„ธ์š”!
  • ํ๋ฆ„์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๋ฉ”์„œ๋“œ ์•ˆ์—์„œ ๋ชจ๋“  ์ฒ˜๋ฆฌ๋ฅผ ์ง์ ‘ ํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ๋‹จ์ˆœํ™”ํ•จ

 

 

์นด์นด์˜คํŽ˜์ด ๊ฒฐ์ œ ์ค€๋น„ ์š”์ฒญ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ
REST ์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
  • @RestController 
  • public class KakaoPayController
    • @PostMapping("/api/pay/kakaopay")
      public ResponseEntity<?> processKakaoPayRequest(@RequestBody OrderInfoDTO orderInfoDTO)
@Transactional
@PostMapping("/api/pay/kakaopay")
public ResponseEntity<?> processKakaoPayRequest(@RequestBody OrderInfoDTO orderInfoDTO) {
    try {
        // ์‚ฌ์šฉ์ž ์ •๋ณด
        String userEmail = SecurityUtils.getCurrentUserEmail();
        Long userId = SecurityUtils.getCurrentUserId();

        // ํฌ์ธํŠธ ๋ฐ ๊ฒฐ์ œ ๊ธˆ์•ก ๊ณ„์‚ฐ
        int total_amount = orderInfoDTO.getPoint_100_Quantity() * 110 + orderInfoDTO.getPoint_1000_Quantity() * 1000;
        int totalPointAmount = orderInfoDTO.getPoint_100_Quantity() * 100 + orderInfoDTO.getPoint_1000_Quantity() * 1000;

        // ๊ฒฐ์ œ ์š”์ฒญ ๊ฐ์ฒด ์ค€๋น„
        KakaoPaymentReadyRequestDTO requestDTO = KakaoPaymentReadyRequestDTO.builder()
            .cid(kakaoPayConfig.getCid())
            .partner_order_id(orderInfoDTO.getPaymentId())
            .partner_user_id(userEmail)
            .item_name("RiddleBox ํฌ์ธํŠธ")
            .item_code("RB-Point")
            .quantity(1)
            .total_amount(total_amount)
            .tax_free_amount(500)
            .approval_url("http://localhost:8080/kakaopay/approval_url")
            .cancel_url("http://localhost:8080/kakaopay/approval_url")
            .fail_url("http://localhost:8080/kakaopay/approval_url")
            .build();

        // ๊ฒฐ์ œ ์ •๋ณด ์ƒ์„ฑ
        PaymentInfo paymentInfo = new PaymentInfo();
        RBUser user = userRepository.findById(userId).orElseThrow(() -> new EntityNotFoundException("User not found"));
        paymentInfo.firstPaymentInformation(user, orderInfoDTO.getPaymentId(), userEmail, "RiddleBox ํฌ์ธํŠธ", "RB-Point", total_amount, totalPointAmount);
        paymentInfo.updatePaymentStatus(PaymentStatus.INITIATED);
        paymentInfoRepository.save(paymentInfo);

        // ์นด์นด์˜คํŽ˜์ด API ํ˜ธ์ถœ
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", "SECRET_KEY " + kakaoPayConfig.getSecretKeyDev());

        String jsonRequest;
        try {
            jsonRequest = objectMapper.writeValueAsString(requestDTO);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Error converting PaymentRequestDTO to JSON", e);
        }

        String kakaopayReadyRequestUrl = kakaoPayConfig.getReadyRequestUriCompletion();
        HttpEntity<String> entity = new HttpEntity<>(jsonRequest, headers);

        ResponseEntity<String> response = restTemplate.postForEntity(kakaopayReadyRequestUrl, entity, String.class);

        if (!response.getStatusCode().is2xxSuccessful()) {
            throw new RuntimeException("์นด์นด์˜คํŽ˜์ด ํ˜ธ์ถœ ์‹คํŒจ");
        }

        // ์‘๋‹ต ์ฒ˜๋ฆฌ
        KakaoPaymentReadyResponseDTO responseDTO = objectMapper.readValue(response.getBody(), KakaoPaymentReadyResponseDTO.class);
        paymentInfo.secondPaymentInformation(responseDTO.getTid(), responseDTO.getCreated_at());
        paymentInfo.updatePaymentStatus(PaymentStatus.AWAITING_PAYMENT);
        paymentInfoRepository.save(paymentInfo);

        // ์‚ฌ์šฉ์ž์—๊ฒŒ ์นด์นด์˜ค ๊ฒฐ์ œ QR ๋งํฌ ์ „๋‹ฌ
        return ResponseEntity.ok(Collections.singletonMap("nextRedirectPcUrl", responseDTO.getNext_redirect_pc_url()));
    } catch (EntityNotFoundException e) {
        return new ResponseEntity<>("์‚ฌ์šฉ์ž๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.", HttpStatus.NOT_FOUND);
    } catch (JsonProcessingException e) {
        return new ResponseEntity<>("์„œ๋ฒ„ ์˜ค๋ฅ˜๋กœ ์ธํ•ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.", HttpStatus.INTERNAL_SERVER_ERROR);
    } catch (RuntimeException e) {
        return new ResponseEntity<>("๋‚ด๋ถ€ ์„œ๋ฒ„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.", HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

 

 

 

 

 

์นด์นด์˜คํŽ˜์ด ๊ฒฐ์ œ ์Šน์ธ ์š”์ฒญ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ
์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
  • @Controller
  • public class PointController
    • //์นด์นด์˜คํŽ˜์ด์˜ ์‘๋‹ต(์„ฑ๊ณต, ์ทจ์†Œ, ์‹คํŒจ)์„ ๋‹ค๋ฃจ
    • public String handleKakaoPayResponse(@RequestParam(value = "pg_token", required = false) String pgToken, HttpServletRequest request, Model model) 
@Transactional
@GetMapping("/kakaopay/approval_url")
public String handleKakaoPayResponse(@RequestParam(value = "pg_token", required = false) String pgToken,
HttpServletRequest request, Model model) throws JsonProcessingException {

    // ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž ID๋ฅผ ํ†ตํ•ด ๋Œ€๊ธฐ ์ค‘์ธ ๊ฒฐ์ œ ์ •๋ณด ์กฐํšŒ
    Long currentUserId = SecurityUtils.getCurrentUserId();
    PaymentInfo paymentInfo = kakaoPayService.findAwaitingPaymentPaymentInfo(currentUserId);
    
    // pg_token ์œ ๋ฌด ํ™•์ธ
    if (pgToken == null || pgToken.isEmpty()) {
        paymentInfo.updatePaymentStatus(PaymentStatus.FAILED);
        paymentInfoRepository.save(paymentInfo);
        // pg_token์ด ์—†๋Š” ๊ฒฝ์šฐ, ๊ฒฐ์ œ ์‹คํŒจ๋กœ ๊ฐ„์ฃผํ•˜๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ์•ˆ๋‚ด
        model.addAttribute("pageType", "paymentCompleted");
        model.addAttribute("title", "paymentCompleted");
        model.addAttribute("paymentResult", "Fail");
        return "layout/layout_base"; // ๊ฒฐ์ œ ์‹คํŒจ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
    }
    
    // pg_token์ด ์žˆ๋Š” ๊ฒฝ์šฐ, ๊ฒฐ์ œ ์Šน์ธ ์ฒ˜๋ฆฌ ์ง„ํ–‰
    String tid = paymentInfo.getTid();
    String partner_order_id = paymentInfo.getPartnerOrderId();
    String partner_user_id = paymentInfo.getPartnerUserId();
    String cid = kakaoPayConfig.getCid(); 
    
    paymentInfo.updatePaymentStatus(PaymentStatus.AUTHORIZED);
    paymentInfoRepository.save(paymentInfo);
    
    String pg_token = request.getParameter("pg_token");
    logger.debug("\n");
    logger.debug(" ===================  4  =================== ");
    logger.debug("pg_token: {}", pg_token);
    logger.debug("\n");
    
    // ์นด์นด์˜คํŽ˜์ด ๊ฒฐ์ œ ์Šน์ธ ์š”์ฒญ
    KakaoPaymentApproveRequestDTO approvalDTO = new KakaoPaymentApproveRequestDTO(cid, tid, partner_order_id, partner_user_id, pg_token);
    RestTemplate restTemplate2 = new RestTemplate();
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    headers.set("Authorization", "SECRET_KEY " + kakaoPayConfig.getSecretKeyDev());
    
    HttpEntity<KakaoPaymentApproveRequestDTO> entity = new HttpEntity<>(approvalDTO, headers);
    
    logger.debug("\n");
    logger.debug(" ===================  5  =================== ");
    logger.debug("HttpEntity<String> entity: {}", entity);
    logger.debug("\n");
    
    ResponseEntity<String> response = restTemplate2.postForEntity(kakaoPayConfig.getApproveRequestUriCompletion(), entity, String.class);
    
    logger.debug("\n");
    logger.debug(" ===================  6  =================== ");
    logger.debug("Response Status Code: {}", response.getStatusCode());
    logger.debug("Response Body: {}", response.getBody());
    logger.debug("\n");
    
    String responseBody = response.getBody();
    
    if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
        // ๊ฒฐ์ œ ์Šน์ธ ์„ฑ๊ณต, ๊ฒฐ์ œ ์ •๋ณด ์—…๋ฐ์ดํŠธ
        KakaoPaymentApproveResponseDTO completionDTO = objectMapper.readValue(responseBody, KakaoPaymentApproveResponseDTO.class);
        paymentInfo.thirdPaymentInformation(completionDTO.getAid(), completionDTO.getAmount(), completionDTO.getCardInfo(), completionDTO.getApprovedAt());
        paymentInfo.updatePaymentStatus(PaymentStatus.APPROVED);
        paymentInfoRepository.save(paymentInfo);
        
        //ํฌ์ธํŠธ ์ €์žฅ
        kakaoPayService.updateAccountBalanceAfterPurchase(currentUserId, paymentInfo.getTotalPointAmount());
        
        model.addAttribute("pageType", "paymentCompleted");
        model.addAttribute("title", "paymentCompleted");
        model.addAttribute("newPoint", paymentInfo.getTotalPointAmount());
        model.addAttribute("paymentResult", "Success");
        return "layout/layout_base";  // ๊ฒฐ์ œ ์„ฑ๊ณต ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
    } else {
        // ๊ฒฐ์ œ ์Šน์ธ ์‹คํŒจ ์ฒ˜๋ฆฌ
        paymentInfo.updatePaymentStatus(PaymentStatus.FAILED);
        paymentInfoRepository.save(paymentInfo);
        
        model.addAttribute("pageType", "paymentCompleted");
        model.addAttribute("title", "paymentCompleted");
        model.addAttribute("paymentResult", "Fail");
        return "layout/layout_base"; // ๊ฒฐ์ œ ์‹คํŒจ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
    }
}