Compare commits
2 Commits
65d4de46a6
...
fb92993e39
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb92993e39 | ||
|
|
7d60ebacda |
@@ -113,7 +113,7 @@ public class UserController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets referrals for a specific level with pagination.
|
* Gets referrals for a specific level with pagination.
|
||||||
* Always returns 50 results per page.
|
* Returns 10 results per page, ordered by commission DESC, then id DESC.
|
||||||
*
|
*
|
||||||
* @param level The referral level (1, 2, or 3)
|
* @param level The referral level (1, 2, or 3)
|
||||||
* @param page Page number (0-indexed, defaults to 0)
|
* @param page Page number (0-indexed, defaults to 0)
|
||||||
|
|||||||
@@ -53,34 +53,34 @@ public interface UserDRepository extends JpaRepository<UserD, Integer> {
|
|||||||
/**
|
/**
|
||||||
* Finds referrals for level 1 (where referer_id_1 = userId).
|
* Finds referrals for level 1 (where referer_id_1 = userId).
|
||||||
* Returns referrals with their screen_name and to_referer_1 commission.
|
* Returns referrals with their screen_name and to_referer_1 commission.
|
||||||
|
* Ordered by commission DESC, then id DESC.
|
||||||
*/
|
*/
|
||||||
@Query("SELECT new com.honey.honey.dto.ReferralDto(" +
|
@Query("SELECT new com.honey.honey.dto.ReferralDto(ud.screenName, ud.toReferer1) " +
|
||||||
"ud.screenName, ud.toReferer1) " +
|
|
||||||
"FROM UserD ud " +
|
"FROM UserD ud " +
|
||||||
"WHERE ud.refererId1 = :userId AND ud.refererId1 > 0 " +
|
"WHERE ud.refererId1 = :userId AND ud.refererId1 > 0 " +
|
||||||
"ORDER BY ud.toReferer1 DESC")
|
"ORDER BY ud.toReferer1 DESC, ud.id DESC")
|
||||||
Page<ReferralDto> findReferralsLevel1(@Param("userId") Integer userId, Pageable pageable);
|
Page<ReferralDto> findReferralsLevel1(@Param("userId") Integer userId, Pageable pageable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds referrals for level 2 (where referer_id_2 = userId).
|
* Finds referrals for level 2 (where referer_id_2 = userId).
|
||||||
* Returns referrals with their screen_name and to_referer_2 commission.
|
* Returns referrals with their screen_name and to_referer_2 commission.
|
||||||
|
* Ordered by commission DESC, then id DESC.
|
||||||
*/
|
*/
|
||||||
@Query("SELECT new com.honey.honey.dto.ReferralDto(" +
|
@Query("SELECT new com.honey.honey.dto.ReferralDto(ud.screenName, ud.toReferer2) " +
|
||||||
"ud.screenName, ud.toReferer2) " +
|
|
||||||
"FROM UserD ud " +
|
"FROM UserD ud " +
|
||||||
"WHERE ud.refererId2 = :userId AND ud.refererId2 > 0 " +
|
"WHERE ud.refererId2 = :userId AND ud.refererId2 > 0 " +
|
||||||
"ORDER BY ud.toReferer2 DESC")
|
"ORDER BY ud.toReferer2 DESC, ud.id DESC")
|
||||||
Page<ReferralDto> findReferralsLevel2(@Param("userId") Integer userId, Pageable pageable);
|
Page<ReferralDto> findReferralsLevel2(@Param("userId") Integer userId, Pageable pageable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds referrals for level 3 (where referer_id_3 = userId).
|
* Finds referrals for level 3 (where referer_id_3 = userId).
|
||||||
* Returns referrals with their screen_name and to_referer_3 commission.
|
* Returns referrals with their screen_name and to_referer_3 commission.
|
||||||
|
* Ordered by commission DESC, then id DESC.
|
||||||
*/
|
*/
|
||||||
@Query("SELECT new com.honey.honey.dto.ReferralDto(" +
|
@Query("SELECT new com.honey.honey.dto.ReferralDto(ud.screenName, ud.toReferer3) " +
|
||||||
"ud.screenName, ud.toReferer3) " +
|
|
||||||
"FROM UserD ud " +
|
"FROM UserD ud " +
|
||||||
"WHERE ud.refererId3 = :userId AND ud.refererId3 > 0 " +
|
"WHERE ud.refererId3 = :userId AND ud.refererId3 > 0 " +
|
||||||
"ORDER BY ud.toReferer3 DESC")
|
"ORDER BY ud.toReferer3 DESC, ud.id DESC")
|
||||||
Page<ReferralDto> findReferralsLevel3(@Param("userId") Integer userId, Pageable pageable);
|
Page<ReferralDto> findReferralsLevel3(@Param("userId") Integer userId, Pageable pageable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,10 +13,12 @@ import com.honey.honey.model.CryptoDepositMethod;
|
|||||||
import com.honey.honey.model.Payment;
|
import com.honey.honey.model.Payment;
|
||||||
import com.honey.honey.model.UserA;
|
import com.honey.honey.model.UserA;
|
||||||
import com.honey.honey.model.UserB;
|
import com.honey.honey.model.UserB;
|
||||||
|
import com.honey.honey.model.UserD;
|
||||||
import com.honey.honey.repository.CryptoDepositMethodRepository;
|
import com.honey.honey.repository.CryptoDepositMethodRepository;
|
||||||
import com.honey.honey.repository.PaymentRepository;
|
import com.honey.honey.repository.PaymentRepository;
|
||||||
import com.honey.honey.repository.UserARepository;
|
import com.honey.honey.repository.UserARepository;
|
||||||
import com.honey.honey.repository.UserBRepository;
|
import com.honey.honey.repository.UserBRepository;
|
||||||
|
import com.honey.honey.repository.UserDRepository;
|
||||||
import com.honey.honey.util.IpUtils;
|
import com.honey.honey.util.IpUtils;
|
||||||
import com.honey.honey.util.TelegramTokenRedactor;
|
import com.honey.honey.util.TelegramTokenRedactor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -47,6 +49,7 @@ public class PaymentService {
|
|||||||
private final PaymentRepository paymentRepository;
|
private final PaymentRepository paymentRepository;
|
||||||
private final UserARepository userARepository;
|
private final UserARepository userARepository;
|
||||||
private final UserBRepository userBRepository;
|
private final UserBRepository userBRepository;
|
||||||
|
private final UserDRepository userDRepository;
|
||||||
private final CryptoDepositMethodRepository cryptoDepositMethodRepository;
|
private final CryptoDepositMethodRepository cryptoDepositMethodRepository;
|
||||||
private final TelegramProperties telegramProperties;
|
private final TelegramProperties telegramProperties;
|
||||||
private final TransactionService transactionService;
|
private final TransactionService transactionService;
|
||||||
@@ -74,6 +77,11 @@ public class PaymentService {
|
|||||||
/** When false, Telegram Stars payment webhooks are ignored (no balance credited). Invoice creation for Stars is already rejected. */
|
/** When false, Telegram Stars payment webhooks are ignored (no balance credited). Invoice creation for Stars is already rejected. */
|
||||||
private static final boolean TELEGRAM_STARS_PAYMENTS_ENABLED = false;
|
private static final boolean TELEGRAM_STARS_PAYMENTS_ENABLED = false;
|
||||||
|
|
||||||
|
/** Referral commission as fraction of base deposit (no bonus). Level 1 = referer_1, level 2 = referer_2, level 3 = referer_3. */
|
||||||
|
private static final double REFERRER_LEVEL1_PERCENT = 0.12;
|
||||||
|
private static final double REFERRER_LEVEL2_PERCENT = 0.06;
|
||||||
|
private static final double REFERRER_LEVEL3_PERCENT = 0.02;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a payment invoice for the user.
|
* Creates a payment invoice for the user.
|
||||||
* Validates the stars amount and creates a pending payment record.
|
* Validates the stars amount and creates a pending payment record.
|
||||||
@@ -409,9 +417,54 @@ public class PaymentService {
|
|||||||
log.error("Error creating deposit transaction: userId={}, amount={}", userId, playBalance, e);
|
log.error("Error creating deposit transaction: userId={}, amount={}", userId, playBalance, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Referral commissions: % of base deposit (no bonus), credited to referer balanceB and tracked in UserD
|
||||||
|
applyReferralCommissions(userId, basePlayBalance);
|
||||||
|
|
||||||
log.info("External deposit completed: orderId={}, userId={}, usdAmount={}, playBalance={}, firstDeposit={}", orderId, userId, usdAmountBd, playBalance, firstDeposit);
|
log.info("External deposit completed: orderId={}, userId={}, usdAmount={}, playBalance={}, firstDeposit={}", orderId, userId, usdAmountBd, playBalance, firstDeposit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies referral commissions on deposit: referer_1 gets REFERRER_LEVEL1_PERCENT, referer_2 gets REFERRER_LEVEL2_PERCENT, referer_3 gets REFERRER_LEVEL3_PERCENT of base play balance (no bonus).
|
||||||
|
* Updates: referer's balanceB, depositor's to_referer_N, referer's from_referals_N.
|
||||||
|
*/
|
||||||
|
private void applyReferralCommissions(Integer depositorUserId, long basePlayBalance) {
|
||||||
|
if (basePlayBalance <= 0) return;
|
||||||
|
UserD depositorUserD = userDRepository.findById(depositorUserId).orElse(null);
|
||||||
|
if (depositorUserD == null) return;
|
||||||
|
|
||||||
|
long commission1 = Math.round(basePlayBalance * REFERRER_LEVEL1_PERCENT);
|
||||||
|
long commission2 = Math.round(basePlayBalance * REFERRER_LEVEL2_PERCENT);
|
||||||
|
long commission3 = Math.round(basePlayBalance * REFERRER_LEVEL3_PERCENT);
|
||||||
|
|
||||||
|
applyReferralLevel(depositorUserD, depositorUserId, 1, depositorUserD.getRefererId1(), commission1,
|
||||||
|
UserD::getToReferer1, UserD::setToReferer1, UserD::getFromReferals1, UserD::setFromReferals1);
|
||||||
|
applyReferralLevel(depositorUserD, depositorUserId, 2, depositorUserD.getRefererId2(), commission2,
|
||||||
|
UserD::getToReferer2, UserD::setToReferer2, UserD::getFromReferals2, UserD::setFromReferals2);
|
||||||
|
applyReferralLevel(depositorUserD, depositorUserId, 3, depositorUserD.getRefererId3(), commission3,
|
||||||
|
UserD::getToReferer3, UserD::setToReferer3, UserD::getFromReferals3, UserD::setFromReferals3);
|
||||||
|
|
||||||
|
userDRepository.save(depositorUserD);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyReferralLevel(UserD depositorUserD, Integer depositorUserId, int level, Integer refererId, long commission,
|
||||||
|
java.util.function.Function<UserD, Long> getToReferer, java.util.function.BiConsumer<UserD, Long> setToReferer,
|
||||||
|
java.util.function.Function<UserD, Long> getFromReferals, java.util.function.BiConsumer<UserD, Long> setFromReferals) {
|
||||||
|
if (refererId == null || refererId <= 0 || commission <= 0) return;
|
||||||
|
|
||||||
|
setToReferer.accept(depositorUserD, (getToReferer.apply(depositorUserD) != null ? getToReferer.apply(depositorUserD) : 0L) + commission);
|
||||||
|
|
||||||
|
userBRepository.findById(refererId).ifPresent(refererB -> {
|
||||||
|
refererB.setBalanceB(refererB.getBalanceB() + commission);
|
||||||
|
userBRepository.save(refererB);
|
||||||
|
});
|
||||||
|
userDRepository.findById(refererId).ifPresent(refererD -> {
|
||||||
|
setFromReferals.accept(refererD, (getFromReferals.apply(refererD) != null ? getFromReferals.apply(refererD) : 0L) + commission);
|
||||||
|
userDRepository.save(refererD);
|
||||||
|
});
|
||||||
|
|
||||||
|
log.debug("Referral commission applied: depositor={}, refererLevel={}, refererId={}, commission={}", depositorUserId, level, refererId, commission);
|
||||||
|
}
|
||||||
|
|
||||||
/** USD range 3–20000 and at most 2 decimal places. */
|
/** USD range 3–20000 and at most 2 decimal places. */
|
||||||
private void validateUsd(double usdAmount) {
|
private void validateUsd(double usdAmount) {
|
||||||
if (usdAmount < MIN_USD || usdAmount > MAX_USD) {
|
if (usdAmount < MIN_USD || usdAmount > MAX_USD) {
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ public class UserService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets referrals for a specific level with pagination.
|
* Gets referrals for a specific level with pagination.
|
||||||
* Always returns 50 results per page.
|
* Returns 10 results per page, ordered by commission DESC, then id DESC.
|
||||||
*
|
*
|
||||||
* @param userId The user ID to get referrals for
|
* @param userId The user ID to get referrals for
|
||||||
* @param level The referral level (1, 2, or 3)
|
* @param level The referral level (1, 2, or 3)
|
||||||
@@ -463,8 +463,7 @@ public class UserService {
|
|||||||
* @return Page of referrals with name and commission
|
* @return Page of referrals with name and commission
|
||||||
*/
|
*/
|
||||||
public Page<ReferralDto> getReferrals(Integer userId, Integer level, Integer page) {
|
public Page<ReferralDto> getReferrals(Integer userId, Integer level, Integer page) {
|
||||||
// Fixed page size of 50 to prevent database overload
|
Pageable pageable = PageRequest.of(page, 10);
|
||||||
Pageable pageable = PageRequest.of(page, 50);
|
|
||||||
|
|
||||||
return switch (level) {
|
return switch (level) {
|
||||||
case 1 -> userDRepository.findReferralsLevel1(userId, pageable);
|
case 1 -> userDRepository.findReferralsLevel1(userId, pageable);
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
-- Extend referral commission indexes to include id DESC so ORDER BY commission DESC, id DESC
|
||||||
|
-- is fully satisfied by the index. Avoids expensive filesort when many referrals share the same
|
||||||
|
-- commission (e.g. 20k with 0 commission).
|
||||||
|
DROP INDEX idx_users_d_referer1_commission ON db_users_d;
|
||||||
|
DROP INDEX idx_users_d_referer2_commission ON db_users_d;
|
||||||
|
DROP INDEX idx_users_d_referer3_commission ON db_users_d;
|
||||||
|
|
||||||
|
CREATE INDEX idx_users_d_referer1_commission ON db_users_d (referer_id_1, to_referer_1 DESC, id DESC);
|
||||||
|
CREATE INDEX idx_users_d_referer2_commission ON db_users_d (referer_id_2, to_referer_2 DESC, id DESC);
|
||||||
|
CREATE INDEX idx_users_d_referer3_commission ON db_users_d (referer_id_3, to_referer_3 DESC, id DESC);
|
||||||
Reference in New Issue
Block a user