This commit is contained in:
@@ -44,7 +44,8 @@ public class HandlerConfig {
|
||||
StatisticUserDynamicHandler statisticUserDynamicHandler,
|
||||
StatisticProtectedFilesHandler statisticProtectedFilesHandler,
|
||||
StatisticViolationHandler statisticViolationHandler,
|
||||
StatisticSubscriberHandler statisticSubscriberHandler
|
||||
StatisticSubscriberHandler statisticSubscriberHandler,
|
||||
StatisticTokenHandler statisticTokenHandler
|
||||
|
||||
) {
|
||||
Map<Integer, RequestHandler> map = new HashMap<>();
|
||||
@@ -81,6 +82,7 @@ public class HandlerConfig {
|
||||
map.put(30022, statisticProtectedFilesHandler);
|
||||
map.put(30023, statisticViolationHandler);
|
||||
map.put(30024, statisticSubscriberHandler);
|
||||
map.put(30025, statisticTokenHandler);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package ru.soune.nocopy.dto.statistic;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TokenStatisticRequest {
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package ru.soune.nocopy.dto.statistic;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class TokenStatisticResponse {
|
||||
|
||||
@JsonProperty("total_bought")
|
||||
private Long totalBought;
|
||||
|
||||
@JsonProperty("total_spent")
|
||||
private Long totalSpent;
|
||||
|
||||
@JsonProperty("bought_per_user")
|
||||
private Percentiles boughtPerUser;
|
||||
|
||||
@JsonProperty("spent_per_user")
|
||||
private Percentiles spentPerUser;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public static class Percentiles {
|
||||
@JsonProperty("p5")
|
||||
private Long p5;
|
||||
|
||||
@JsonProperty("p50")
|
||||
private Long p50;
|
||||
|
||||
@JsonProperty("p95")
|
||||
private Long p95;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package ru.soune.nocopy.handler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.soune.nocopy.dto.BaseRequest;
|
||||
import ru.soune.nocopy.dto.BaseResponse;
|
||||
import ru.soune.nocopy.dto.MessageCode;
|
||||
import ru.soune.nocopy.dto.statistic.TokenStatisticResponse;
|
||||
import ru.soune.nocopy.service.statistic.TokenStatisticService;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class StatisticTokenHandler implements RequestHandler {
|
||||
private final TokenStatisticService statisticService;
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) throws Exception {
|
||||
TokenStatisticResponse statistics = statisticService.getTokenStatistics();
|
||||
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(),
|
||||
statistics
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package ru.soune.nocopy.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import ru.soune.nocopy.entity.payment.Payment;
|
||||
|
||||
@@ -11,4 +12,23 @@ import java.util.Optional;
|
||||
public interface PaymentRepository extends JpaRepository<Payment, String> {
|
||||
Optional<Payment> findByPaymentUuid(String paymentUuid);
|
||||
List<Payment> findByUserId(Long userId);
|
||||
|
||||
@Query("""
|
||||
SELECT COALESCE(SUM(p.tariff.tokens), 0)
|
||||
FROM Payment p
|
||||
WHERE p.operationType = 'TOKEN'
|
||||
AND p.status = 'SUCCEEDED'
|
||||
""")
|
||||
Long getTotalTokensBought();
|
||||
|
||||
@Query("""
|
||||
SELECT
|
||||
p.user.Id,
|
||||
COALESCE(SUM(p.tariff.tokens), 0)
|
||||
FROM Payment p
|
||||
WHERE p.operationType = 'TOKEN'
|
||||
AND p.status = 'SUCCEEDED'
|
||||
GROUP BY p.user.Id
|
||||
""")
|
||||
List<Object[]> getTokensBoughtPerUser();
|
||||
}
|
||||
|
||||
@@ -38,4 +38,19 @@ public interface TokenOperationRepository extends JpaRepository<TokenOperation,
|
||||
Long sumSpentByUserAndType(@Param("userId") Long userId, @Param("operationType") OperationType operationType);
|
||||
|
||||
Long countByUserId(Long userId);
|
||||
|
||||
@Query("""
|
||||
SELECT COALESCE(SUM(t.spent), 0)
|
||||
FROM TokenOperation t
|
||||
""")
|
||||
Long getTotalTokensSpent();
|
||||
|
||||
@Query("""
|
||||
SELECT
|
||||
t.userId,
|
||||
COALESCE(SUM(t.spent), 0)
|
||||
FROM TokenOperation t
|
||||
GROUP BY t.userId
|
||||
""")
|
||||
List<Object[]> getTokensSpentPerUser();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package ru.soune.nocopy.service.statistic;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.soune.nocopy.dto.statistic.TokenStatisticResponse;
|
||||
import ru.soune.nocopy.repository.PaymentRepository;
|
||||
import ru.soune.nocopy.repository.TokenOperationRepository;
|
||||
import ru.soune.nocopy.util.PercentileCalculator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class TokenStatisticService {
|
||||
private final PaymentRepository paymentRepository;
|
||||
|
||||
private final TokenOperationRepository tokenOperationRepository;
|
||||
|
||||
private static final int PERCENTILE_5 = 5;
|
||||
|
||||
private static final int PERCENTILE_50 = 50;
|
||||
|
||||
private static final int PERCENTILE_95 = 95;
|
||||
|
||||
public TokenStatisticResponse getTokenStatistics() {
|
||||
Long totalBought = paymentRepository.getTotalTokensBought();
|
||||
Long totalSpent = tokenOperationRepository.getTotalTokensSpent();
|
||||
|
||||
List<Object[]> boughtData = paymentRepository.getTokensBoughtPerUser();
|
||||
List<Long> boughtValues = extractTokenValues(boughtData);
|
||||
|
||||
List<Object[]> spentData = tokenOperationRepository.getTokensSpentPerUser();
|
||||
List<Long> spentValues = extractTokenValues(spentData);
|
||||
|
||||
PercentileCalculator.PercentilesResult boughtPercentiles =
|
||||
PercentileCalculator.calculatePercentiles(boughtValues, PERCENTILE_5, PERCENTILE_50, PERCENTILE_95);
|
||||
PercentileCalculator.PercentilesResult spentPercentiles =
|
||||
PercentileCalculator.calculatePercentiles(spentValues, PERCENTILE_5, PERCENTILE_50, PERCENTILE_95);
|
||||
|
||||
return TokenStatisticResponse.builder()
|
||||
.totalBought(totalBought != null ? totalBought : 0L)
|
||||
.totalSpent(totalSpent != null ? totalSpent : 0L)
|
||||
.boughtPerUser(new TokenStatisticResponse.Percentiles(
|
||||
boughtPercentiles.getP5(),
|
||||
boughtPercentiles.getP50(),
|
||||
boughtPercentiles.getP95()
|
||||
))
|
||||
.spentPerUser(new TokenStatisticResponse.Percentiles(
|
||||
spentPercentiles.getP5(),
|
||||
spentPercentiles.getP50(),
|
||||
spentPercentiles.getP95()
|
||||
))
|
||||
.build();
|
||||
}
|
||||
|
||||
private List<Long> extractTokenValues(List<Object[]> data) {
|
||||
return data.stream()
|
||||
.map(row -> row[1] != null ? ((Number) row[1]).longValue() : 0L)
|
||||
.filter(value -> value > 0)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user