2026-02-20 20:51:14 +07:00
|
|
|
package ru.soune.nocopy.service.payout;
|
|
|
|
|
|
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
import ru.soune.nocopy.dto.payout.AddBankTransferRequest;
|
|
|
|
|
import ru.soune.nocopy.dto.payout.AddCardRequest;
|
|
|
|
|
import ru.soune.nocopy.dto.payout.PayoutMethodDTO;
|
2026-02-24 20:27:58 +07:00
|
|
|
import ru.soune.nocopy.entity.payout.*;
|
2026-02-20 20:51:14 +07:00
|
|
|
import ru.soune.nocopy.entity.user.User;
|
|
|
|
|
import ru.soune.nocopy.exception.DuplicateMethodException;
|
|
|
|
|
import ru.soune.nocopy.repository.PayoutMethodRepository;
|
|
|
|
|
import ru.soune.nocopy.repository.UserRepository;
|
|
|
|
|
import ru.soune.nocopy.service.user.UserService;
|
|
|
|
|
|
|
|
|
|
import java.security.MessageDigest;
|
|
|
|
|
import java.security.NoSuchAlgorithmException;
|
|
|
|
|
import java.util.Base64;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Optional;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
@Slf4j
|
|
|
|
|
@Service
|
|
|
|
|
@RequiredArgsConstructor
|
|
|
|
|
public class PayoutMethodService {
|
|
|
|
|
|
|
|
|
|
private final PayoutMethodRepository payoutMethodRepository;
|
|
|
|
|
|
|
|
|
|
private final UserRepository userRepository;
|
|
|
|
|
|
|
|
|
|
@Transactional
|
|
|
|
|
public void initiatedStandartPayoutMethods(User user) {
|
|
|
|
|
createInternalMethod(user);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Transactional
|
|
|
|
|
public InternalPayoutMethod createInternalMethod(User user) {
|
|
|
|
|
if (payoutMethodRepository.findByUserAndType(user.getId(), InternalPayoutMethod.class).isPresent()) {
|
|
|
|
|
return (InternalPayoutMethod) payoutMethodRepository.findByUserAndType(
|
|
|
|
|
user.getId(), InternalPayoutMethod.class).get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InternalPayoutMethod internalMethod = new InternalPayoutMethod();
|
|
|
|
|
internalMethod.setUser(user);
|
|
|
|
|
internalMethod.setDefault(true);
|
|
|
|
|
|
|
|
|
|
return payoutMethodRepository.save(internalMethod);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<PayoutMethodDTO> getUserMethods(long userId) {
|
|
|
|
|
return payoutMethodRepository.findByUserId(userId)
|
|
|
|
|
.stream()
|
|
|
|
|
.map(this::convertToDto)
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Transactional
|
|
|
|
|
public void setDefaultMethod(Long userId, Long methodId) {
|
|
|
|
|
payoutMethodRepository.clearOtherDefault(userId, methodId);
|
|
|
|
|
|
|
|
|
|
PayoutMethod method = payoutMethodRepository.findByIdAndUserId(methodId, userId)
|
|
|
|
|
.orElseThrow(() -> new IllegalArgumentException("Not found method"));
|
|
|
|
|
method.setDefault(true);
|
|
|
|
|
|
|
|
|
|
payoutMethodRepository.save(method);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Transactional
|
|
|
|
|
public BankTransferPayoutMethod addBankTransferMethod(Long userId, AddBankTransferRequest request) {
|
|
|
|
|
User user = userRepository.findById(userId).orElseThrow();
|
|
|
|
|
|
|
|
|
|
BankTransferPayoutMethod bankMethod = new BankTransferPayoutMethod();
|
|
|
|
|
bankMethod.setUser(user);
|
|
|
|
|
bankMethod.setBankName(request.getBankName());
|
|
|
|
|
bankMethod.setBic(request.getBic());
|
|
|
|
|
bankMethod.setCorrespondentAccount(request.getCorrespondentAccount());
|
|
|
|
|
bankMethod.setAccountNumber(request.getAccountNumber());
|
|
|
|
|
bankMethod.setAccountHolder(request.getAccountHolder());
|
|
|
|
|
bankMethod.setInn(request.getInn());
|
|
|
|
|
bankMethod.setKpp(request.getKpp());
|
|
|
|
|
bankMethod.setDefault(payoutMethodRepository.countByUserId(user.getId()) == 0);
|
|
|
|
|
|
|
|
|
|
return payoutMethodRepository.save(bankMethod);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Transactional
|
|
|
|
|
public CardPayoutMethod addCardMethod(Long userId, AddCardRequest request) {
|
2026-02-24 20:27:58 +07:00
|
|
|
List<PayoutMethod> byUserId = payoutMethodRepository.findByUserId(userId);
|
|
|
|
|
|
|
|
|
|
if (!byUserId.isEmpty()) {
|
|
|
|
|
for (PayoutMethod payoutMethod : byUserId) {
|
|
|
|
|
if (payoutMethod.getMethodType().equals(PayoutType.CARD.getDisplayName())) {
|
|
|
|
|
payoutMethodRepository.delete(payoutMethod);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-20 20:51:14 +07:00
|
|
|
String cardHash = generateCardHash(request.getCardNumber());
|
|
|
|
|
|
|
|
|
|
if (payoutMethodRepository.existsByCardHash(cardHash)) {
|
|
|
|
|
throw new DuplicateMethodException("Card was added");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
User user = userRepository.findById(userId).orElseThrow();
|
|
|
|
|
|
|
|
|
|
CardPayoutMethod cardMethod = new CardPayoutMethod();
|
|
|
|
|
cardMethod.setUser(user);
|
|
|
|
|
cardMethod.setCardNumber(request.getCardNumber());
|
|
|
|
|
cardMethod.setCardHash(cardHash);
|
|
|
|
|
cardMethod.setDefault(payoutMethodRepository.countByUserId(user.getId()) == 0);
|
|
|
|
|
|
|
|
|
|
CardPayoutMethod saved = payoutMethodRepository.save(cardMethod);
|
|
|
|
|
log.info("Added user card: {}", user.getId());
|
|
|
|
|
|
|
|
|
|
return saved;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public PayoutMethod getDefaultMethod(User user) {
|
|
|
|
|
return payoutMethodRepository.findByUserIdAndIsDefaultTrue(user.getId())
|
|
|
|
|
.orElseGet(() -> {
|
|
|
|
|
List<PayoutMethod> methods = payoutMethodRepository.findByUserId(user.getId());
|
|
|
|
|
if (methods.isEmpty()) {
|
|
|
|
|
return createInternalMethod(user);
|
|
|
|
|
}
|
|
|
|
|
return methods.get(0);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public PayoutMethodDTO convertToDto(PayoutMethod method) {
|
|
|
|
|
return PayoutMethodDTO.builder()
|
|
|
|
|
.id(method.getId())
|
|
|
|
|
.type(method.getClass().getSimpleName().replace("PayoutMethod", ""))
|
|
|
|
|
.displayName(method.getDisplayName())
|
|
|
|
|
.maskedDetails(method.getMaskedDetails())
|
|
|
|
|
.isDefault(method.isDefault())
|
|
|
|
|
.build();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String generateCardHash(String cardNumber) {
|
|
|
|
|
try {
|
|
|
|
|
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
|
|
|
|
byte[] hash = md.digest(cardNumber.getBytes());
|
|
|
|
|
return Base64.getEncoder().encodeToString(hash);
|
|
|
|
|
} catch (NoSuchAlgorithmException e) {
|
|
|
|
|
throw new RuntimeException("Failed generate hash", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|