This commit is contained in:
@@ -2,11 +2,9 @@ package com.honey.honey.controller;
|
|||||||
|
|
||||||
import com.honey.honey.model.Payment;
|
import com.honey.honey.model.Payment;
|
||||||
import com.honey.honey.model.Payout;
|
import com.honey.honey.model.Payout;
|
||||||
import com.honey.honey.model.SupportTicket;
|
|
||||||
import com.honey.honey.model.UserA;
|
import com.honey.honey.model.UserA;
|
||||||
import com.honey.honey.repository.PaymentRepository;
|
import com.honey.honey.repository.PaymentRepository;
|
||||||
import com.honey.honey.repository.PayoutRepository;
|
import com.honey.honey.repository.PayoutRepository;
|
||||||
import com.honey.honey.repository.SupportTicketRepository;
|
|
||||||
import com.honey.honey.repository.UserARepository;
|
import com.honey.honey.repository.UserARepository;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@@ -30,7 +28,6 @@ public class AdminDashboardController {
|
|||||||
private final UserARepository userARepository;
|
private final UserARepository userARepository;
|
||||||
private final PaymentRepository paymentRepository;
|
private final PaymentRepository paymentRepository;
|
||||||
private final PayoutRepository payoutRepository;
|
private final PayoutRepository payoutRepository;
|
||||||
private final SupportTicketRepository supportTicketRepository;
|
|
||||||
|
|
||||||
@GetMapping("/stats")
|
@GetMapping("/stats")
|
||||||
public ResponseEntity<Map<String, Object>> getDashboardStats() {
|
public ResponseEntity<Map<String, Object>> getDashboardStats() {
|
||||||
@@ -103,15 +100,6 @@ public class AdminDashboardController {
|
|||||||
BigDecimal cryptoNetRevenueWeek = cryptoRevenueWeek.subtract(cryptoPayoutsWeek);
|
BigDecimal cryptoNetRevenueWeek = cryptoRevenueWeek.subtract(cryptoPayoutsWeek);
|
||||||
BigDecimal cryptoNetRevenueMonth = cryptoRevenueMonth.subtract(cryptoPayoutsMonth);
|
BigDecimal cryptoNetRevenueMonth = cryptoRevenueMonth.subtract(cryptoPayoutsMonth);
|
||||||
|
|
||||||
// Support Tickets
|
|
||||||
long openTickets = supportTicketRepository.countByStatus(SupportTicket.TicketStatus.OPENED);
|
|
||||||
// Count tickets closed today
|
|
||||||
long ticketsResolvedToday = supportTicketRepository.findAll().stream()
|
|
||||||
.filter(t -> t.getStatus() == SupportTicket.TicketStatus.CLOSED &&
|
|
||||||
t.getUpdatedAt() != null &&
|
|
||||||
t.getUpdatedAt().isAfter(todayStart))
|
|
||||||
.count();
|
|
||||||
|
|
||||||
// Build response
|
// Build response
|
||||||
stats.put("users", Map.of(
|
stats.put("users", Map.of(
|
||||||
"total", totalUsers,
|
"total", totalUsers,
|
||||||
@@ -162,19 +150,6 @@ public class AdminDashboardController {
|
|||||||
crypto.put("profitUsdMonth", cryptoNetRevenueMonth);
|
crypto.put("profitUsdMonth", cryptoNetRevenueMonth);
|
||||||
stats.put("crypto", crypto);
|
stats.put("crypto", crypto);
|
||||||
|
|
||||||
stats.put("rounds", Map.of(
|
|
||||||
"total", 0L,
|
|
||||||
"today", 0L,
|
|
||||||
"week", 0L,
|
|
||||||
"month", 0L,
|
|
||||||
"avgPool", 0
|
|
||||||
));
|
|
||||||
|
|
||||||
stats.put("supportTickets", Map.of(
|
|
||||||
"open", openTickets,
|
|
||||||
"resolvedToday", ticketsResolvedToday
|
|
||||||
));
|
|
||||||
|
|
||||||
return ResponseEntity.ok(stats);
|
return ResponseEntity.ok(stats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ public class AdminPaymentController {
|
|||||||
.orderId(payment.getOrderId())
|
.orderId(payment.getOrderId())
|
||||||
.starsAmount(payment.getStarsAmount())
|
.starsAmount(payment.getStarsAmount())
|
||||||
.ticketsAmount(payment.getTicketsAmount())
|
.ticketsAmount(payment.getTicketsAmount())
|
||||||
|
.usdAmount(payment.getUsdAmount())
|
||||||
.status(payment.getStatus().name())
|
.status(payment.getStatus().name())
|
||||||
.telegramPaymentChargeId(payment.getTelegramPaymentChargeId())
|
.telegramPaymentChargeId(payment.getTelegramPaymentChargeId())
|
||||||
.telegramProviderPaymentChargeId(payment.getTelegramProviderPaymentChargeId())
|
.telegramProviderPaymentChargeId(payment.getTelegramProviderPaymentChargeId())
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ public class AdminPayoutController {
|
|||||||
.type(payout.getType().name())
|
.type(payout.getType().name())
|
||||||
.giftName(payout.getGiftName() != null ? payout.getGiftName().name() : null)
|
.giftName(payout.getGiftName() != null ? payout.getGiftName().name() : null)
|
||||||
.total(payout.getTotal())
|
.total(payout.getTotal())
|
||||||
|
.usdAmount(payout.getUsdAmount())
|
||||||
.starsAmount(payout.getStarsAmount())
|
.starsAmount(payout.getStarsAmount())
|
||||||
.quantity(payout.getQuantity())
|
.quantity(payout.getQuantity())
|
||||||
.status(payout.getStatus().name())
|
.status(payout.getStatus().name())
|
||||||
|
|||||||
@@ -58,8 +58,10 @@ public class AdminUserController {
|
|||||||
@RequestParam(required = false) String languageCode,
|
@RequestParam(required = false) String languageCode,
|
||||||
@RequestParam(required = false) Integer dateRegFrom,
|
@RequestParam(required = false) Integer dateRegFrom,
|
||||||
@RequestParam(required = false) Integer dateRegTo,
|
@RequestParam(required = false) Integer dateRegTo,
|
||||||
@RequestParam(required = false) Long balanceMin,
|
@RequestParam(required = false) Long balanceAMin,
|
||||||
@RequestParam(required = false) Long balanceMax,
|
@RequestParam(required = false) Long balanceAMax,
|
||||||
|
@RequestParam(required = false) Long balanceBMin,
|
||||||
|
@RequestParam(required = false) Long balanceBMax,
|
||||||
@RequestParam(required = false) Integer referralCountMin,
|
@RequestParam(required = false) Integer referralCountMin,
|
||||||
@RequestParam(required = false) Integer referralCountMax,
|
@RequestParam(required = false) Integer referralCountMax,
|
||||||
@RequestParam(required = false) Integer referrerId,
|
@RequestParam(required = false) Integer referrerId,
|
||||||
@@ -81,9 +83,11 @@ public class AdminUserController {
|
|||||||
}
|
}
|
||||||
Pageable pageable = PageRequest.of(page, size, sort);
|
Pageable pageable = PageRequest.of(page, size, sort);
|
||||||
|
|
||||||
// Convert balance filters from tickets (divide by 1000000) to bigint format
|
// Convert balance filters from display value to bigint format
|
||||||
Long balanceMinBigint = balanceMin != null ? balanceMin * 1000000L : null;
|
Long balanceAMinBigint = balanceAMin != null ? balanceAMin * 1000000L : null;
|
||||||
Long balanceMaxBigint = balanceMax != null ? balanceMax * 1000000L : null;
|
Long balanceAMaxBigint = balanceAMax != null ? balanceAMax * 1000000L : null;
|
||||||
|
Long balanceBMinBigint = balanceBMin != null ? balanceBMin * 1000000L : null;
|
||||||
|
Long balanceBMaxBigint = balanceBMax != null ? balanceBMax * 1000000L : null;
|
||||||
|
|
||||||
boolean excludeMasters = isSupport();
|
boolean excludeMasters = isSupport();
|
||||||
Page<AdminUserDto> dtoPage = adminUserService.getUsers(
|
Page<AdminUserDto> dtoPage = adminUserService.getUsers(
|
||||||
@@ -94,8 +98,10 @@ public class AdminUserController {
|
|||||||
languageCode,
|
languageCode,
|
||||||
dateRegFrom,
|
dateRegFrom,
|
||||||
dateRegTo,
|
dateRegTo,
|
||||||
balanceMinBigint,
|
balanceAMinBigint,
|
||||||
balanceMaxBigint,
|
balanceAMaxBigint,
|
||||||
|
balanceBMinBigint,
|
||||||
|
balanceBMaxBigint,
|
||||||
referralCountMin,
|
referralCountMin,
|
||||||
referralCountMax,
|
referralCountMax,
|
||||||
referrerId,
|
referrerId,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import lombok.Builder;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -18,6 +19,8 @@ public class AdminPaymentDto {
|
|||||||
private String orderId;
|
private String orderId;
|
||||||
private Integer starsAmount;
|
private Integer starsAmount;
|
||||||
private Long ticketsAmount;
|
private Long ticketsAmount;
|
||||||
|
/** USD amount (e.g. 1.25). */
|
||||||
|
private BigDecimal usdAmount;
|
||||||
private String status;
|
private String status;
|
||||||
private String telegramPaymentChargeId;
|
private String telegramPaymentChargeId;
|
||||||
private String telegramProviderPaymentChargeId;
|
private String telegramProviderPaymentChargeId;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import lombok.Builder;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -19,6 +20,8 @@ public class AdminPayoutDto {
|
|||||||
private String type;
|
private String type;
|
||||||
private String giftName;
|
private String giftName;
|
||||||
private Long total;
|
private Long total;
|
||||||
|
/** USD amount (e.g. 1.25). */
|
||||||
|
private BigDecimal usdAmount;
|
||||||
private Integer starsAmount;
|
private Integer starsAmount;
|
||||||
private Integer quantity;
|
private Integer quantity;
|
||||||
private String status;
|
private String status;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ public class AdminUserDetailDto {
|
|||||||
|
|
||||||
// Balance Info
|
// Balance Info
|
||||||
private Long balanceA;
|
private Long balanceA;
|
||||||
|
private Long balanceB;
|
||||||
private Long depositTotal;
|
private Long depositTotal;
|
||||||
private Integer depositCount;
|
private Integer depositCount;
|
||||||
private Long withdrawTotal;
|
private Long withdrawTotal;
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@@ -17,13 +16,12 @@ public class BalanceAdjustmentRequest {
|
|||||||
private BalanceType balanceType; // A or B
|
private BalanceType balanceType; // A or B
|
||||||
|
|
||||||
@NotNull(message = "Amount is required")
|
@NotNull(message = "Amount is required")
|
||||||
private Long amount; // In bigint format (tickets * 1,000,000)
|
private Long amount; // In bigint format (display value * 1,000,000)
|
||||||
|
|
||||||
@NotNull(message = "Operation is required")
|
@NotNull(message = "Operation is required")
|
||||||
private OperationType operation; // ADD or SUBTRACT
|
private OperationType operation; // ADD or SUBTRACT
|
||||||
|
|
||||||
@NotBlank(message = "Reason is required")
|
private String reason; // Optional reason for adjustment (for audit log)
|
||||||
private String reason; // Reason for adjustment (for audit log)
|
|
||||||
|
|
||||||
public enum BalanceType {
|
public enum BalanceType {
|
||||||
A, B
|
A, B
|
||||||
|
|||||||
@@ -56,8 +56,10 @@ public class AdminUserService {
|
|||||||
String languageCode,
|
String languageCode,
|
||||||
Integer dateRegFrom,
|
Integer dateRegFrom,
|
||||||
Integer dateRegTo,
|
Integer dateRegTo,
|
||||||
Long balanceMin,
|
Long balanceAMin,
|
||||||
Long balanceMax,
|
Long balanceAMax,
|
||||||
|
Long balanceBMin,
|
||||||
|
Long balanceBMax,
|
||||||
Integer referralCountMin,
|
Integer referralCountMin,
|
||||||
Integer referralCountMax,
|
Integer referralCountMax,
|
||||||
Integer referrerId,
|
Integer referrerId,
|
||||||
@@ -137,20 +139,16 @@ public class AdminUserService {
|
|||||||
predicates.add(cb.lessThanOrEqualTo(root.get("dateReg"), endOfDayTimestamp));
|
predicates.add(cb.lessThanOrEqualTo(root.get("dateReg"), endOfDayTimestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Balance / referral filters via subqueries so DB handles pagination
|
// Balance A / Balance B filters via subqueries
|
||||||
if (balanceMin != null || balanceMax != null) {
|
if (balanceAMin != null || balanceAMax != null || balanceBMin != null || balanceBMax != null) {
|
||||||
Subquery<Integer> subB = query.subquery(Integer.class);
|
Subquery<Integer> subB = query.subquery(Integer.class);
|
||||||
Root<UserB> br = subB.from(UserB.class);
|
Root<UserB> br = subB.from(UserB.class);
|
||||||
subB.select(br.get("id"));
|
subB.select(br.get("id"));
|
||||||
List<Predicate> subPreds = new ArrayList<>();
|
List<Predicate> subPreds = new ArrayList<>();
|
||||||
if (balanceMin != null) {
|
if (balanceAMin != null) subPreds.add(cb.greaterThanOrEqualTo(br.get("balanceA"), balanceAMin));
|
||||||
subPreds.add(cb.greaterThanOrEqualTo(
|
if (balanceAMax != null) subPreds.add(cb.lessThanOrEqualTo(br.get("balanceA"), balanceAMax));
|
||||||
cb.sum(br.get("balanceA"), br.get("balanceB")), balanceMin));
|
if (balanceBMin != null) subPreds.add(cb.greaterThanOrEqualTo(br.get("balanceB"), balanceBMin));
|
||||||
}
|
if (balanceBMax != null) subPreds.add(cb.lessThanOrEqualTo(br.get("balanceB"), balanceBMax));
|
||||||
if (balanceMax != null) {
|
|
||||||
subPreds.add(cb.lessThanOrEqualTo(
|
|
||||||
cb.sum(br.get("balanceA"), br.get("balanceB")), balanceMax));
|
|
||||||
}
|
|
||||||
subB.where(cb.and(subPreds.toArray(new Predicate[0])));
|
subB.where(cb.and(subPreds.toArray(new Predicate[0])));
|
||||||
predicates.add(cb.in(root.get("id")).value(subB));
|
predicates.add(cb.in(root.get("id")).value(subB));
|
||||||
}
|
}
|
||||||
@@ -186,7 +184,7 @@ public class AdminUserService {
|
|||||||
return cb.and(predicates.toArray(new Predicate[0]));
|
return cb.and(predicates.toArray(new Predicate[0]));
|
||||||
};
|
};
|
||||||
|
|
||||||
Set<String> sortRequiresJoin = Set.of("balanceA", "depositTotal", "withdrawTotal", "referralCount", "profit");
|
Set<String> sortRequiresJoin = Set.of("balanceA", "balanceB", "depositTotal", "withdrawTotal", "referralCount", "profit");
|
||||||
boolean useJoinSort = sortBy != null && sortRequiresJoin.contains(sortBy);
|
boolean useJoinSort = sortBy != null && sortRequiresJoin.contains(sortBy);
|
||||||
List<UserA> userList;
|
List<UserA> userList;
|
||||||
long totalElements;
|
long totalElements;
|
||||||
@@ -194,7 +192,7 @@ public class AdminUserService {
|
|||||||
if (useJoinSort) {
|
if (useJoinSort) {
|
||||||
List<Integer> orderedIds = getOrderedUserIdsForAdminList(
|
List<Integer> orderedIds = getOrderedUserIdsForAdminList(
|
||||||
search, banned, countryCode, languageCode,
|
search, banned, countryCode, languageCode,
|
||||||
dateRegFrom, dateRegTo, balanceMin, balanceMax,
|
dateRegFrom, dateRegTo, balanceAMin, balanceAMax, balanceBMin, balanceBMax,
|
||||||
referralCountMin, referralCountMax,
|
referralCountMin, referralCountMax,
|
||||||
referrerId, referralLevel, ipFilter,
|
referrerId, referralLevel, ipFilter,
|
||||||
sortBy, sortDir != null ? sortDir : "desc",
|
sortBy, sortDir != null ? sortDir : "desc",
|
||||||
@@ -301,8 +299,10 @@ public class AdminUserService {
|
|||||||
String languageCode,
|
String languageCode,
|
||||||
Integer dateRegFrom,
|
Integer dateRegFrom,
|
||||||
Integer dateRegTo,
|
Integer dateRegTo,
|
||||||
Long balanceMin,
|
Long balanceAMin,
|
||||||
Long balanceMax,
|
Long balanceAMax,
|
||||||
|
Long balanceBMin,
|
||||||
|
Long balanceBMax,
|
||||||
Integer referralCountMin,
|
Integer referralCountMin,
|
||||||
Integer referralCountMax,
|
Integer referralCountMax,
|
||||||
Integer referrerId,
|
Integer referrerId,
|
||||||
@@ -374,14 +374,24 @@ public class AdminUserService {
|
|||||||
params.add(dateRegTo);
|
params.add(dateRegTo);
|
||||||
paramIndex++;
|
paramIndex++;
|
||||||
}
|
}
|
||||||
if (balanceMin != null) {
|
if (balanceAMin != null) {
|
||||||
sql.append(" AND (b.balance_a + b.balance_b) >= ?");
|
sql.append(" AND b.balance_a >= ?");
|
||||||
params.add(balanceMin);
|
params.add(balanceAMin);
|
||||||
paramIndex++;
|
paramIndex++;
|
||||||
}
|
}
|
||||||
if (balanceMax != null) {
|
if (balanceAMax != null) {
|
||||||
sql.append(" AND (b.balance_a + b.balance_b) <= ?");
|
sql.append(" AND b.balance_a <= ?");
|
||||||
params.add(balanceMax);
|
params.add(balanceAMax);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
if (balanceBMin != null) {
|
||||||
|
sql.append(" AND b.balance_b >= ?");
|
||||||
|
params.add(balanceBMin);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
if (balanceBMax != null) {
|
||||||
|
sql.append(" AND b.balance_b <= ?");
|
||||||
|
params.add(balanceBMax);
|
||||||
paramIndex++;
|
paramIndex++;
|
||||||
}
|
}
|
||||||
if (referralCountMin != null || referralCountMax != null) {
|
if (referralCountMin != null || referralCountMax != null) {
|
||||||
@@ -417,6 +427,7 @@ public class AdminUserService {
|
|||||||
|
|
||||||
String orderColumn = switch (sortBy != null ? sortBy : "") {
|
String orderColumn = switch (sortBy != null ? sortBy : "") {
|
||||||
case "balanceA" -> "b.balance_a";
|
case "balanceA" -> "b.balance_a";
|
||||||
|
case "balanceB" -> "b.balance_b";
|
||||||
case "depositTotal" -> "b.deposit_total";
|
case "depositTotal" -> "b.deposit_total";
|
||||||
case "withdrawTotal" -> "b.withdraw_total";
|
case "withdrawTotal" -> "b.withdraw_total";
|
||||||
case "referralCount" -> "(d.referals_1 + d.referals_2 + d.referals_3 + d.referals_4 + d.referals_5)";
|
case "referralCount" -> "(d.referals_1 + d.referals_2 + d.referals_3 + d.referals_4 + d.referals_5)";
|
||||||
@@ -579,6 +590,7 @@ public class AdminUserService {
|
|||||||
.banned(userA.getBanned())
|
.banned(userA.getBanned())
|
||||||
.ipAddress(IpUtils.bytesToIp(userA.getIp()))
|
.ipAddress(IpUtils.bytesToIp(userA.getIp()))
|
||||||
.balanceA(userB.getBalanceA())
|
.balanceA(userB.getBalanceA())
|
||||||
|
.balanceB(userB.getBalanceB())
|
||||||
.depositTotal(userB.getDepositTotal())
|
.depositTotal(userB.getDepositTotal())
|
||||||
.depositCount(userB.getDepositCount())
|
.depositCount(userB.getDepositCount())
|
||||||
.withdrawTotal(userB.getWithdrawTotal())
|
.withdrawTotal(userB.getWithdrawTotal())
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Ensure payment_enabled and payout_enabled feature switches exist (for admin panel and runtime).
|
||||||
|
INSERT INTO feature_switches (`key`, `enabled`, `updated_at`)
|
||||||
|
VALUES ('payment_enabled', 1, CURRENT_TIMESTAMP), ('payout_enabled', 1, CURRENT_TIMESTAMP)
|
||||||
|
ON DUPLICATE KEY UPDATE `updated_at` = CURRENT_TIMESTAMP;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- Index for admin users list: filter and sort by Balance B
|
||||||
|
CREATE INDEX idx_users_b_balance_b ON db_users_b(balance_b);
|
||||||
Reference in New Issue
Block a user