diff --git a/build.gradle b/build.gradle index 677e8c6..f7926a3 100644 --- a/build.gradle +++ b/build.gradle @@ -63,6 +63,8 @@ dependencies { implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.12.0' + implementation project(':referral') + } tasks.named('test') { diff --git a/referral/src/main/kotlin/Referral.kt b/referral/src/main/kotlin/Referral.kt index 0dd336b..4b65d8a 100644 --- a/referral/src/main/kotlin/Referral.kt +++ b/referral/src/main/kotlin/Referral.kt @@ -2,9 +2,9 @@ package ru.soune interface Referral { - val userId: String + val userId: Long val referralLink: String - val inviter: String? + val inviter: Long? val currentLevel: String val totalIncome: Int val availableIncome: Int diff --git a/referral/src/main/kotlin/ReferralRepo.kt b/referral/src/main/kotlin/ReferralRepo.kt index 54a6c49..17c36cd 100644 --- a/referral/src/main/kotlin/ReferralRepo.kt +++ b/referral/src/main/kotlin/ReferralRepo.kt @@ -2,32 +2,32 @@ package ru.soune interface ReferralRepo { - fun getUserReferralLink(userId: String): String + fun getUserReferralLink(userId: Long): String - fun getUserIdByLink(link: String): String + fun getUserIdByLink(link: String): Long? - fun getInviterIdForUser(userId: String): String? + fun getInviterIdForUser(userId: Long): Long? - fun getReferralLevelForUser(userId: String): String + fun getReferralLevelForUser(userId: Long): String - fun getReferralByUserId(userId: String): Referral + fun getReferralByUserId(userId: Long): Referral - fun getReferralInvitees(userId: String, pageSize: Int, pageNumber: Int): List + fun getReferralInvitees(userId: Long, pageSize: Int, pageNumber: Int): List // создаем новую запись в БД fun createReferralEntity(entity: Referral) // прибавить к totalIncome и availableIncome значение transferAmount - fun increaseIncome(userId: String, transferAmount: Int) + fun increaseIncome(userId: Long, transferAmount: Int) // установить active в true - fun activateUser(userId: String): Boolean + fun activateUser(userId: Long): Boolean // посчитать записи, у которых inviter == userId и active == true - fun getActiveInviteeForUser(userId: String): Int + fun getActiveInviteeForUser(userId: Long): Int // посчитать записи, у которых inviter == userId - fun getTotalInviteeForUser(userId: String): Int + fun getTotalInviteeForUser(userId: Long): Int - fun upgradeReferralLevelForUser(userId: String, newLevelId: String) + fun upgradeReferralLevelForUser(userId: Long, newLevelId: String) } \ No newline at end of file diff --git a/referral/src/main/kotlin/ReferralService.kt b/referral/src/main/kotlin/ReferralService.kt index bae3dc0..489e149 100644 --- a/referral/src/main/kotlin/ReferralService.kt +++ b/referral/src/main/kotlin/ReferralService.kt @@ -5,7 +5,7 @@ class ReferralService( private val referralRepo: ReferralRepo, ) { - fun onRegister(userId: String, inviterReferralLink: String?) { + fun onRegister(userId: Long, inviterReferralLink: String?) { val initialReferralLevel = referralLevelProvider.getInitialReferralLevelId() val referralLink = referralRepo.getUserReferralLink(userId) val inviter = inviterReferralLink?.let(referralRepo::getUserIdByLink) @@ -24,7 +24,7 @@ class ReferralService( referralRepo.createReferralEntity(referral) } - fun onUserAccountRefill(userId: String, transferAmount: Int) { + fun onUserAccountRefill(userId: Long, transferAmount: Int) { val wasActivated = referralRepo.activateUser(userId) val inviterId = referralRepo.getInviterIdForUser(userId) ?: return val currentInviterLevel = referralRepo.getReferralLevelForUser(inviterId) @@ -47,11 +47,11 @@ class ReferralService( referralLevelProvider.getAvailableReferralLevels() - fun getReferralLevelForUser(userId: String): ReferralLevel = + fun getReferralLevelForUser(userId: Long): ReferralLevel = referralRepo.getReferralLevelForUser(userId) .let { referralLevelProvider.getReferralLevelById(it) } - fun getReferralStatForUser(userId: String): ReferralStat { + fun getReferralStatForUser(userId: Long): ReferralStat { var referral = referralRepo.getReferralByUserId(userId) return ReferralStat( totalInvitee = referralRepo.getTotalInviteeForUser(userId), @@ -59,9 +59,10 @@ class ReferralService( totalIncome = referral.totalIncome, availableIncome = referral.availableIncome, holdBalance = referral.holdBalance, + referralLink = referral.referralLink ) } - fun getInviteeForUser(userId: String, pageSize: Int, pageNumber: Int): List = + fun getInviteeForUser(userId: Long, pageSize: Int, pageNumber: Int): List = referralRepo.getReferralInvitees(userId, pageSize, pageNumber) } \ No newline at end of file diff --git a/referral/src/main/kotlin/ReferralStat.kt b/referral/src/main/kotlin/ReferralStat.kt index 554a723..d9e6ae5 100644 --- a/referral/src/main/kotlin/ReferralStat.kt +++ b/referral/src/main/kotlin/ReferralStat.kt @@ -6,4 +6,5 @@ data class ReferralStat( val totalIncome: Int, val availableIncome: Int, val holdBalance: Int, + val referralLink: String, ) \ No newline at end of file diff --git a/src/main/java/ru/soune/nocopy/configuration/HandlerConfig.java b/src/main/java/ru/soune/nocopy/configuration/HandlerConfig.java index b2d7862..933ee69 100644 --- a/src/main/java/ru/soune/nocopy/configuration/HandlerConfig.java +++ b/src/main/java/ru/soune/nocopy/configuration/HandlerConfig.java @@ -22,7 +22,8 @@ public class HandlerConfig { AuthRequestHandler authRequestHandler, CompanyHandler companyHandler, TariffHandler tariffHandler, - TariffInfoHandler tariffInfoHandler + TariffInfoHandler tariffInfoHandler, + ReferralHandler referralHandler ) { Map map = new HashMap<>(); map.put(20001, login); @@ -36,6 +37,7 @@ public class HandlerConfig { map.put(30000, companyHandler); map.put(30001, tariffHandler); map.put(30002, tariffInfoHandler); + map.put(30003, referralHandler); return map; } diff --git a/src/main/java/ru/soune/nocopy/configuration/ReferralConfig.java b/src/main/java/ru/soune/nocopy/configuration/ReferralConfig.java new file mode 100644 index 0000000..160e707 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/configuration/ReferralConfig.java @@ -0,0 +1,16 @@ +package ru.soune.nocopy.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.soune.ReferralLevelProvider; +import ru.soune.ReferralRepo; +import ru.soune.ReferralService; + +@Configuration +public class ReferralConfig { + + @Bean + public ReferralService referralService(ReferralLevelProvider referralLevelProvider, ReferralRepo referralRepo) { + return new ReferralService(referralLevelProvider, referralRepo); + } +} diff --git a/src/main/java/ru/soune/nocopy/dto/referral/ReferralRequest.java b/src/main/java/ru/soune/nocopy/dto/referral/ReferralRequest.java new file mode 100644 index 0000000..d22a4f9 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/dto/referral/ReferralRequest.java @@ -0,0 +1,18 @@ +package ru.soune.nocopy.dto.referral; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ReferralRequest { + private String token; + private Integer amount; + private Integer pageSize; + private Integer pageNumber; + private String action; +} diff --git a/src/main/java/ru/soune/nocopy/dto/register/RegRequest.java b/src/main/java/ru/soune/nocopy/dto/register/RegRequest.java index d9b630b..15d1c47 100644 --- a/src/main/java/ru/soune/nocopy/dto/register/RegRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/register/RegRequest.java @@ -29,4 +29,6 @@ public class RegRequest { private String password; private String authToken; + + private String referralLink; } diff --git a/src/main/java/ru/soune/nocopy/entity/referral/Referral.java b/src/main/java/ru/soune/nocopy/entity/referral/Referral.java new file mode 100644 index 0000000..d3d1036 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/entity/referral/Referral.java @@ -0,0 +1,37 @@ +package ru.soune.nocopy.entity.referral; + + +import jakarta.persistence.*; +import lombok.Data; +import org.springframework.data.annotation.CreatedDate; +import java.time.LocalDateTime; + +@Entity +@Table(name = "referrals") +@Data +public class Referral { + @Id + private Long userId; + + @Column(name = "referral_link", unique = true, nullable = false) + private String referralLink; + + @Column(name = "inviter_id") + private Long inviterId; + + @Column(name = "level_id") + private String levelId = "bronze"; + + @Column(name = "total_income") + private int totalIncome = 0; + + @Column(name = "is_active") + private boolean isActive = false; + + @CreatedDate + @Column(name = "created_at", updatable = false, nullable = false) + private LocalDateTime createdAt = LocalDateTime.now(); + + @Column(name = "hold_balance") + private int holdBalance = 0; +} diff --git a/src/main/java/ru/soune/nocopy/entity/referral/ReferralLevelEntity.java b/src/main/java/ru/soune/nocopy/entity/referral/ReferralLevelEntity.java new file mode 100644 index 0000000..9562db3 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/entity/referral/ReferralLevelEntity.java @@ -0,0 +1,21 @@ +package ru.soune.nocopy.entity.referral; + +import jakarta.persistence.*; +import lombok.Data; + +@Entity +@Table(name = "referral_levels") +@Data +public class ReferralLevelEntity { + @Id + private String id; + + @Column(nullable = false) + private String name; + + @Column(name = "min_invitees") + private int minInvitees; + + @Column(name = "reward_percentage") + private int rewardPercentage; +} diff --git a/src/main/java/ru/soune/nocopy/handler/ReferralHandler.java b/src/main/java/ru/soune/nocopy/handler/ReferralHandler.java new file mode 100644 index 0000000..902b022 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/handler/ReferralHandler.java @@ -0,0 +1,90 @@ +package ru.soune.nocopy.handler; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import ru.soune.ReferralInvitee; +import ru.soune.ReferralLevel; +import ru.soune.ReferralService; +import ru.soune.ReferralStat; +import ru.soune.nocopy.dto.BaseRequest; +import ru.soune.nocopy.dto.BaseResponse; +import ru.soune.nocopy.dto.MessageCode; +import ru.soune.nocopy.dto.referral.ReferralRequest; +import ru.soune.nocopy.entity.user.AuthToken; +import ru.soune.nocopy.repository.AuthTokenRepository; + +import java.util.List; +import java.util.Map; + + +@Component +@RequiredArgsConstructor +public class ReferralHandler implements RequestHandler { + + private final ReferralService referralService; + + private final AuthTokenRepository authTokenRepository; + + private final ObjectMapper mapper = new ObjectMapper(); + + @Override + public BaseResponse handle(BaseRequest request) throws Exception { + ReferralRequest referralRequest = mapper.convertValue(request.getMessageBody(), ReferralRequest.class); + String action = referralRequest.getAction(); + String token = referralRequest.getToken(); + AuthToken authToken = authTokenRepository.findByToken(token).orElseThrow(); + + switch (action) { + case "refill": + return handleRefill(request, authToken.getUser().getId(), referralRequest.getAmount()); + case "levels": + return handleReferralLevels(request); + case "level": + return handleUserLevel(request, authToken.getUser().getId()); + case "userStats" : + return handleUserStats(request, authToken.getUser().getId()); + case "invitees": + return handleInvitees(referralRequest, request, authToken.getUser().getId()); + } + + return null; + } + + private BaseResponse handleRefill(BaseRequest request, Long userId, Integer amount) { + referralService.onUserAccountRefill(userId, amount); + + return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), + MessageCode.SUCCESS.getDescription(), Map.of("account", "refill")); + } + + private BaseResponse handleReferralLevels(BaseRequest request) { + List referralLevels = referralService.getReferralLevels(); + + return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), + MessageCode.SUCCESS.getDescription(), referralLevels); + + } + + private BaseResponse handleUserLevel(BaseRequest request, Long userId) { + ReferralLevel referralLevelForUser = referralService.getReferralLevelForUser(userId); + + return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), + MessageCode.SUCCESS.getDescription(), referralLevelForUser); + } + + private BaseResponse handleUserStats(BaseRequest request, Long userId) { + ReferralStat referralStatForUser = referralService.getReferralStatForUser(userId); + + return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), + MessageCode.SUCCESS.getDescription(), referralStatForUser); + } + + private BaseResponse handleInvitees(ReferralRequest referralRequest, BaseRequest request, Long userId) { + List inviteeForUser = referralService.getInviteeForUser(userId, referralRequest.getPageSize(), + referralRequest.getPageNumber()); + + return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), + MessageCode.SUCCESS.getDescription(), inviteeForUser); + } +} diff --git a/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java b/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java index 6718fca..58a6221 100644 --- a/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java @@ -6,6 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.BindingResult; +import ru.soune.ReferralService; import ru.soune.nocopy.dto.*; import ru.soune.nocopy.dto.register.RegAnswer; import ru.soune.nocopy.dto.register.RegRequest; @@ -34,6 +35,8 @@ public class RegRequestHandler implements RequestHandler { private final EmailService emailService; + private final ReferralService referralService; + @Override public BaseResponse handle(BaseRequest request) throws ValidationException { RegRequest regRequest = objectMapper.convertValue(request.getMessageBody(), RegRequest.class); @@ -82,6 +85,8 @@ public class RegRequestHandler implements RequestHandler { regAnswer.setVerified(true); regAnswer.setActive(true); + referralService.onRegister(authToken.getUser().getId(), regRequest.getReferralLink()); + return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), MessageCode.SUCCESS.getDescription(), regAnswer); } diff --git a/src/main/java/ru/soune/nocopy/repository/ReferralJpaRepository.java b/src/main/java/ru/soune/nocopy/repository/ReferralJpaRepository.java new file mode 100644 index 0000000..db9c703 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/repository/ReferralJpaRepository.java @@ -0,0 +1,40 @@ +package ru.soune.nocopy.repository; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import ru.soune.nocopy.entity.referral.Referral; +import java.util.List; + +@Repository +public interface ReferralJpaRepository extends JpaRepository { + Referral findByReferralLink(String link); + + Referral findByUserId(Long userId); + + List findByInviterId(Long inviterId); + + @Query("SELECT r FROM Referral r WHERE r.inviterId = :userId AND r.isActive = true") + List findByInviterId(Long inviterId, Pageable pageable); + + @Modifying + @Query("UPDATE Referral r SET r.totalIncome = r.totalIncome + :amount WHERE r.userId = :userId") + void increaseIncome(@Param("userId") Long userId, @Param("amount") int amount); + + @Modifying + @Query("UPDATE Referral r SET r.levelId = :newLevelId WHERE r.userId = :userId") + void updateLevel(@Param("userId") Long userId, @Param("newLevelId") String newLevelId); + + @Modifying + @Query("UPDATE Referral r SET r.isActive = true WHERE r.userId = :userId") + void activateUser(@Param("userId") Long userId); + + @Query("SELECT COUNT(r) FROM Referral r WHERE r.inviterId = :userId AND r.isActive = true") + int countActiveInvitees(@Param("userId") Long userId); + + @Query("SELECT COUNT(r) FROM Referral r WHERE r.inviterId = :userId") + int countTotalInvitees(@Param("userId") Long userId); +} diff --git a/src/main/java/ru/soune/nocopy/repository/ReferralLevelRepository.java b/src/main/java/ru/soune/nocopy/repository/ReferralLevelRepository.java new file mode 100644 index 0000000..7a02874 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/repository/ReferralLevelRepository.java @@ -0,0 +1,13 @@ +package ru.soune.nocopy.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.soune.nocopy.entity.referral.ReferralLevelEntity; + +import java.util.List; + +@Repository +public interface ReferralLevelRepository extends JpaRepository { + List findAllByOrderByMinInviteesAsc(); + ReferralLevelEntity findById(String id); +} diff --git a/src/main/java/ru/soune/nocopy/service/referral/ReferralLevelProviderImpl.java b/src/main/java/ru/soune/nocopy/service/referral/ReferralLevelProviderImpl.java new file mode 100644 index 0000000..f714ab7 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/service/referral/ReferralLevelProviderImpl.java @@ -0,0 +1,83 @@ +package ru.soune.nocopy.service.referral; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import ru.soune.ReferralLevel; +import ru.soune.ReferralLevelProvider; +import ru.soune.nocopy.entity.referral.ReferralLevelEntity; +import ru.soune.nocopy.repository.ReferralLevelRepository; + + +import java.util.List; +import java.util.stream.Collectors; + +@Component +@RequiredArgsConstructor +public class ReferralLevelProviderImpl implements ReferralLevelProvider { + + private final ReferralLevelRepository referralLevelRepository; + + @Override + public List getAvailableReferralLevels() { + List entities = referralLevelRepository.findAll(); + + return entities.stream() + .map(this::createReferralLevel) + .collect(Collectors.toList()); + } + + @Override + public String getInitialReferralLevelId() { + return "bronze"; + } + + @Override + public ReferralLevel getReferralLevelById(String levelId) { + return createReferralLevel(referralLevelRepository.findById(levelId)); + } + + private ReferralLevel createReferralLevel(ReferralLevelEntity entity) { + return new ReferralLevel() { + @Override + public String getId() { + return entity.getId(); + } + + @Override + public String getName() { + return entity.getName(); + } + + @Override + public int getShare() { + return entity.getRewardPercentage(); + } + + @Override + public int getMinInvitee() { + return entity.getMinInvitees(); + } + + @Override + public int getMaxInvitee() { + switch (entity.getId()) { + case "bronze": return 9; + case "silver": return 49; + case "gold": return 99; + case "platinum": return Integer.MAX_VALUE; + default: return Integer.MAX_VALUE; + } + } + + @Override + public String getNext() { + switch (entity.getId()) { + case "bronze": return "silver"; + case "silver": return "gold"; + case "gold": return "platinum"; + default: return null; + } + } + }; + } +} \ No newline at end of file diff --git a/src/main/java/ru/soune/nocopy/service/referral/ReferralRepoImpl.java b/src/main/java/ru/soune/nocopy/service/referral/ReferralRepoImpl.java new file mode 100644 index 0000000..b97b566 --- /dev/null +++ b/src/main/java/ru/soune/nocopy/service/referral/ReferralRepoImpl.java @@ -0,0 +1,221 @@ +package ru.soune.nocopy.service.referral; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; +import ru.soune.Referral; +import ru.soune.ReferralInvitee; +import ru.soune.ReferralRepo; +import ru.soune.nocopy.entity.user.User; +import ru.soune.nocopy.repository.ReferralJpaRepository; +import ru.soune.nocopy.repository.UserRepository; + + +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Repository +@RequiredArgsConstructor +@Slf4j +@Transactional +public class ReferralRepoImpl implements ReferralRepo { + + private final ReferralJpaRepository referralRepository; + + private final UserRepository userRepository; + + @Override + public @NotNull String getUserReferralLink(long userId) { + ru.soune.nocopy.entity.referral.Referral referral = + referralRepository.findByUserId(userId); + + if (referral != null && referral.getReferralLink() != null && + !referral.getReferralLink().isEmpty()) { + return referral.getReferralLink(); + } + + String newLink = "ref-" + userId + "-" + UUID.randomUUID().toString().substring(0, 8); + + if (referral == null) { + referral = new ru.soune.nocopy.entity.referral.Referral(); + referral.setUserId(userId); + referral.setLevelId("bronze"); + referral.setActive(false); + } + + referral.setReferralLink(newLink); + + referralRepository.save(referral); + + return newLink; + } + + @Override + public @NotNull Long getUserIdByLink(@NotNull String link) { + ru.soune.nocopy.entity.referral.Referral referral = referralRepository.findByReferralLink(link); + return referral != null ? referral.getUserId() : 0L; + } + + @Override + public @Nullable Long getInviterIdForUser(long userId) { + ru.soune.nocopy.entity.referral.Referral referral = referralRepository.findByUserId(userId); + return referral != null ? referral.getInviterId() : 0L; + } + + @Override + public @NotNull String getReferralLevelForUser(long userId) { + ru.soune.nocopy.entity.referral.Referral referral = referralRepository.findByUserId(userId); + return referral != null ? referral.getLevelId() : ""; + } + + @Override + public @NotNull Referral getReferralByUserId(long userId) { + ru.soune.nocopy.entity.referral.Referral entity = referralRepository.findByUserId(userId); + + if (entity == null) { + return createDefaultReferral(userId); + } + + return new Referral() { + @Override + public long getUserId() { return entity.getUserId(); } + + @Override + public String getReferralLink() { return entity.getReferralLink(); } + + @Override + public Long getInviter() { + return entity.getInviterId() != null ? entity.getInviterId() : 0L; + } + + @Override + public String getCurrentLevel() { return entity.getLevelId(); } + + @Override + public int getTotalIncome() { return entity.getTotalIncome(); } + + @Override + public int getAvailableIncome() { + Integer holdBalance = entity.getHoldBalance(); + return entity.getTotalIncome() - (holdBalance != null ? holdBalance : 0); + } + + @Override + public int getHoldBalance() { + Integer holdBalance = entity.getHoldBalance(); + return holdBalance != null ? holdBalance : 0; + } + + @Override + public boolean getActive() { return entity.isActive(); } + }; + } + + private Referral createDefaultReferral(long userId) { + return new Referral() { + @Override + public long getUserId() { return userId; } + + @Override + public String getReferralLink() { return ""; } + + @Override + public Long getInviter() { return 0L; } + + @Override + public String getCurrentLevel() { return "bronze"; } + + @Override + public int getTotalIncome() { return 0; } + + @Override + public int getAvailableIncome() { return 0; } + + @Override + public int getHoldBalance() { return 0; } + + @Override + public boolean getActive() { return false; } + }; + } + + @Override + public @NotNull List getReferralInvitees(long userId, int pageSize, int pageNumber) { + Pageable pageable = PageRequest.of(pageNumber, pageSize); + List referrals = referralRepository.findByInviterId(userId, pageable); + + List result = new ArrayList<>(); + + for (ru.soune.nocopy.entity.referral.Referral referral : referrals) { + User user = userRepository.findById(referral.getUserId()).orElse(null); + + String email = user != null ? user.getEmail() : ""; + boolean isActive = referral.isActive(); + String regDate = referral.getCreatedAt() != null ? + referral.getCreatedAt().toString() : ""; + + try { + Constructor constructor = ReferralInvitee.class.getDeclaredConstructor( + String.class, boolean.class, String.class + ); + ReferralInvitee invitee = constructor.newInstance(email, isActive, regDate); + result.add(invitee); + } catch (Exception e) { + e.printStackTrace(); + } + } + + return result; + } + + @Override + public void createReferralEntity(@NotNull Referral entity) { + ru.soune.nocopy.entity.referral.Referral referral = new ru.soune.nocopy.entity.referral.Referral(); + referral.setUserId(entity.getUserId()); + referral.setReferralLink(entity.getReferralLink()); + referral.setInviterId(entity.getInviter()); + referral.setLevelId(entity.getCurrentLevel()); + referral.setTotalIncome(entity.getTotalIncome()); + referral.setHoldBalance(entity.getHoldBalance()); + referral.setActive(entity.getActive()); + + referralRepository.save(referral); + } + + @Override + public void increaseIncome(long userId, int transferAmount) { + referralRepository.increaseIncome(userId, transferAmount); + } + + @Override + public boolean activateUser(long userId) { + try { + referralRepository.activateUser(userId); + return true; + } catch (Exception e) { + return false; + } + } + + @Override + public int getActiveInviteeForUser(long userId) { + return referralRepository.countActiveInvitees(userId); + } + + @Override + public int getTotalInviteeForUser(long userId) { + return referralRepository.countTotalInvitees(userId); + } + + @Override + public void upgradeReferralLevelForUser(long userId, @NotNull String newLevelId) { + referralRepository.updateLevel(userId, newLevelId); + } +} \ No newline at end of file