diff --git a/referral/src/main/kotlin/Referral.kt b/referral/src/main/kotlin/Referral.kt index f51b54e..4b65d8a 100644 --- a/referral/src/main/kotlin/Referral.kt +++ b/referral/src/main/kotlin/Referral.kt @@ -4,7 +4,7 @@ interface Referral { 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 7a48039..17c36cd 100644 --- a/referral/src/main/kotlin/ReferralRepo.kt +++ b/referral/src/main/kotlin/ReferralRepo.kt @@ -4,7 +4,7 @@ interface ReferralRepo { fun getUserReferralLink(userId: Long): String - fun getUserIdByLink(link: String): String + fun getUserIdByLink(link: String): Long? fun getInviterIdForUser(userId: Long): Long? diff --git a/referral/src/main/kotlin/ReferralService.kt b/referral/src/main/kotlin/ReferralService.kt index 2ff40ee..489e149 100644 --- a/referral/src/main/kotlin/ReferralService.kt +++ b/referral/src/main/kotlin/ReferralService.kt @@ -59,6 +59,7 @@ class ReferralService( totalIncome = referral.totalIncome, availableIncome = referral.availableIncome, holdBalance = referral.holdBalance, + referralLink = referral.referralLink ) } 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/dto/referral/ReferralRequest.java b/src/main/java/ru/soune/nocopy/dto/referral/ReferralRequest.java index 8185f14..d22a4f9 100644 --- a/src/main/java/ru/soune/nocopy/dto/referral/ReferralRequest.java +++ b/src/main/java/ru/soune/nocopy/dto/referral/ReferralRequest.java @@ -4,7 +4,6 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import ru.soune.nocopy.entity.user.AuthToken; @Data @AllArgsConstructor 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 index 9213bf2..902b022 100644 --- a/src/main/java/ru/soune/nocopy/handler/ReferralHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/ReferralHandler.java @@ -51,7 +51,6 @@ public class ReferralHandler implements RequestHandler { return null; } - private BaseResponse handleRefill(BaseRequest request, Long userId, Integer amount) { referralService.onUserAccountRefill(userId, amount); diff --git a/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java b/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java index 5c62223..58a6221 100644 --- a/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/RegRequestHandler.java @@ -35,8 +35,7 @@ public class RegRequestHandler implements RequestHandler { private final EmailService emailService; - //TODO add when add all referall -// private final ReferralService referralService; + private final ReferralService referralService; @Override public BaseResponse handle(BaseRequest request) throws ValidationException { @@ -85,8 +84,8 @@ public class RegRequestHandler implements RequestHandler { regAnswer.setToken(token); regAnswer.setVerified(true); regAnswer.setActive(true); - //TODO add when add all referall -// referralService.onRegister(authToken.getUser().getId(), regRequest.getReferralLink()); + + 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 index 3bc2fdf..f714ab7 100644 --- a/src/main/java/ru/soune/nocopy/service/referral/ReferralLevelProviderImpl.java +++ b/src/main/java/ru/soune/nocopy/service/referral/ReferralLevelProviderImpl.java @@ -1,20 +1,29 @@ 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.ArrayList; import java.util.List; +import java.util.stream.Collectors; @Component +@RequiredArgsConstructor public class ReferralLevelProviderImpl implements ReferralLevelProvider { + private final ReferralLevelRepository referralLevelRepository; + @Override public List getAvailableReferralLevels() { - // TODO + List entities = referralLevelRepository.findAll(); - return new ArrayList(); + return entities.stream() + .map(this::createReferralLevel) + .collect(Collectors.toList()); } @Override @@ -24,8 +33,51 @@ public class ReferralLevelProviderImpl implements ReferralLevelProvider { @Override public ReferralLevel getReferralLevelById(String levelId) { - // TODO + return createReferralLevel(referralLevelRepository.findById(levelId)); + } - return null; + 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 index ac9cdf5..b97b566 100644 --- a/src/main/java/ru/soune/nocopy/service/referral/ReferralRepoImpl.java +++ b/src/main/java/ru/soune/nocopy/service/referral/ReferralRepoImpl.java @@ -1,75 +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 { - @Override - public String getUserIdByLink(String link) { - // TODO - return ""; - } + private final ReferralJpaRepository referralRepository; + + private final UserRepository userRepository; @Override public @NotNull String getUserReferralLink(long userId) { - return ""; + 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) { - return 0L; + ru.soune.nocopy.entity.referral.Referral referral = referralRepository.findByUserId(userId); + return referral != null ? referral.getInviterId() : 0L; } @Override public @NotNull String getReferralLevelForUser(long userId) { - return ""; + ru.soune.nocopy.entity.referral.Referral referral = referralRepository.findByUserId(userId); + return referral != null ? referral.getLevelId() : ""; } @Override public @NotNull Referral getReferralByUserId(long userId) { - return null; + 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) { - return List.of(); + 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) { - return false; + try { + referralRepository.activateUser(userId); + return true; + } catch (Exception e) { + return false; + } } @Override public int getActiveInviteeForUser(long userId) { - return 0; + return referralRepository.countActiveInvitees(userId); } @Override public int getTotalInviteeForUser(long userId) { - return 0; + return referralRepository.countTotalInvitees(userId); } @Override public void upgradeReferralLevelForUser(long userId, @NotNull String newLevelId) { - + referralRepository.updateLevel(userId, newLevelId); } -} +} \ No newline at end of file