Skip to content
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 @@ -88,11 +88,12 @@ public SecurityFilterChain authPublicFilterChain(HttpSecurity http) throws Excep
.build();
}


@Bean
@Order(6) // 기타 허용된 공개 엔드포인트
public SecurityFilterChain miscPublicFilterChain(HttpSecurity http) throws Exception {
return configureCommon(http)
.securityMatcher("/actuator/health", "/favicon.ico", "/public/**")
.securityMatcher("/actuator/health", "/favicon.ico", "/public/**", "/images/**", "/css/**", "/js/**")
.authorizeHttpRequests(request ->
request.anyRequest().permitAll()
)
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/com/fisa/pg/controller/AdminController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.fisa.pg.dto.response.ApiKeyResponseDto;
import com.fisa.pg.dto.response.BaseResponse;
import com.fisa.pg.dto.response.TransactionLogResponseDto;
import com.fisa.pg.dto.response.WebhookResponseDto;
import com.fisa.pg.service.AdminTransactionService;
import com.fisa.pg.service.ApiKeyService;
import com.fisa.pg.service.WebhookService;
import lombok.RequiredArgsConstructor;
Expand All @@ -28,6 +30,8 @@ public class AdminController {

private final WebhookService webhookService;

private final AdminTransactionService adminTransactionService;

/**
* 전체 API 키 목록 페이징 조회 API
*
Expand All @@ -41,6 +45,18 @@ public ResponseEntity<BaseResponse<Page<ApiKeyResponseDto>>> getApiKeyList(Pagea
return ResponseEntity.ok(BaseResponse.onSuccess("API 키 목록 조회 성공", data));
}

/**
* 전체 트랜잭션 로그 조회 API
*
* @param pageable 페이지 정보
* @return 트랜잭션 로그 응답 DTO 페이지
*/
@GetMapping("/transactions")
public ResponseEntity<BaseResponse<Page<TransactionLogResponseDto>>> getAllTransactions(Pageable pageable) {
Page<TransactionLogResponseDto> result = adminTransactionService.getAllTransactionLogs(pageable);
return ResponseEntity.ok(BaseResponse.onSuccess("전체 트랜잭션 조회 성공", result));
}

/**
* 관리자용 웹훅 목록 조회 API
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.fisa.pg.dto.response;

import com.fisa.pg.entity.payment.PaymentMethod;
import com.fisa.pg.entity.transaction.TransactionLog;
import com.fisa.pg.entity.transaction.TransactionStatus;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TransactionLogResponseDto {

/**
* 트랜잭션 로그 ID
*/
private String transactionId;

/**
* 트랜잭션 로그 메시지
*/
private String message;

/**
* 트랜잭션을 구성하는 금액
*/
private Long amount;

/**
* 트랜잭션 상태
*/
private TransactionStatus status;

/**
* 지불 방법
*/
private PaymentMethod method;

/**
* 트랜잭션 발생 시각
*/
private LocalDateTime date;

/**
* 가맹점 이름
*/
private String merchantName;

public static TransactionLogResponseDto from(TransactionLog transactionLog) {
return TransactionLogResponseDto.builder()
.transactionId(transactionLog.getTransaction().getTransactionId())
.message(transactionLog.getMessage())
.amount(transactionLog.getTransaction().getAmount())
.status(transactionLog.getStatus())
.method(transactionLog.getTransaction().getPayment().getPaymentMethod())
.date(transactionLog.getTransaction().getRequestedAt())
.merchantName(transactionLog.getMerchant().getName())
.build();
}
}
11 changes: 11 additions & 0 deletions src/main/java/com/fisa/pg/repository/TransactionLogRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.fisa.pg.repository;

import com.fisa.pg.entity.transaction.TransactionLog;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface TransactionLogRepository extends JpaRepository<TransactionLog, String> {

Page<TransactionLog> findAllByOrderByCreatedAtDesc(Pageable pageable);
}
27 changes: 27 additions & 0 deletions src/main/java/com/fisa/pg/service/AdminTransactionService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.fisa.pg.service;

import com.fisa.pg.dto.response.TransactionLogResponseDto;
import com.fisa.pg.repository.TransactionLogRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Slf4j
@Service
@RequiredArgsConstructor
public class AdminTransactionService {

private final TransactionLogRepository transactionLogRepository;

@Transactional(readOnly = true)
public Page<TransactionLogResponseDto> getAllTransactionLogs(Pageable pageable) {
log.info("[서비스 호출] 전체 트랜잭션 로그 조회 시작");

return transactionLogRepository.findAllByOrderByCreatedAtDesc(pageable)
.map(TransactionLogResponseDto::from);
}
}
55 changes: 49 additions & 6 deletions src/main/java/com/fisa/pg/service/PaymentService.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.fisa.pg.entity.payment.PaymentMethod;
import com.fisa.pg.entity.payment.PaymentStatus;
import com.fisa.pg.entity.transaction.Transaction;
import com.fisa.pg.entity.transaction.TransactionLog;
import com.fisa.pg.entity.transaction.TransactionStatus;
import com.fisa.pg.entity.user.Merchant;
import com.fisa.pg.exception.AppCardAuthenticationFailedException;
Expand All @@ -24,10 +25,7 @@
import com.fisa.pg.feign.dto.card.request.CardPaymentApprovalRequestDto;
import com.fisa.pg.feign.dto.card.response.BaseResponse;
import com.fisa.pg.feign.dto.card.response.CardPaymentApprovalResponseDto;
import com.fisa.pg.repository.BinInfoRepository;
import com.fisa.pg.repository.PaymentRepository;
import com.fisa.pg.repository.TransactionRepository;
import com.fisa.pg.repository.UserCardRepository;
import com.fisa.pg.repository.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
Expand All @@ -53,6 +51,8 @@ public class PaymentService {

private final UserCardRepository userCardRepository;

private final TransactionLogRepository transactionLogRepository;

private static final SecureRandom random = new SecureRandom();

/**
Expand Down Expand Up @@ -102,7 +102,17 @@ public PaymentCreateResponseDto createPayment(PaymentCreateRequestDto request, M

transactionRepository.save(transaction);

// 4. 응답 반환
// 4. 트랜잭션 로그 생성
TransactionLog logEntry = TransactionLog.builder()
.transaction(transaction)
.message("결제 생성 완료")
.status(transaction.getTransactionStatus())
.merchant(merchant)
.createdAt(LocalDateTime.now())
.build();
transactionLogRepository.save(logEntry);

// 5. 응답 반환
return PaymentCreateResponseDto.from(payment, merchant);
}

Expand Down Expand Up @@ -141,6 +151,15 @@ public PaymentMethodUpdateResponseDto updatePaymentMethod(PaymentMethodUpdateReq

log.info("결제 수단 {}로 업데이트 완료: paymentId={}, txnId={}", method, payment.getId(), transaction.getTransactionId());

TransactionLog logEntry = TransactionLog.builder()
.transaction(transaction)
.message("결제 수단 업데이트: " + method)
.status(transaction.getTransactionStatus())
.merchant(payment.getMerchant())
.createdAt(LocalDateTime.now())
.build();
transactionLogRepository.save(logEntry);

// 결제 UI URL 생성 (11단계)
String redirectUrl = generatePaymentRedirectUrl(payment, method);

Expand Down Expand Up @@ -227,6 +246,14 @@ public CardPaymentApprovalResponseDto processPaymentApproval(AppCardPaymentReque
transaction.updateTransactionStatus(TransactionStatus.AUTH_FAILED);
transactionRepository.save(transaction);

transactionLogRepository.save(TransactionLog.builder()
.transaction(transaction)
.message("앱카드 인증 실패")
.status(transaction.getTransactionStatus())
.merchant(payment.getMerchant())
.createdAt(LocalDateTime.now())
.build());

// 인증 실패 예외 던짐
throw new AppCardAuthenticationFailedException(transactionId);
}
Expand All @@ -248,6 +275,14 @@ public CardPaymentApprovalResponseDto processPaymentApproval(AppCardPaymentReque
transaction.updateTransactionStatus(TransactionStatus.FAILED);
transactionRepository.save(transaction);

transactionLogRepository.save(TransactionLog.builder()
.transaction(transaction)
.message("지원하지 않는 카드사")
.status(transaction.getTransactionStatus())
.merchant(payment.getMerchant())
.createdAt(LocalDateTime.now())
.build());

// 카드사 미지원 예외 던짐
throw new UnsupportedIssuerException(transactionId, cardNumber);
}
Expand Down Expand Up @@ -286,8 +321,16 @@ public CardPaymentApprovalResponseDto processPaymentApproval(AppCardPaymentReque
);
transactionRepository.save(transaction);

transactionLogRepository.save(TransactionLog.builder()
.transaction(transaction)
.message("카드사 승인 완료")
.status(transaction.getTransactionStatus())
.merchant(payment.getMerchant())
.createdAt(LocalDateTime.now())
.build());

log.info("앱카드 서버에 결제 결과 전송 완료: txnId={}, status={}",
transactionId, payment.getPaymentStatus());
transactionId, payment.getPaymentStatus());

return approvalResponse;
}
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/com/fisa/pg/service/RefundService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@
import com.fisa.pg.entity.payment.Payment;
import com.fisa.pg.entity.payment.PaymentStatus;
import com.fisa.pg.entity.transaction.Transaction;
import com.fisa.pg.entity.transaction.TransactionLog;
import com.fisa.pg.entity.transaction.TransactionStatus;
import com.fisa.pg.feign.client.CardClient;
import com.fisa.pg.feign.dto.card.request.RefundRequestToCardDto;
import com.fisa.pg.feign.dto.card.response.RefundResponseFromCardDto;
import com.fisa.pg.repository.PaymentRepository;
import com.fisa.pg.repository.TransactionLogRepository;
import com.fisa.pg.repository.TransactionRepository;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

/**
* 환불 요청을 처리하는 서비스 클래스입니다.
*/
Expand All @@ -27,6 +31,7 @@ public class RefundService {
private final PaymentRepository paymentRepository;
private final TransactionRepository transactionRepository;
private final CardClient cardClient;
private final TransactionLogRepository transactionLogRepository;

/**
* 원큐오더 서버로부터의 환불 요청을 처리하고 카드사에 환불 요청을 위임한 후,
Expand Down Expand Up @@ -67,8 +72,24 @@ public RefundResponseToOneQOrderDto refund(RefundRequestFromOneQOrderDto request

// 아래 코드가 범인이다.
transaction.updateTransactionStatus(TransactionStatus.CANCELLED);

transactionLogRepository.save(TransactionLog.builder()
.transaction(transaction)
.message("결제 환불 성공")
.status(TransactionStatus.CANCELLED)
.merchant(payment.getMerchant())
.createdAt(LocalDateTime.now())
.build());
} else {
transaction.updateTransactionStatus(TransactionStatus.REFUND_FAILED);

transactionLogRepository.save(TransactionLog.builder()
.transaction(transaction)
.message("결제 환불 실패")
.status(TransactionStatus.REFUND_FAILED)
.merchant(payment.getMerchant())
.createdAt(LocalDateTime.now())
.build());
}

// 5. 최종 응답 생성
Expand Down