PaymentCommandService.java
package com.newbit.payment.command.application.service;
import com.newbit.auth.model.CustomUser;
import com.newbit.common.exception.BusinessException;
import com.newbit.common.exception.ErrorCode;
import com.newbit.notification.command.application.dto.request.NotificationSendRequest;
import com.newbit.notification.command.application.service.NotificationCommandService;
import com.newbit.payment.command.application.dto.TossPaymentApiDto;
import com.newbit.payment.command.application.dto.request.PaymentApproveRequest;
import com.newbit.payment.command.application.dto.request.PaymentPrepareRequest;
import com.newbit.payment.command.application.dto.response.PaymentApproveResponse;
import com.newbit.payment.command.application.dto.response.PaymentPrepareResponse;
import com.newbit.payment.command.domain.aggregate.Payment;
import com.newbit.payment.command.domain.aggregate.PaymentStatus;
import com.newbit.payment.command.domain.repository.PaymentRepository;
import com.newbit.purchase.command.application.service.DiamondTransactionCommandService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.UUID;
@Service
public class PaymentCommandService extends AbstractPaymentService<PaymentApproveResponse> {
private static final int DIAMOND_UNIT_PRICE = 100;
private final NotificationCommandService notificationCommandService;
private final DiamondTransactionCommandService diamondTransactionCommandService;
public PaymentCommandService(PaymentRepository paymentRepository, TossPaymentApiClient tossPaymentApiClient
, NotificationCommandService notificationCommandService
, DiamondTransactionCommandService diamondTransactionCommandService
) {
super(paymentRepository, tossPaymentApiClient);
this.notificationCommandService = notificationCommandService;
this.diamondTransactionCommandService = diamondTransactionCommandService;
}
@Transactional
public PaymentPrepareResponse preparePayment(PaymentPrepareRequest request) {
String orderId = generateOrderId();
Payment payment = Payment.createPayment(
request.getAmount(),
request.getPaymentMethod(),
request.getUserId(),
orderId,
request.getOrderName()
);
Payment savedPayment = paymentRepository.save(payment);
String paymentWidgetUrl = tossPaymentApiClient.createPaymentWidgetUrl(
savedPayment.getAmount().longValue(),
savedPayment.getOrderId(),
savedPayment.getOrderName() != null ? savedPayment.getOrderName() : "상품 결제"
);
return PaymentPrepareResponse.builder()
.paymentId(savedPayment.getPaymentId())
.orderId(savedPayment.getOrderId())
.orderName(savedPayment.getOrderName())
.amount(savedPayment.getAmount())
.paymentMethod(savedPayment.getPaymentMethod())
.paymentStatus(savedPayment.getPaymentStatus())
.paymentWidgetUrl(paymentWidgetUrl)
.build();
}
@Transactional
public PaymentApproveResponse approvePayment(PaymentApproveRequest request) {
Payment payment = paymentRepository.findByOrderId(request.getOrderId())
.orElseThrow(() -> new BusinessException(ErrorCode.PAYMENT_NOT_FOUND));
validateAmount(payment.getAmount(), BigDecimal.valueOf(request.getAmount()));
TossPaymentApiDto.PaymentResponse tossResponse = tossPaymentApiClient.requestPaymentApproval(
request.getPaymentKey(),
request.getOrderId(),
request.getAmount()
);
payment.updatePaymentKey(tossResponse.getPaymentKey());
payment.approve(tossResponse.getApprovedAtDateTime());
payment.updatePaymentStatus(PaymentStatus.DONE);
if (tossResponse.getReceipt() != null && tossResponse.getReceipt().get("url") != null) {
payment.updateReceiptUrl(tossResponse.getReceipt().get("url").toString());
}
Payment updatedPayment = paymentRepository.save(payment);
int diamondAmount = updatedPayment.getAmount().intValue() / DIAMOND_UNIT_PRICE;
diamondTransactionCommandService.applyDiamondPayment(
updatedPayment.getUserId()
, updatedPayment.getPaymentId()
, diamondAmount
);
String notificationContent = String.format("결제가 완료 되었습니다. (결제 금액: %,d)", updatedPayment.getAmount().intValue());
notificationCommandService.sendNotification(
new NotificationSendRequest(
updatedPayment.getUserId(),
14L,
payment.getPaymentId(),
notificationContent
)
);
return createPaymentApproveResponse(updatedPayment);
}
@Override
@Transactional(readOnly = true)
public PaymentApproveResponse getPayment(Long paymentId) {
Payment payment = findPaymentById(paymentId);
return createPaymentApproveResponse(payment);
}
@Transactional(readOnly = true)
public PaymentApproveResponse getPaymentByOrderId(String orderId) {
Payment payment = paymentRepository.findByOrderId(orderId)
.orElseThrow(() -> new BusinessException(ErrorCode.PAYMENT_NOT_FOUND));
return createPaymentApproveResponse(payment);
}
private String generateOrderId() {
return UUID.randomUUID().toString();
}
private PaymentApproveResponse createPaymentApproveResponse(Payment payment) {
return PaymentApproveResponse.builder()
.paymentId(payment.getPaymentId())
.orderId(payment.getOrderId())
.paymentKey(payment.getPaymentKey())
.amount(payment.getAmount())
.paymentMethod(payment.getPaymentMethod())
.paymentStatus(payment.getPaymentStatus())
.approvedAt(payment.getApprovedAt())
.receiptUrl(payment.getReceiptUrl())
.build();
}
}