Skip to content

Commit

Permalink
Merge pull request #34 from marinesnow34/payAllow
Browse files Browse the repository at this point in the history
Feat: 결제 성공 구현
  • Loading branch information
marinesnow34 authored Nov 20, 2023
2 parents 9434cd3 + b252f7d commit 160a296
Show file tree
Hide file tree
Showing 13 changed files with 277 additions and 3 deletions.
6 changes: 5 additions & 1 deletion src/main/java/com/readyvery/readyverydemo/domain/Order.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
Expand All @@ -20,14 +21,16 @@
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Getter
@Entity
@Builder
@Table(name = "ORDERS")
@Table(name = "ORDERS", indexes = {@Index(name = "idx_order_id", columnList = "orderId", unique = true)})
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Slf4j
public class Order {
@Id
Expand Down Expand Up @@ -70,6 +73,7 @@ public class Order {

// 가게 아이템 연관 관계
@OneToMany(mappedBy = "order")
@Builder.Default
private List<OrderItem> orderItems = new ArrayList<OrderItem>();

// 가게 연관 관계
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public class OrderItem {
private Foodie foodie;

@OneToMany(mappedBy = "orderItem")
@Builder.Default
private List<OrderItemOption> orderItemOptions = new ArrayList<OrderItemOption>();

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public enum Progress {
REQUEST("REQUEST", "토스 결제 요청"),
ORDER("ORDER", "주문 접수"),
MAKE("MAKE", "음식 제조 중"),
COMPLETE("COMPLETE", "배달 완료"),
COMPLETE("COMPLETE", "제조 완료"),
PICKUP("PICKUP", "픽업 완료");

private final String key;
Expand Down
88 changes: 88 additions & 0 deletions src/main/java/com/readyvery/readyverydemo/domain/Receipt.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.readyvery.readyverydemo.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.MapsId;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
Expand All @@ -21,7 +23,93 @@
@Slf4j
public class Receipt {
@Id
private Long id;

@OneToOne(fetch = FetchType.LAZY)
@MapsId
@JoinColumn(name = "order_idx")
private Order order;

@Column
private String type;

@Column
private String mid;

@Column
private String currency;

@Column
private Long balanceAmount;

@Column
private Long suppliedAmount;

@Column
private String status;

@Column
private String requestedAt;

@Column
private String approvedAt;

@Column
private String lastTransactionKey;

@Column
private Long vat;

@Column
private Long taxFreeAmount;

@Column
private Long taxExemptionAmount;

// @Column(columnDefinition = "json")
@Column
private String cancels;

// @Column(columnDefinition = "json")
@Column
private String card;

// @Column(columnDefinition = "json")
@Column
private String receipt;

// @Column(columnDefinition = "json")
@Column
private String checkout;

// @Column(columnDefinition = "json")
@Column
private String easyPay;

@Column
private String country;

// @Column(columnDefinition = "json")
@Column
private String failure;

// @Column(columnDefinition = "json")
@Column
private String discount;

// @Column(columnDefinition = "json")
@Column
private String virtualAccount;

// @Column(columnDefinition = "json")
@Column
private String transfer;

// @Column(columnDefinition = "json")
@Column
private String cashReceipt;

// @Column(columnDefinition = "json")
@Column
private String cashReceipts;
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,12 @@ public class UserInfo extends BaseTimeEntity {

// 유저 주문 연관관계 매핑
@OneToMany(mappedBy = "userInfo", cascade = CascadeType.ALL)
@Builder.Default
private List<Order> orders = new ArrayList<Order>();

// 유저 쿠폰 연관관계 매핑
@OneToMany(mappedBy = "userInfo", cascade = CascadeType.ALL)
@Builder.Default
private List<Coupon> coupons = new ArrayList<Coupon>();

// 리프레시토큰 업데이트
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.readyvery.readyverydemo.domain.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;

import com.readyvery.readyverydemo.domain.Order;

public interface OrdersRepository extends JpaRepository<Order, Long> {
Optional<Order> findByOrderId(String orderId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.readyvery.readyverydemo.domain.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.readyvery.readyverydemo.domain.Receipt;

public interface ReceiptRepository extends JpaRepository<Receipt, Long> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ public enum ExceptionCode {
OPTION_NOT_FOUND(404, "Option does not exists."),
CART_ITEM_NOT_FOUND(404, "Cart item does not exists."),
CART_NOT_FOUND(404, "Cart does not exists."),
ITEM_NOT_SAME_STORE(400, "Item is not same store.");
ITEM_NOT_SAME_STORE(400, "Item is not same store."),
TOSS_PAYMENT_SUCCESS_FAIL(400, "Toss payment success fail."),
ORDER_NOT_FOUND(400, "Order does not exists."),
TOSS_PAYMENT_AMOUNT_NOT_MATCH(400, "Toss payment amount not match.");

private int status;
private String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ public ResponseEntity<CartGetRes> getCart(@AuthenticationPrincipal CustomUserDet
return new ResponseEntity<>(cartGetRes, HttpStatus.OK);
}

@GetMapping("/toss/success")
public ResponseEntity<String> tossPaymentSuccess(
@RequestParam("paymentKey") String paymentKey,
@RequestParam("orderId") String orderId,
@RequestParam("amount") Long amount) {
String result = orderService.tossPaymentSuccess(paymentKey, orderId, amount);
return new ResponseEntity<>(result, HttpStatus.OK);
}

@PostMapping("/cart")
public ResponseEntity<CartAddRes> addCart(@AuthenticationPrincipal CustomUserDetails userDetails,
@RequestBody CartAddReq cartAddReq) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ public interface OrderService {
CartGetRes getCart(CustomUserDetails userDetails, Long inout);

TosspaymentMakeRes requestTossPayment(CustomUserDetails userDetails, PaymentReq paymentReq);

String tossPaymentSuccess(String paymentKey, String orderId, Long amount);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
package com.readyvery.readyverydemo.src.order;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import net.minidev.json.JSONObject;

import com.readyvery.readyverydemo.domain.Cart;
import com.readyvery.readyverydemo.domain.CartItem;
Expand All @@ -15,6 +24,7 @@
import com.readyvery.readyverydemo.domain.FoodieOptionCategory;
import com.readyvery.readyverydemo.domain.Order;
import com.readyvery.readyverydemo.domain.Progress;
import com.readyvery.readyverydemo.domain.Receipt;
import com.readyvery.readyverydemo.domain.Store;
import com.readyvery.readyverydemo.domain.UserInfo;
import com.readyvery.readyverydemo.domain.repository.CartItemRepository;
Expand All @@ -23,11 +33,14 @@
import com.readyvery.readyverydemo.domain.repository.FoodieOptionRepository;
import com.readyvery.readyverydemo.domain.repository.FoodieRepository;
import com.readyvery.readyverydemo.domain.repository.OrderRepository;
import com.readyvery.readyverydemo.domain.repository.OrdersRepository;
import com.readyvery.readyverydemo.domain.repository.ReceiptRepository;
import com.readyvery.readyverydemo.domain.repository.StoreRepository;
import com.readyvery.readyverydemo.domain.repository.UserRepository;
import com.readyvery.readyverydemo.global.exception.BusinessLogicException;
import com.readyvery.readyverydemo.global.exception.ExceptionCode;
import com.readyvery.readyverydemo.security.jwt.dto.CustomUserDetails;
import com.readyvery.readyverydemo.src.order.config.TossPaymentConfig;
import com.readyvery.readyverydemo.src.order.dto.CartAddReq;
import com.readyvery.readyverydemo.src.order.dto.CartAddRes;
import com.readyvery.readyverydemo.src.order.dto.CartEditReq;
Expand All @@ -40,6 +53,7 @@
import com.readyvery.readyverydemo.src.order.dto.FoodyDto;
import com.readyvery.readyverydemo.src.order.dto.OrderMapper;
import com.readyvery.readyverydemo.src.order.dto.PaymentReq;
import com.readyvery.readyverydemo.src.order.dto.TosspaymentDto;
import com.readyvery.readyverydemo.src.order.dto.TosspaymentMakeRes;

import lombok.RequiredArgsConstructor;
Expand All @@ -56,6 +70,9 @@ public class OrderServiceImpl implements OrderService {
private final StoreRepository storeRepository;
private final OrderRepository orderRepository;
private final OrderMapper orderMapper;
private final TossPaymentConfig tosspaymentConfig;
private final OrdersRepository ordersRepository;
private final ReceiptRepository receiptRepository;

@Override
public FoodyDetailRes getFoody(Long storeId, Long foodyId, Long inout) {
Expand Down Expand Up @@ -146,6 +163,67 @@ public TosspaymentMakeRes requestTossPayment(CustomUserDetails userDetails, Paym
return orderMapper.orderToTosspaymentMakeRes(order);
}

@Override
public String tossPaymentSuccess(String paymentKey, String orderId, Long amount) {
Order order = getOrder(orderId);
verifyOrder(order, amount);
TosspaymentDto tosspaymentDto = requestTossPaymentAccept(paymentKey, orderId, amount);
applyTosspaymentDto(order, tosspaymentDto);
orderRepository.save(order);
//TODO: 영수증 처리
Receipt receipt = orderMapper.tosspaymentDtoToReceipt(tosspaymentDto, order);
receiptRepository.save(receipt);
return "hi";
}

private void applyTosspaymentDto(Order order, TosspaymentDto tosspaymentDto) {
//TODO: orderNumber 적용
order.setPaymentKey(tosspaymentDto.getPaymentKey());
order.setMethod(tosspaymentDto.getMethod());
order.setProgress(Progress.ORDER);
}

private void verifyOrder(Order order, Long amount) {
if (!order.getTotalAmount().equals(amount)) {
throw new BusinessLogicException(ExceptionCode.TOSS_PAYMENT_AMOUNT_NOT_MATCH);
}
}

private Order getOrder(String orderId) {
return ordersRepository.findByOrderId(orderId).orElseThrow(
() -> new BusinessLogicException(ExceptionCode.ORDER_NOT_FOUND)
);
}

private TosspaymentDto requestTossPaymentAccept(String paymentKey, String orderId, Long amount) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = makeTossHeader();
JSONObject params = new JSONObject();

params.put("amount", amount);
params.put("orderId", orderId);
params.put("paymentKey", paymentKey);

try {
return restTemplate.postForObject(TossPaymentConfig.CONFIRM_URL,
new HttpEntity<>(params, headers),
TosspaymentDto.class);
} catch (Exception e) {
System.out.println("e.getMessage() = " + e.getMessage());
throw new BusinessLogicException(ExceptionCode.TOSS_PAYMENT_SUCCESS_FAIL);
}
}

private HttpHeaders makeTossHeader() {
HttpHeaders headers = new HttpHeaders();
String encodedAuthKey = new String(
Base64.getEncoder().encode((tosspaymentConfig.getTossSecretKey() + ":").getBytes(StandardCharsets.UTF_8)));
headers.setBasicAuth(encodedAuthKey);
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
return headers;
}

private Order makeOrder(UserInfo user, Store store, Long amount, List<FoodyDto> carts) {
if (carts.isEmpty()) {
throw new BusinessLogicException(ExceptionCode.CART_NOT_FOUND);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.readyvery.readyverydemo.domain.FoodieOption;
import com.readyvery.readyverydemo.domain.FoodieOptionCategory;
import com.readyvery.readyverydemo.domain.Order;
import com.readyvery.readyverydemo.domain.Receipt;
import com.readyvery.readyverydemo.src.order.config.TossPaymentConfig;

import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -152,4 +153,35 @@ public TosspaymentMakeRes orderToTosspaymentMakeRes(Order order) {
.amount(order.getAmount())
.build();
}

public Receipt tosspaymentDtoToReceipt(TosspaymentDto tosspaymentDto, Order order) {
return Receipt.builder()
.order(order)
.type(tosspaymentDto.getType())
.mid(tosspaymentDto.getMid())
.currency(tosspaymentDto.getCurrency())
.balanceAmount(tosspaymentDto.getBalanceAmount())
.suppliedAmount(tosspaymentDto.getSuppliedAmount())
.status(tosspaymentDto.getStatus())
.requestedAt(tosspaymentDto.getRequestedAt())
.approvedAt(tosspaymentDto.getApprovedAt())
.lastTransactionKey(tosspaymentDto.getLastTransactionKey())
.vat(tosspaymentDto.getVat())
.taxFreeAmount(tosspaymentDto.getTaxFreeAmount())
.taxExemptionAmount(tosspaymentDto.getTaxExemptionAmount())
.cancels(tosspaymentDto.getCancels() != null ? tosspaymentDto.getCancels().toString() : null)
.card(tosspaymentDto.getCard() != null ? tosspaymentDto.getCard().toString() : null)
.receipt(tosspaymentDto.getReceipt() != null ? tosspaymentDto.getReceipt().toString() : null)
.checkout(tosspaymentDto.getCheckout() != null ? tosspaymentDto.getCheckout().toString() : null)
.easyPay(tosspaymentDto.getEasyPay() != null ? tosspaymentDto.getEasyPay().toString() : null)
.country(tosspaymentDto.getCountry())
.failure(tosspaymentDto.getFailure() != null ? tosspaymentDto.getFailure().toString() : null)
.discount(tosspaymentDto.getDiscount() != null ? tosspaymentDto.getDiscount().toString() : null)
.virtualAccount(
tosspaymentDto.getVirtualAccount() != null ? tosspaymentDto.getVirtualAccount().toString() : null)
.transfer(tosspaymentDto.getTransfer() != null ? tosspaymentDto.getTransfer().toString() : null)
.cashReceipt(tosspaymentDto.getCashReceipt() != null ? tosspaymentDto.getCashReceipt().toString() : null)
.cashReceipts(tosspaymentDto.getCashReceipts() != null ? tosspaymentDto.getCashReceipts().toString() : null)
.build();
}
}
Loading

0 comments on commit 160a296

Please sign in to comment.