fix coupon analytics

This commit is contained in:
2026-04-15 13:39:06 -06:00
parent 405fa60d61
commit 77b697ac83
4 changed files with 40 additions and 4 deletions

View File

@@ -5,12 +5,15 @@ import com.petshop.backend.entity.User;
import com.petshop.backend.repository.UserRepository;
import com.petshop.backend.service.AnalyticsService;
import com.petshop.backend.util.AuthenticationHelper;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import java.time.LocalDate;
@RestController
@RequestMapping("/api/v1/analytics")
@PreAuthorize("hasAnyRole('ADMIN', 'STAFF')")
@@ -27,7 +30,11 @@ public class AnalyticsController {
@GetMapping("/dashboard")
public ResponseEntity<DashboardResponse> getDashboard(
@RequestParam(defaultValue = "30") int days,
@RequestParam(defaultValue = "10") int top) {
@RequestParam(defaultValue = "10") int top,
@RequestParam(required = false) String paymentMethod,
@RequestParam(required = false) Long storeId,
@RequestParam(required = false) String channel,
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {
if (days < 1 || days > 365) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "days must be between 1 and 365");
}
@@ -35,6 +42,7 @@ public class AnalyticsController {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "top must be between 1 and 50");
}
User user = AuthenticationHelper.getAuthenticatedUser(userRepository);
return ResponseEntity.ok(analyticsService.getDashboardData(days, top, user));
java.time.LocalDateTime endDateTime = endDate != null ? endDate.plusDays(1).atStartOfDay() : null;
return ResponseEntity.ok(analyticsService.getDashboardData(days, top, user, paymentMethod, storeId, channel, endDateTime));
}
}

View File

@@ -3,6 +3,7 @@ package com.petshop.backend.repository;
import com.petshop.backend.entity.Sale;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.time.LocalDateTime;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
@@ -26,6 +27,19 @@ public interface SaleRepository extends JpaRepository<Sale, Long> {
"(:customerId IS NULL OR s.customer.id = :customerId)")
Page<Sale> searchSales(@Param("q") String query, @Param("paymentMethod") String paymentMethod, @Param("storeId") Long storeId, @Param("isRefund") Boolean isRefund, @Param("customerId") Long customerId, Pageable pageable);
long countByCoupon_CouponId(Long couponId);
@Query("SELECT s FROM Sale s WHERE s.saleDate > :startDate " +
"AND (:endDate IS NULL OR s.saleDate <= :endDate) " +
"AND (:paymentMethod IS NULL OR LOWER(s.paymentMethod) = LOWER(:paymentMethod)) " +
"AND (:storeId IS NULL OR s.store.storeId = :storeId) " +
"AND (:channel IS NULL OR s.channel = :channel)")
List<Sale> findForAnalytics(@Param("startDate") LocalDateTime startDate,
@Param("endDate") LocalDateTime endDate,
@Param("paymentMethod") String paymentMethod,
@Param("storeId") Long storeId,
@Param("channel") String channel);
List<Sale> findByOriginalSaleSaleId(Long originalSaleId);
Optional<Sale> findByCartCartId(Long cartId);

View File

@@ -34,10 +34,17 @@ public class AnalyticsService {
@Transactional(readOnly = true)
public DashboardResponse getDashboardData(int days, int top, User user) {
return getDashboardData(days, top, user, null, null, null, null);
}
@Transactional(readOnly = true)
public DashboardResponse getDashboardData(int days, int top, User user,
String paymentMethod, Long storeId,
String channel, LocalDateTime endDate) {
LocalDateTime startDate = LocalDateTime.now().minusDays(days);
List<Sale> sales = saleRepository.findAll().stream()
.filter(sale -> sale.getSaleDate().isAfter(startDate))
List<Sale> sales = saleRepository.findForAnalytics(startDate, endDate, paymentMethod, storeId, channel)
.stream()
.filter(sale -> includeSaleForUser(sale, user))
.collect(Collectors.toList());

View File

@@ -206,6 +206,13 @@ public class CartService {
throw new BusinessException("Minimum order amount of $" + coupon.getMinOrderAmount() + " required");
}
if (coupon.getUsageLimit() != null) {
long used = saleRepository.countByCoupon_CouponId(coupon.getCouponId());
if (used >= coupon.getUsageLimit()) {
throw new BusinessException("Coupon usage limit has been reached");
}
}
cart.setCoupon(coupon);
recalculate(cart);