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.Payout;
|
||||
import com.honey.honey.model.SupportTicket;
|
||||
import com.honey.honey.model.UserA;
|
||||
import com.honey.honey.repository.PaymentRepository;
|
||||
import com.honey.honey.repository.PayoutRepository;
|
||||
import com.honey.honey.repository.SupportTicketRepository;
|
||||
import com.honey.honey.repository.UserARepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -30,7 +28,6 @@ public class AdminDashboardController {
|
||||
private final UserARepository userARepository;
|
||||
private final PaymentRepository paymentRepository;
|
||||
private final PayoutRepository payoutRepository;
|
||||
private final SupportTicketRepository supportTicketRepository;
|
||||
|
||||
@GetMapping("/stats")
|
||||
public ResponseEntity<Map<String, Object>> getDashboardStats() {
|
||||
@@ -103,15 +100,6 @@ public class AdminDashboardController {
|
||||
BigDecimal cryptoNetRevenueWeek = cryptoRevenueWeek.subtract(cryptoPayoutsWeek);
|
||||
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
|
||||
stats.put("users", Map.of(
|
||||
"total", totalUsers,
|
||||
@@ -162,19 +150,6 @@ public class AdminDashboardController {
|
||||
crypto.put("profitUsdMonth", cryptoNetRevenueMonth);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +124,7 @@ public class AdminPaymentController {
|
||||
.orderId(payment.getOrderId())
|
||||
.starsAmount(payment.getStarsAmount())
|
||||
.ticketsAmount(payment.getTicketsAmount())
|
||||
.usdAmount(payment.getUsdAmount())
|
||||
.status(payment.getStatus().name())
|
||||
.telegramPaymentChargeId(payment.getTelegramPaymentChargeId())
|
||||
.telegramProviderPaymentChargeId(payment.getTelegramProviderPaymentChargeId())
|
||||
|
||||
@@ -135,6 +135,7 @@ public class AdminPayoutController {
|
||||
.type(payout.getType().name())
|
||||
.giftName(payout.getGiftName() != null ? payout.getGiftName().name() : null)
|
||||
.total(payout.getTotal())
|
||||
.usdAmount(payout.getUsdAmount())
|
||||
.starsAmount(payout.getStarsAmount())
|
||||
.quantity(payout.getQuantity())
|
||||
.status(payout.getStatus().name())
|
||||
|
||||
@@ -58,8 +58,10 @@ public class AdminUserController {
|
||||
@RequestParam(required = false) String languageCode,
|
||||
@RequestParam(required = false) Integer dateRegFrom,
|
||||
@RequestParam(required = false) Integer dateRegTo,
|
||||
@RequestParam(required = false) Long balanceMin,
|
||||
@RequestParam(required = false) Long balanceMax,
|
||||
@RequestParam(required = false) Long balanceAMin,
|
||||
@RequestParam(required = false) Long balanceAMax,
|
||||
@RequestParam(required = false) Long balanceBMin,
|
||||
@RequestParam(required = false) Long balanceBMax,
|
||||
@RequestParam(required = false) Integer referralCountMin,
|
||||
@RequestParam(required = false) Integer referralCountMax,
|
||||
@RequestParam(required = false) Integer referrerId,
|
||||
@@ -81,9 +83,11 @@ public class AdminUserController {
|
||||
}
|
||||
Pageable pageable = PageRequest.of(page, size, sort);
|
||||
|
||||
// Convert balance filters from tickets (divide by 1000000) to bigint format
|
||||
Long balanceMinBigint = balanceMin != null ? balanceMin * 1000000L : null;
|
||||
Long balanceMaxBigint = balanceMax != null ? balanceMax * 1000000L : null;
|
||||
// Convert balance filters from display value to bigint format
|
||||
Long balanceAMinBigint = balanceAMin != null ? balanceAMin * 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();
|
||||
Page<AdminUserDto> dtoPage = adminUserService.getUsers(
|
||||
@@ -94,8 +98,10 @@ public class AdminUserController {
|
||||
languageCode,
|
||||
dateRegFrom,
|
||||
dateRegTo,
|
||||
balanceMinBigint,
|
||||
balanceMaxBigint,
|
||||
balanceAMinBigint,
|
||||
balanceAMaxBigint,
|
||||
balanceBMinBigint,
|
||||
balanceBMaxBigint,
|
||||
referralCountMin,
|
||||
referralCountMax,
|
||||
referrerId,
|
||||
|
||||
@@ -5,6 +5,7 @@ import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
|
||||
@Data
|
||||
@@ -18,6 +19,8 @@ public class AdminPaymentDto {
|
||||
private String orderId;
|
||||
private Integer starsAmount;
|
||||
private Long ticketsAmount;
|
||||
/** USD amount (e.g. 1.25). */
|
||||
private BigDecimal usdAmount;
|
||||
private String status;
|
||||
private String telegramPaymentChargeId;
|
||||
private String telegramProviderPaymentChargeId;
|
||||
|
||||
@@ -5,6 +5,7 @@ import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
|
||||
@Data
|
||||
@@ -19,6 +20,8 @@ public class AdminPayoutDto {
|
||||
private String type;
|
||||
private String giftName;
|
||||
private Long total;
|
||||
/** USD amount (e.g. 1.25). */
|
||||
private BigDecimal usdAmount;
|
||||
private Integer starsAmount;
|
||||
private Integer quantity;
|
||||
private String status;
|
||||
|
||||
@@ -30,6 +30,7 @@ public class AdminUserDetailDto {
|
||||
|
||||
// Balance Info
|
||||
private Long balanceA;
|
||||
private Long balanceB;
|
||||
private Long depositTotal;
|
||||
private Integer depositCount;
|
||||
private Long withdrawTotal;
|
||||
|
||||
@@ -6,7 +6,6 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@@ -17,13 +16,12 @@ public class BalanceAdjustmentRequest {
|
||||
private BalanceType balanceType; // A or B
|
||||
|
||||
@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")
|
||||
private OperationType operation; // ADD or SUBTRACT
|
||||
|
||||
@NotBlank(message = "Reason is required")
|
||||
private String reason; // Reason for adjustment (for audit log)
|
||||
private String reason; // Optional reason for adjustment (for audit log)
|
||||
|
||||
public enum BalanceType {
|
||||
A, B
|
||||
|
||||
@@ -56,8 +56,10 @@ public class AdminUserService {
|
||||
String languageCode,
|
||||
Integer dateRegFrom,
|
||||
Integer dateRegTo,
|
||||
Long balanceMin,
|
||||
Long balanceMax,
|
||||
Long balanceAMin,
|
||||
Long balanceAMax,
|
||||
Long balanceBMin,
|
||||
Long balanceBMax,
|
||||
Integer referralCountMin,
|
||||
Integer referralCountMax,
|
||||
Integer referrerId,
|
||||
@@ -137,20 +139,16 @@ public class AdminUserService {
|
||||
predicates.add(cb.lessThanOrEqualTo(root.get("dateReg"), endOfDayTimestamp));
|
||||
}
|
||||
|
||||
// Balance / referral filters via subqueries so DB handles pagination
|
||||
if (balanceMin != null || balanceMax != null) {
|
||||
// Balance A / Balance B filters via subqueries
|
||||
if (balanceAMin != null || balanceAMax != null || balanceBMin != null || balanceBMax != null) {
|
||||
Subquery<Integer> subB = query.subquery(Integer.class);
|
||||
Root<UserB> br = subB.from(UserB.class);
|
||||
subB.select(br.get("id"));
|
||||
List<Predicate> subPreds = new ArrayList<>();
|
||||
if (balanceMin != null) {
|
||||
subPreds.add(cb.greaterThanOrEqualTo(
|
||||
cb.sum(br.get("balanceA"), br.get("balanceB")), balanceMin));
|
||||
}
|
||||
if (balanceMax != null) {
|
||||
subPreds.add(cb.lessThanOrEqualTo(
|
||||
cb.sum(br.get("balanceA"), br.get("balanceB")), balanceMax));
|
||||
}
|
||||
if (balanceAMin != null) subPreds.add(cb.greaterThanOrEqualTo(br.get("balanceA"), balanceAMin));
|
||||
if (balanceAMax != null) subPreds.add(cb.lessThanOrEqualTo(br.get("balanceA"), balanceAMax));
|
||||
if (balanceBMin != null) subPreds.add(cb.greaterThanOrEqualTo(br.get("balanceB"), balanceBMin));
|
||||
if (balanceBMax != null) subPreds.add(cb.lessThanOrEqualTo(br.get("balanceB"), balanceBMax));
|
||||
subB.where(cb.and(subPreds.toArray(new Predicate[0])));
|
||||
predicates.add(cb.in(root.get("id")).value(subB));
|
||||
}
|
||||
@@ -186,7 +184,7 @@ public class AdminUserService {
|
||||
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);
|
||||
List<UserA> userList;
|
||||
long totalElements;
|
||||
@@ -194,7 +192,7 @@ public class AdminUserService {
|
||||
if (useJoinSort) {
|
||||
List<Integer> orderedIds = getOrderedUserIdsForAdminList(
|
||||
search, banned, countryCode, languageCode,
|
||||
dateRegFrom, dateRegTo, balanceMin, balanceMax,
|
||||
dateRegFrom, dateRegTo, balanceAMin, balanceAMax, balanceBMin, balanceBMax,
|
||||
referralCountMin, referralCountMax,
|
||||
referrerId, referralLevel, ipFilter,
|
||||
sortBy, sortDir != null ? sortDir : "desc",
|
||||
@@ -301,8 +299,10 @@ public class AdminUserService {
|
||||
String languageCode,
|
||||
Integer dateRegFrom,
|
||||
Integer dateRegTo,
|
||||
Long balanceMin,
|
||||
Long balanceMax,
|
||||
Long balanceAMin,
|
||||
Long balanceAMax,
|
||||
Long balanceBMin,
|
||||
Long balanceBMax,
|
||||
Integer referralCountMin,
|
||||
Integer referralCountMax,
|
||||
Integer referrerId,
|
||||
@@ -374,14 +374,24 @@ public class AdminUserService {
|
||||
params.add(dateRegTo);
|
||||
paramIndex++;
|
||||
}
|
||||
if (balanceMin != null) {
|
||||
sql.append(" AND (b.balance_a + b.balance_b) >= ?");
|
||||
params.add(balanceMin);
|
||||
if (balanceAMin != null) {
|
||||
sql.append(" AND b.balance_a >= ?");
|
||||
params.add(balanceAMin);
|
||||
paramIndex++;
|
||||
}
|
||||
if (balanceMax != null) {
|
||||
sql.append(" AND (b.balance_a + b.balance_b) <= ?");
|
||||
params.add(balanceMax);
|
||||
if (balanceAMax != null) {
|
||||
sql.append(" AND b.balance_a <= ?");
|
||||
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++;
|
||||
}
|
||||
if (referralCountMin != null || referralCountMax != null) {
|
||||
@@ -417,6 +427,7 @@ public class AdminUserService {
|
||||
|
||||
String orderColumn = switch (sortBy != null ? sortBy : "") {
|
||||
case "balanceA" -> "b.balance_a";
|
||||
case "balanceB" -> "b.balance_b";
|
||||
case "depositTotal" -> "b.deposit_total";
|
||||
case "withdrawTotal" -> "b.withdraw_total";
|
||||
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())
|
||||
.ipAddress(IpUtils.bytesToIp(userA.getIp()))
|
||||
.balanceA(userB.getBalanceA())
|
||||
.balanceB(userB.getBalanceB())
|
||||
.depositTotal(userB.getDepositTotal())
|
||||
.depositCount(userB.getDepositCount())
|
||||
.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