Skip to content

Commit

Permalink
[Orders] 카카오 결제 환불 (#106)
Browse files Browse the repository at this point in the history
  • Loading branch information
winter0123 committed Jul 19, 2024
1 parent 8eee2cb commit a1cb33d
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ public enum BaseResponseMessage {
ORDERS_CREATED_FAIL(false, 5401, "주문 실패하였습니다."),
ORDERS_CREATED_FAIL_STOCK(false, 5401, "상품재고가 부족합니다."),
ORDERS_SEARCH_FAIL_ORDERED(false, 5111, "해당주문을 찾을 수 없습니다."),
ORDERS_CANCEL_SUCCESS_KAKAO(false, 5500, "카카오페이 결제 취소되었습니다."),
ORDERS_CANCEL_FAIL_KAKAO(false, 5501, "카카오페이 결제 취소 실패하였습니다."),

USER_CREATE_SUCCESS(true, 3200, "상품 등록이 완료되었습니다"),
USER_CREATE_FAIL(false,3201,"상품을 등록하는데 실패했습니다"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,21 @@ public AuthenticationManager authenticationManager(AuthenticationConfiguration a
}

// 카카오페이 테스트시 필요하여 넣음
// @Bean
// public CorsFilter corsFilter() {
// CorsConfiguration config = new CorsConfiguration();
//
// config.addAllowedOrigin("http://localhost:63342"); // 허용할 출처
// config.addAllowedOrigin("http://localhost:8080"); // 허용할 출처
// config.addAllowedMethod("*"); // 허용할 메서드 (GET, POST, PUT 등)
// config.addAllowedHeader("*"); // 허용할 헤더
// config.setAllowCredentials(true); // 자격 증명 허용
//
// UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// source.registerCorsConfiguration("/**", config);
//
// return new CorsFilter(source);
// }
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();

config.addAllowedOrigin("http://localhost:63342"); // 허용할 출처
config.addAllowedOrigin("http://localhost:8080"); // 허용할 출처
config.addAllowedMethod("*"); // 허용할 메서드 (GET, POST, PUT 등)
config.addAllowedHeader("*"); // 허용할 헤더
config.setAllowCredentials(true); // 자격 증명 허용

UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);

return new CorsFilter(source);
}

@Bean
public SecurityFilterChain filterChain (HttpSecurity http) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.team404x.greenplate.orders.service.OrdersService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
Expand Down Expand Up @@ -94,24 +95,27 @@ public BaseResponse inputInvoice(@RequestBody OrderInvoiceReq orderInvoiceReq) {

//String impUid
/** kakao pay 결제 **/
@PostMapping(value = "/kakao")
public ResponseEntity<String> kakao(@RequestBody OrderCreateReq orderCreateReq) throws IamportResponseException, IOException {

System.out.println(orderCreateReq.getUserId());
System.out.println(orderCreateReq.getTotalPrice());

@PostMapping(value = "/kakaoPay")
public ResponseEntity<String> kakaoPay(@RequestBody OrderCreateReq orderCreateReq) throws IamportResponseException, IOException {
IamportResponse<Payment> info = ordersService.getPaymentInfo(orderCreateReq.getImpUid());
BaseResponse result = ordersService.createOrder(orderCreateReq);

//if(resultPay) {
System.out.println(orderCreateReq.getImpUid());
Boolean payCheck = ordersService.payCheck(orderCreateReq,info);
if(payCheck) {
System.out.println("ok");

BaseResponse resultPay = ordersService.createOrder(orderCreateReq);
return ResponseEntity.ok("ok");
//}
// else {
// System.out.println("error");
// //paymentService.refund(impUid, info);
// return ResponseEntity.ok("error");
// }
}
else {
System.out.println("error");
ordersService.refund(orderCreateReq, info);
return ResponseEntity.ok("error");
}
}

/** kakao pay 결제 **/
@PostMapping(value = "/kakaoRefund")
public BaseResponse kakaoRefund(@RequestBody OrderCancelReq orderCancelReq) throws IamportResponseException, IOException {
BaseResponse result = ordersService.kakaoPayRefund(orderCancelReq);
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class Orders {
private String addressDetail;
private String phoneNum;
private String invoice;
private String impUid;

@ColumnDefault("false")
private Boolean delYn;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.team404x.greenplate.orders.model.response;

import lombok.Builder;
import lombok.Data;

import java.time.LocalDateTime;

@Data
@Builder
public class OrderUserSearchDetailRes {
private Long order_id;
private Long orderDetail_id;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.team404x.greenplate.orders.model.response;

import lombok.Builder;
import lombok.Data;

import java.time.LocalDateTime;

@Data
@Builder
public class OrderUserSearchRes {
private Long order_id;
private LocalDateTime order_date;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.team404x.greenplate.orders.service;

import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import com.google.gson.JsonObject;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.siot.IamportRestClient.IamportClient;
import com.siot.IamportRestClient.exception.IamportResponseException;
import com.siot.IamportRestClient.request.CancelData;
import com.siot.IamportRestClient.response.AccessToken;
import com.siot.IamportRestClient.response.IamportResponse;
import com.siot.IamportRestClient.response.Payment;
import com.team404x.greenplate.common.BaseResponse;
Expand All @@ -29,14 +30,21 @@
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedWriter;
import java.net.URL;
import java.time.LocalDateTime;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.*;

import static com.team404x.greenplate.common.BaseResponseMessage.*;

Expand All @@ -56,6 +64,11 @@ public class OrdersService {

JPAQueryFactory queryFactory;

@Value("${imp.imp_key}")
private String impKey;
@Value("${imp.imp_secret}")
private String impSecret;


@Transactional
public BaseResponse<OrderPaymentRes> chosePayment(OrderCreateReq orderCreateReq) {
Expand Down Expand Up @@ -108,6 +121,7 @@ public BaseResponse<String> createOrder(OrderCreateReq orderCreateReq) {
.addressDetail(orderCreateReq.getAddressDetail())
.phoneNum(orderCreateReq.getPhoneNum())
.refundYn(false)
.impUid(orderCreateReq.getImpUid())
.build();
orders = ordersRepository.save(orders);

Expand All @@ -132,7 +146,6 @@ public BaseResponse<String> createOrder(OrderCreateReq orderCreateReq) {

}
return new BaseResponse<>(ORDERS_CREATED_SUCCESS);

}

//유저 주문 상품 목록 조회
Expand All @@ -147,14 +160,15 @@ public BaseResponse<List<OrderUserSearchRes>> searchForUser(Long userId) {
List<OrderUserSearchRes> orderUserSearchResList = new ArrayList<OrderUserSearchRes>();
List<Orders> orders = ordersRepository.findAllByUser(user.get());
for(Orders order : orders){
OrderUserSearchRes orderUserSearchRes = new OrderUserSearchRes();
orderUserSearchRes.setOrder_id(order.getId());
orderUserSearchRes.setOrder_state(order.getOrderState());
orderUserSearchRes.setTotal_price(order.getTotalPrice());
orderUserSearchRes.setTotal_cnt(order.getTotalQuantity());
orderUserSearchRes.setRefund_yn(order.getRefundYn());
orderUserSearchRes.setOrder_date(order.getOrderDate());
orderUserSearchResList.add(orderUserSearchRes);
OrderUserSearchRes res = OrderUserSearchRes.builder()
.order_id(order.getId())
.order_state(order.getOrderState())
.total_price(order.getTotalPrice())
.total_cnt(order.getTotalQuantity())
.refund_yn(order.getRefundYn())
.order_date(order.getOrderDate())
.build();
orderUserSearchResList.add(res);
}
return new BaseResponse<>(orderUserSearchResList);
}
Expand All @@ -175,14 +189,18 @@ public BaseResponse<List<OrderUserSearchDetailRes>> searchForUserDetail(Long use

List<OrderUserSearchDetailRes> orderUserSearchResList = new ArrayList<OrderUserSearchDetailRes>();
for(OrderDetail orderDetail : orderDetailList){
OrderUserSearchDetailRes orderUserSearchDetailRes = new OrderUserSearchDetailRes();
orderUserSearchDetailRes.setOrder_id(orders2.getId());
orderUserSearchDetailRes.setOrder_state(orders2.getOrderState());
orderUserSearchDetailRes.setPrice(orderDetail.getPrice());
orderUserSearchDetailRes.setCnt(orderDetail.getCnt());
orderUserSearchDetailRes.setRefund_yn(orders2.getRefundYn());
orderUserSearchDetailRes.setOrder_date(orders2.getOrderDate());
orderUserSearchResList.add(orderUserSearchDetailRes);

OrderUserSearchDetailRes res = OrderUserSearchDetailRes.builder()
.order_id(orders2.getId())
.orderDetail_id(orderDetail.getId())
.order_state(orders2.getOrderState())
.price(orderDetail.getPrice())
.cnt(orderDetail.getCnt())
.refund_yn(orders2.getRefundYn())
.order_date(orders2.getOrderDate())
.build();
orderUserSearchResList.add(res);

}
return new BaseResponse<>(orderUserSearchResList);
}
Expand Down Expand Up @@ -212,20 +230,7 @@ public BaseResponse<List<OrdersQueryProjection>> searchForCompanyDetail(Long com
return new BaseResponse<>(ordersList);
}

//주문취소
@Transactional
public BaseResponse<String> cancelOrder(OrderCancelReq orderCancelReq) {
Optional<Orders> orders = ordersRepository.findById(orderCancelReq.getOrderId());

if (!orders.isPresent()) {
return new BaseResponse<>(ORDERS_SEARCH_FAIL_ORDERED);
}else{
Orders orders2 = orders.get();
orders2.refundOrder();
ordersRepository.save(orders2);
}
return new BaseResponse<>(ORDERS_CANCEL_SUCCESS);
}

//사업자 배송 상태 변경
@Transactional
Expand Down Expand Up @@ -264,15 +269,117 @@ public BaseResponse inputInvoice(OrderInvoiceReq orderInvoiceReq) {
return new BaseResponse<>(ORDERS_UPDATE_SUCCESS_INVOICE);
}

public IamportResponse<Payment> getPaymentInfo(String impUid) throws IamportResponseException, IOException {

//카카오페이 결제금액 체크
public Boolean payCheck(OrderCreateReq orderCreateReq, IamportResponse<Payment> iamportResponse) {
Long amount = iamportResponse.getResponse().getAmount().longValue();
if (amount != orderCreateReq.getTotalPrice()){
return false;
}else{
return true;
}
}

public IamportResponse<Payment> getPaymentInfo(String impUid) throws IamportResponseException, IOException {
return iamportClient.paymentByImpUid(impUid);
}

//카카오페이 결제중 환불
public IamportResponse refund(OrderCreateReq orderCreateReq, IamportResponse<Payment> info) throws IamportResponseException, IOException {
CancelData cancelData = new CancelData(orderCreateReq.getImpUid(), true, info.getResponse().getAmount());
return iamportClient.cancelPaymentByImpUid(cancelData);
}

//카카오페이 결제 완료 후 환불
public BaseResponse kakaoPayRefund(OrderCancelReq orderCancelReq) {
Optional<Orders> orders = ordersRepository.findById(orderCancelReq.getOrderId());
if (!orders.isPresent()) {
return new BaseResponse<>(ORDERS_SEARCH_FAIL_ORDERED);
}

String accessToken = getAccessToken(); //토큰 요청
if(requestsRefun(accessToken, orders.get())){ //카카오페이 결제 취소
cancelOrder(orderCancelReq); //주문취소 데이터 저장
return new BaseResponse<>(ORDERS_CANCEL_FAIL_KAKAO);
};

return new BaseResponse<>(ORDERS_CANCEL_SUCCESS_KAKAO);
}

//카카오페이 결제 취소용 TOKEN
public String getAccessToken() {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, "application/json");
headers.add(HttpHeaders.ACCEPT, "application/json");

Gson gson = new Gson();
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("imp_key", impKey);
jsonObject.addProperty("imp_secret", impSecret);
String jsonStr = gson.toJson(jsonObject);


HttpEntity<String> request = new HttpEntity<>(jsonStr, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(
"https://api.iamport.kr/users/getToken",
HttpMethod.POST,
request,
String.class
);

Map<String, Object> result = gson.fromJson(response.getBody(), Map.class);
Map<String, Object> data = (Map<String, Object>) result.get("response");
String access_token = (String) data.get("access_token");
return access_token;
}

//pg사 kakao 결제 취소 요청
public Boolean requestsRefun(String accessToken, Orders orders){
HttpHeaders headers = new HttpHeaders();
try{
headers.add(HttpHeaders.CONTENT_TYPE, "application/json");
headers.add(HttpHeaders.ACCEPT, "application/json");
headers.add(HttpHeaders.AUTHORIZATION, accessToken);

Gson gson = new Gson();
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("reason", "결제 정보가 이상합니다.");
jsonObject.addProperty("imp_uid", orders.getImpUid());
jsonObject.addProperty("amount", orders.getTotalPrice());
String jsonStr = gson.toJson(jsonObject);

HttpEntity<String> request = new HttpEntity<>(jsonStr, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(
"https://api.iamport.kr/payments/cancel",
HttpMethod.POST,
request,
String.class
);

Map<String, Object> result = gson.fromJson(response.getBody(), Map.class);
System.out.println(result);
}catch(Exception e){
return false;
}

return true;
}

//주문취소 데이터 저장
@Transactional
public BaseResponse<String> cancelOrder(OrderCancelReq orderCancelReq) {
Optional<Orders> orders = ordersRepository.findById(orderCancelReq.getOrderId());

if (!orders.isPresent()) {
return new BaseResponse<>(ORDERS_SEARCH_FAIL_ORDERED);
}else{
Orders orders2 = orders.get();
orders2.refundOrder();
ordersRepository.save(orders2);
}
return new BaseResponse<>(ORDERS_CANCEL_SUCCESS);
}


}
Loading

0 comments on commit a1cb33d

Please sign in to comment.