Skip to content

Commit d454274

Browse files
authored
결제 Controller 구현 (#289)
1 parent ce43835 commit d454274

22 files changed

+1499
-27
lines changed

src/main/java/com/back/domain/cart/repository/CartRepository.java

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,35 @@
1515
@Repository
1616
public interface CartRepository extends JpaRepository<Cart, Long> {
1717

18-
List<Cart> findByUser(User user);
19-
20-
List<Cart> findByUserAndCartType(User user, Cart.CartType cartType);
21-
22-
Optional<Cart> findByUserAndProduct(User user, Product product);
23-
18+
/**
19+
* 사용자와 상품, 장바구니 타입으로 조회
20+
*/
2421
Optional<Cart> findByUserAndProductAndCartType(User user, Product product, Cart.CartType cartType);
2522

26-
void deleteByUserAndProduct(User user, Product product);
27-
23+
/**
24+
* 사용자의 모든 장바구니 삭제
25+
*/
2826
int deleteByUser(User user);
2927

28+
/**
29+
* 사용자의 특정 타입 장바구니 삭제
30+
*/
3031
int deleteByUserAndCartType(User user, Cart.CartType cartType);
3132

32-
@Query("SELECT c FROM Cart c JOIN FETCH c.product p WHERE c.user = :user AND c.cartType = :cartType")
33-
List<Cart> findByUserAndCartTypeWithProduct(@Param("user") User user, @Param("cartType") Cart.CartType cartType);
34-
33+
/**
34+
* 사용자의 장바구니 조회 (상품 정보 포함, N+1 문제 해결)
35+
*/
3536
@Query("SELECT c FROM Cart c JOIN FETCH c.product p WHERE c.user = :user")
3637
List<Cart> findByUserWithProduct(@Param("user") User user);
3738

39+
/**
40+
* 선택된 장바구니 아이템 조회
41+
*/
3842
List<Cart> findByUserAndIsSelectedTrue(User user);
39-
40-
@Modifying
41-
@Query("DELETE FROM Cart c WHERE c.user = :user AND c.product.id IN :productIds")
42-
void deleteByUserAndProductIdIn(@Param("user") User user, @Param("productIds") List<Long> productIds);
4343

44+
/**
45+
* 주문 완료 후 장바구니에서 제거 (UUID 기반)
46+
*/
4447
@Modifying
4548
@Query("DELETE FROM Cart c WHERE c.user = :user AND c.product.productUuid IN :productUuids")
4649
void deleteByUserAndProductUuidIn(@Param("user") User user, @Param("productUuids") List<java.util.UUID> productUuids);
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.back.domain.payment.cash.controller;
2+
3+
import com.back.domain.payment.cash.dto.request.CashChargeRequestDto;
4+
import com.back.domain.payment.cash.dto.response.CashChargeResponseDto;
5+
import com.back.domain.payment.cash.service.CashChargeService;
6+
import com.back.domain.user.entity.User;
7+
import io.swagger.v3.oas.annotations.tags.Tag;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.http.ResponseEntity;
10+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
11+
import org.springframework.web.bind.annotation.*;
12+
13+
/**
14+
* 캐시 충전 Controller
15+
*/
16+
@Tag(name = "캐시 충전", description = "캐시 충전 관련 API")
17+
@RestController
18+
@RequestMapping("/api/cash/charge")
19+
@RequiredArgsConstructor
20+
public class CashChargeController {
21+
22+
private final CashChargeService cashChargeService;
23+
24+
/**
25+
* 캐시 충전 신청
26+
*/
27+
@PostMapping
28+
public ResponseEntity<CashChargeResponseDto> createChargeRequest(
29+
@RequestBody CashChargeRequestDto requestDto,
30+
@AuthenticationPrincipal User user) {
31+
32+
CashChargeResponseDto response = cashChargeService.createChargeRequest(requestDto, user);
33+
return ResponseEntity.ok(response);
34+
}
35+
36+
/**
37+
* 캐시 충전 완료 (PG 승인 후)
38+
*/
39+
@PostMapping("/{transactionId}/complete")
40+
public ResponseEntity<CashChargeResponseDto> completeCharge(
41+
@PathVariable Long transactionId,
42+
@RequestParam String paymentKey,
43+
@RequestParam String orderId) {
44+
45+
CashChargeResponseDto response = cashChargeService.completeCharge(transactionId, paymentKey, orderId);
46+
return ResponseEntity.ok(response);
47+
}
48+
49+
/**
50+
* 캐시 충전 실패
51+
*/
52+
@PostMapping("/{transactionId}/fail")
53+
public ResponseEntity<Void> failCharge(
54+
@PathVariable Long transactionId,
55+
@RequestParam String failureReason) {
56+
57+
cashChargeService.failCharge(transactionId, failureReason);
58+
return ResponseEntity.ok().build();
59+
}
60+
61+
/**
62+
* 캐시 충전 취소
63+
*/
64+
@PostMapping("/{transactionId}/cancel")
65+
public ResponseEntity<Void> cancelCharge(
66+
@PathVariable Long transactionId,
67+
@RequestParam String paymentKey,
68+
@RequestParam String cancellationReason) {
69+
70+
cashChargeService.cancelCharge(transactionId, paymentKey, cancellationReason);
71+
return ResponseEntity.ok().build();
72+
}
73+
}
74+
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.back.domain.payment.cash.controller;
2+
3+
import com.back.domain.payment.cash.dto.request.CashExchangeRequestDto;
4+
import com.back.domain.payment.cash.dto.response.CashExchangeResponseDto;
5+
import com.back.domain.payment.cash.service.CashExchangeService;
6+
import com.back.domain.user.entity.User;
7+
import io.swagger.v3.oas.annotations.tags.Tag;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.http.ResponseEntity;
10+
import org.springframework.security.access.prepost.PreAuthorize;
11+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
12+
import org.springframework.web.bind.annotation.*;
13+
14+
/**
15+
* 캐시 환전 Controller (작가 전용)
16+
*/
17+
@Tag(name = "캐시 환전", description = "캐시 환전 관련 API (작가 전용)")
18+
@RestController
19+
@RequestMapping("/api/cash/exchange")
20+
@RequiredArgsConstructor
21+
public class CashExchangeController {
22+
23+
private final CashExchangeService cashExchangeService;
24+
25+
/**
26+
* 환전 신청 (작가만 가능)
27+
*/
28+
@PostMapping
29+
@PreAuthorize("hasRole('ARTIST')")
30+
public ResponseEntity<CashExchangeResponseDto> createExchangeRequest(
31+
@RequestBody CashExchangeRequestDto requestDto,
32+
@AuthenticationPrincipal User artist) {
33+
34+
CashExchangeResponseDto response = cashExchangeService.createExchangeRequest(requestDto, artist);
35+
return ResponseEntity.ok(response);
36+
}
37+
38+
/**
39+
* 환전 승인 (관리자만 가능)
40+
*/
41+
@PostMapping("/{transactionId}/approve")
42+
@PreAuthorize("hasRole('ADMIN')")
43+
public ResponseEntity<CashExchangeResponseDto> approveExchange(
44+
@PathVariable Long transactionId,
45+
@RequestParam String pgTransactionId,
46+
@RequestParam String pgApprovalNumber) {
47+
48+
CashExchangeResponseDto response = cashExchangeService.approveExchange(
49+
transactionId, pgTransactionId, pgApprovalNumber);
50+
return ResponseEntity.ok(response);
51+
}
52+
53+
/**
54+
* 환전 거부 (관리자만 가능)
55+
*/
56+
@PostMapping("/{transactionId}/reject")
57+
@PreAuthorize("hasRole('ADMIN')")
58+
public ResponseEntity<Void> rejectExchange(
59+
@PathVariable Long transactionId,
60+
@RequestParam String reason) {
61+
62+
cashExchangeService.rejectExchange(transactionId, reason);
63+
return ResponseEntity.ok().build();
64+
}
65+
}
66+

src/main/java/com/back/domain/payment/cash/dto/response/CashChargeResponseDto.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public class CashChargeResponseDto {
2121

2222
private Long transactionId; // 거래 ID
2323
private Long userId; // 사용자 ID
24+
private String orderId; // 주문 ID (토스 결제창에 전달용, format: CHARGE_{transactionId})
2425
private Integer amount; // 충전 금액
2526
private CashTransactionStatus status; // 거래 상태
2627
private String paymentMethod; // 결제 수단
@@ -35,6 +36,7 @@ public static CashChargeResponseDto from(CashTransaction transaction) {
3536
return CashChargeResponseDto.builder()
3637
.transactionId(transaction.getId())
3738
.userId(transaction.getUser().getId())
39+
.orderId("CHARGE_" + transaction.getId()) // Webhook용 orderId 생성
3840
.amount(transaction.getAmount())
3941
.status(transaction.getStatus())
4042
.paymentMethod(transaction.getPgProvider())
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.back.domain.payment.moriCash.controller;
2+
3+
import com.back.domain.payment.moriCash.dto.response.MoriCashBalanceResponseDto;
4+
import com.back.domain.payment.moriCash.dto.response.MoriCashPaymentResponseDto;
5+
import com.back.domain.payment.moriCash.service.MoriCashBalanceService;
6+
import com.back.domain.user.entity.User;
7+
import io.swagger.v3.oas.annotations.tags.Tag;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.data.domain.Page;
10+
import org.springframework.data.domain.Pageable;
11+
import org.springframework.data.domain.Sort;
12+
import org.springframework.data.web.PageableDefault;
13+
import org.springframework.http.ResponseEntity;
14+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
15+
import org.springframework.web.bind.annotation.*;
16+
17+
/**
18+
* 모리캐시 잔액 Controller
19+
*/
20+
@Tag(name = "모리캐시 잔액", description = "모리캐시 잔액 및 거래 내역 조회 API")
21+
@RestController
22+
@RequestMapping("/api/moricash/balance")
23+
@RequiredArgsConstructor
24+
public class MoriCashBalanceController {
25+
26+
private final MoriCashBalanceService moriCashBalanceService;
27+
28+
/**
29+
* 내 모리캐시 잔액 조회
30+
*/
31+
@GetMapping
32+
public ResponseEntity<MoriCashBalanceResponseDto> getMyBalance(
33+
@AuthenticationPrincipal User user) {
34+
35+
MoriCashBalanceResponseDto response = moriCashBalanceService.getBalance(user);
36+
return ResponseEntity.ok(response);
37+
}
38+
39+
/**
40+
* 내 모리캐시 거래 내역 조회 (충전/사용 모두)
41+
*/
42+
@GetMapping("/history")
43+
public ResponseEntity<Page<MoriCashPaymentResponseDto>> getMyHistory(
44+
@AuthenticationPrincipal User user,
45+
@PageableDefault(size = 20, sort = "createdDate", direction = Sort.Direction.DESC) Pageable pageable) {
46+
47+
Page<MoriCashPaymentResponseDto> response = moriCashBalanceService.getHistory(user, pageable);
48+
return ResponseEntity.ok(response);
49+
}
50+
}
51+
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.back.domain.payment.moriCash.controller;
2+
3+
import com.back.domain.payment.moriCash.dto.request.MoriCashPaymentRequestDto;
4+
import com.back.domain.payment.moriCash.dto.response.MoriCashPaymentResponseDto;
5+
import com.back.domain.payment.moriCash.service.MoriCashPaymentService;
6+
import com.back.domain.user.entity.User;
7+
import io.swagger.v3.oas.annotations.tags.Tag;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.data.domain.Page;
10+
import org.springframework.data.domain.Pageable;
11+
import org.springframework.data.domain.Sort;
12+
import org.springframework.data.web.PageableDefault;
13+
import org.springframework.http.ResponseEntity;
14+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
15+
import org.springframework.web.bind.annotation.*;
16+
17+
/**
18+
* 모리캐시 결제 Controller
19+
*/
20+
@Tag(name = "모리캐시 결제", description = "모리캐시 결제 관련 API")
21+
@RestController
22+
@RequestMapping("/api/moricash/payments")
23+
@RequiredArgsConstructor
24+
public class MoriCashPaymentController {
25+
26+
private final MoriCashPaymentService moriCashPaymentService;
27+
28+
/**
29+
* 모리캐시 결제
30+
*/
31+
@PostMapping
32+
public ResponseEntity<MoriCashPaymentResponseDto> createPayment(
33+
@RequestBody MoriCashPaymentRequestDto requestDto,
34+
@AuthenticationPrincipal User user) {
35+
36+
MoriCashPaymentResponseDto response = moriCashPaymentService.createPayment(requestDto, user);
37+
return ResponseEntity.ok(response);
38+
}
39+
40+
/**
41+
* 모리캐시 결제 취소
42+
*/
43+
@PostMapping("/{paymentId}/cancel")
44+
public ResponseEntity<Void> cancelPayment(
45+
@PathVariable Long paymentId,
46+
@AuthenticationPrincipal User user) {
47+
48+
moriCashPaymentService.cancelPayment(paymentId, user);
49+
return ResponseEntity.ok().build();
50+
}
51+
52+
/**
53+
* 모리캐시 결제 상세 조회
54+
*/
55+
@GetMapping("/{paymentId}")
56+
public ResponseEntity<MoriCashPaymentResponseDto> getPayment(
57+
@PathVariable Long paymentId,
58+
@AuthenticationPrincipal User user) {
59+
60+
MoriCashPaymentResponseDto response = moriCashPaymentService.getPayment(paymentId, user);
61+
return ResponseEntity.ok(response);
62+
}
63+
64+
/**
65+
* 내 모리캐시 결제 내역 조회
66+
*/
67+
@GetMapping
68+
public ResponseEntity<Page<MoriCashPaymentResponseDto>> getMyPayments(
69+
@AuthenticationPrincipal User user,
70+
@PageableDefault(size = 20, sort = "createdDate", direction = Sort.Direction.DESC) Pageable pageable) {
71+
72+
Page<MoriCashPaymentResponseDto> response = moriCashPaymentService.getPayments(user, pageable);
73+
return ResponseEntity.ok(response);
74+
}
75+
}
76+

0 commit comments

Comments
 (0)