Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: 결제 로직 구현 #10

Merged
merged 6 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing
@SpringBootApplication
public class ReadyverydemoApplication {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.readyvery.readyverydemo.src.payment;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.readyvery.readyverydemo.src.payment.dto.PaymentReq;
import com.readyvery.readyverydemo.src.payment.dto.TossPaymentRes;
import com.readyvery.readyverydemo.src.payment.dto.TossPaymentSuccessRes;

import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/api/v1/payments")
@RequiredArgsConstructor
public class PaymentController {
private final PaymentService paymentService;

@PostMapping("/toss") // 토스 결제 요청
public ResponseEntity<TossPaymentRes> requestTossPayment(@RequestBody PaymentReq paymentReq) {
TossPaymentRes tossPaymentRes = paymentService.requestTossPayment(paymentReq);
return new ResponseEntity<>(tossPaymentRes, HttpStatus.OK);
}

@GetMapping("/toss/success") // 토스 결제 성공
public ResponseEntity<TossPaymentSuccessRes> successTossPayment(
@RequestParam String paymentKey,
@RequestParam String orderId,
@RequestParam Long amount) {

return new ResponseEntity<>(
paymentService.tossPaymentSuccess(paymentKey, orderId, amount).toTossPaymentSuccessRes(),
HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.readyvery.readyverydemo.src.payment;

import com.readyvery.readyverydemo.src.payment.dto.PaymentReq;
import com.readyvery.readyverydemo.src.payment.dto.TossPaymentRes;
import com.readyvery.readyverydemo.src.payment.dto.toss.Payments;

public interface PaymentService {
TossPaymentRes requestTossPayment(PaymentReq paymentReq);

Payments tossPaymentSuccess(String paymentKey, String orderId, Long amount);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.readyvery.readyverydemo.src.payment;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collections;

import org.springframework.beans.factory.annotation.Autowired;
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.src.payment.config.TossPaymentConfig;
import com.readyvery.readyverydemo.src.payment.dto.PaymentReq;
import com.readyvery.readyverydemo.src.payment.dto.TossPaymentRes;
import com.readyvery.readyverydemo.src.payment.dto.toss.Payments;

@Service
public class PaymentServiceImpl implements PaymentService {
@Autowired
TossPaymentConfig tosspaymentConfig;

@Override
public TossPaymentRes requestTossPayment(PaymentReq paymentReq) {
Long amount = calculateTotalAmount();

return null;
}

private Long calculateTotalAmount() {
//TODO: 장바구니, 장바구니 상세에서 총 금액 계산
return 0L;
}

@Override
public Payments tossPaymentSuccess(String paymentKey, String orderId, Long amount) {
// TODO: 검증, 결제 완료 처리
Payments result = requestTossPaymentAccept(paymentKey, orderId, amount);

return null;
}

private Payments 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);

Payments result = null;
try {
result = restTemplate.postForObject(TossPaymentConfig.CONFIRM_URL,
new HttpEntity<>(params, headers),
Payments.class);
} catch (Exception e) {
throw new RuntimeException(); // 추후에 오류 수정 (이미 승인 됨)
}

return result;
}

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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.readyvery.readyverydemo.src.payment.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import lombok.Getter;

@Configuration
@Getter
public class TossPaymentConfig {
public static final String CONFIRM_URL = "https://api.tosspayments.com/v1/payments/confirm";

@Value("${payment.toss.client_key}")
private String tossClientKey;

@Value("${payment.toss.secret_key}")
private String tossSecretKey;

@Value("${payment.toss.success_url}")
private String tossSuccessUrl;

@Value("${payment.toss.fail_url}")
private String tossFailUrl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.readyvery.readyverydemo.src.payment.dto;

public class PaymentReq {
private Long storeId;
private Long coupon;
//TODO: 장바구니, 장바구니 상세 추가
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.readyvery.readyverydemo.src.payment.dto;

public class TossPaymentRes {
private String payType;
private Long amount;
private String orderId;
private String orderName;
private String customerName;
private String customerEmail;
private String successUrl;
private String failUrl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.readyvery.readyverydemo.src.payment.dto;

public class TossPaymentSuccessDto {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.readyvery.readyverydemo.src.payment.dto;

import java.time.LocalDateTime;

import lombok.Builder;

@Builder
public class TossPaymentSuccessRes {
private String orderId;
private String orderName;
private String method;
private Long totalAmount;
private String status;
private LocalDateTime requestedAt;
private LocalDateTime approvedAt;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

import java.time.LocalDateTime;

public class Cancels {
private Long cancelAmount;
private String cancelReason;
private Long taxFreeAmount;
private Long taxExemptionAmount;
private Long refundableAmount;
private Long easyPayDiscountAmount;
private LocalDateTime canceledAt;
private String transactionKey;
private String receiptKey;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

public class Card {
private Long amount;
private String issuerCode;
private String acquireCode;
private String number;
private Long installmentPlanMonths;
private String approveNo;
private Boolean useCardPoint;
private String cardType;
private String ownerType;
private String aquireStatus;
private Boolean isInterestFree;
private String interestPayer;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

public class CashReceipt {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

public class CashReceipts {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

public class Checkout {
private String url;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

public class Discount {
private Long amount;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

public class EasyPay {
private String provider;
private Long amount;
private Long discountAmount;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

public class Failure {
private String code;
private String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

public class GiftCertificate {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

public class MobliePhone {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

import java.time.LocalDateTime;

import com.readyvery.readyverydemo.src.payment.dto.TossPaymentSuccessRes;

public class Payments {
private String version;
private String paymentKey;
private String type;
private String orderId;
private String orderName;
private String mid;
private String currency;
private String method;
private Long totalAmount;
private Long balanceAmount;
private String status;
private LocalDateTime requestedAt;
private LocalDateTime approvedAt;
private Boolean useEscrow;
private String lastTransactionKey; // nullable
private Long suppliedAmount;
private Long vat;
private Boolean cultureExpense;
private Long taxFreeAmount;
private Long taxExemptedAmount;
private Cancels cancels;
private Boolean isPartialCancel;
private Card card;
private VirtualAccount virtualAccount;
private String secret;
private MobliePhone mobilePhone;
private GiftCertificate giftCertificate;
private Transfer transfer;
private Receipt receipt;
private Checkout checkout;
private EasyPay easyPay;
private String country;
private Failure failure;
private CashReceipt cashReceipt;
private CashReceipts cashReceipts;
private Discount discount;

public TossPaymentSuccessRes toTossPaymentSuccessRes() {
return TossPaymentSuccessRes.builder()
.orderId(orderId)
.orderName(orderName)
.method(method)
.totalAmount(totalAmount)
.status(status)
.requestedAt(requestedAt)
.approvedAt(approvedAt)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

public class Receipt {
private String url;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

public class Transfer {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.readyvery.readyverydemo.src.payment.dto.toss;

public class VirtualAccount {
}
6 changes: 6 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ spring.security.oauth2.client.provider.kakao.authorization-uri=https://kauth.kak
spring.security.oauth2.client.provider.kakao.token-uri=https://kauth.kakao.com/oauth/token
spring.security.oauth2.client.provider.kakao.user-info-uri=https://kapi.kakao.com/v2/user/me
spring.security.oauth2.client.provider.kakao.user-name-attribute=id
#payment
##tosspay
payment.toss.client_key=test_ck_pP2YxJ4K87By0b4RZeo0rRGZwXLO
payment.toss.secret_key=test_sk_pP2YxJ4K87BbBaQPDwEJrRGZwXLO
payment.toss.success_url=http://localhost:8080/api/v1/payment/toss/success
payment.toss.fail_url=http://localhost:8080/api/v1/payment/toss/fail