diff --git a/src/main/java/com/ycwl/basic/pricing/controller/CouponManagementController.java b/src/main/java/com/ycwl/basic/pricing/controller/CouponManagementController.java index 46d66ca..c061981 100644 --- a/src/main/java/com/ycwl/basic/pricing/controller/CouponManagementController.java +++ b/src/main/java/com/ycwl/basic/pricing/controller/CouponManagementController.java @@ -85,11 +85,12 @@ public class CouponManagementController { @RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(required = false) Boolean isActive, - @RequestParam(required = false) String couponName) { - log.info("分页查询优惠券配置: pageNum={}, pageSize={}, isActive={}, couponName={}", - pageNum, pageSize, isActive, couponName); + @RequestParam(required = false) String couponName, + @RequestParam(required = false) String scenicId) { + log.info("分页查询优惠券配置: pageNum={}, pageSize={}, isActive={}, couponName={}, scenicId={}", + pageNum, pageSize, isActive, couponName, scenicId); PageInfo pageInfo = couponManagementService.getCouponConfigsPage( - pageNum, pageSize, isActive, couponName); + pageNum, pageSize, isActive, couponName, scenicId); return ApiResponse.success(pageInfo); } @@ -136,11 +137,12 @@ public class CouponManagementController { @RequestParam(required = false) Long couponId, @RequestParam(required = false) CouponStatus status, @RequestParam(required = false) String startTime, - @RequestParam(required = false) String endTime) { - log.info("分页查询优惠券领取记录: pageNum={}, pageSize={}, userId={}, couponId={}, status={}, startTime={}, endTime={}", - pageNum, pageSize, userId, couponId, status, startTime, endTime); + @RequestParam(required = false) String endTime, + @RequestParam(required = false) String scenicId) { + log.info("分页查询优惠券领取记录: pageNum={}, pageSize={}, userId={}, couponId={}, status={}, startTime={}, endTime={}, scenicId={}", + pageNum, pageSize, userId, couponId, status, startTime, endTime, scenicId); PageInfo pageInfo = couponManagementService.getClaimRecordsPage( - pageNum, pageSize, userId, couponId, status, startTime, endTime); + pageNum, pageSize, userId, couponId, status, startTime, endTime, scenicId); return ApiResponse.success(pageInfo); } @@ -202,9 +204,20 @@ public class CouponManagementController { @GetMapping("/stats/period") public ApiResponse> getPeriodStats( @RequestParam String startDate, - @RequestParam String endDate) { - log.info("查询时间范围统计: startDate={}, endDate={}", startDate, endDate); - Map stats = couponManagementService.getPeriodStats(startDate, endDate); + @RequestParam String endDate, + @RequestParam(required = false) String scenicId) { + log.info("查询时间范围统计: startDate={}, endDate={}, scenicId={}", startDate, endDate, scenicId); + Map stats = couponManagementService.getPeriodStats(startDate, endDate, scenicId); + return ApiResponse.success(stats); + } + + /** + * 查询景区优惠券统计 + */ + @GetMapping("/stats/scenic/{scenicId}") + public ApiResponse> getScenicCouponStats(@PathVariable String scenicId) { + log.info("查询景区优惠券统计: scenicId={}", scenicId); + Map stats = couponManagementService.getScenicCouponStats(scenicId); return ApiResponse.success(stats); } diff --git a/src/main/java/com/ycwl/basic/pricing/dto/CouponUseRequest.java b/src/main/java/com/ycwl/basic/pricing/dto/CouponUseRequest.java index f1f7253..a8231e6 100644 --- a/src/main/java/com/ycwl/basic/pricing/dto/CouponUseRequest.java +++ b/src/main/java/com/ycwl/basic/pricing/dto/CouponUseRequest.java @@ -34,4 +34,9 @@ public class CouponUseRequest { * 优惠金额 */ private BigDecimal discountAmount; + + /** + * 景区ID + */ + private String scenicId; } \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/pricing/dto/ProductItem.java b/src/main/java/com/ycwl/basic/pricing/dto/ProductItem.java index 5bb0444..c5d2160 100644 --- a/src/main/java/com/ycwl/basic/pricing/dto/ProductItem.java +++ b/src/main/java/com/ycwl/basic/pricing/dto/ProductItem.java @@ -45,4 +45,9 @@ public class ProductItem { * 小计(计算后填入) */ private BigDecimal subtotal; + + /** + * 景区ID + */ + private String scenicId; } \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/pricing/entity/PriceCouponClaimRecord.java b/src/main/java/com/ycwl/basic/pricing/entity/PriceCouponClaimRecord.java index 352650f..22f1824 100644 --- a/src/main/java/com/ycwl/basic/pricing/entity/PriceCouponClaimRecord.java +++ b/src/main/java/com/ycwl/basic/pricing/entity/PriceCouponClaimRecord.java @@ -44,4 +44,9 @@ public class PriceCouponClaimRecord extends BaseEntity { * 状态 */ private CouponStatus status; + + /** + * 景区ID - 记录优惠券在哪个景区被领取/使用 + */ + private String scenicId; } \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/pricing/entity/PriceCouponConfig.java b/src/main/java/com/ycwl/basic/pricing/entity/PriceCouponConfig.java index f0e134e..386e6fe 100644 --- a/src/main/java/com/ycwl/basic/pricing/entity/PriceCouponConfig.java +++ b/src/main/java/com/ycwl/basic/pricing/entity/PriceCouponConfig.java @@ -70,4 +70,9 @@ public class PriceCouponConfig extends BaseEntity { * 是否启用 */ private Boolean isActive; + + /** + * 景区ID - 限制优惠券只能在该景区使用 + */ + private String scenicId; } \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/pricing/mapper/PriceCouponClaimRecordMapper.java b/src/main/java/com/ycwl/basic/pricing/mapper/PriceCouponClaimRecordMapper.java index 9c0dfd4..b95bf3d 100644 --- a/src/main/java/com/ycwl/basic/pricing/mapper/PriceCouponClaimRecordMapper.java +++ b/src/main/java/com/ycwl/basic/pricing/mapper/PriceCouponClaimRecordMapper.java @@ -40,18 +40,19 @@ public interface PriceCouponClaimRecordMapper extends BaseMapper" + "AND r.claim_time <= #{endTime}" + "" + + "" + + "AND r.scenic_id = #{scenicId}" + + "" + "" + "ORDER BY r.created_time DESC" + "") @@ -102,7 +106,8 @@ public interface PriceCouponClaimRecordMapper extends BaseMapper" + + "SELECT " + "COUNT(*) as total_claimed, " + "COUNT(CASE WHEN status = 'USED' THEN 1 END) as total_used, " + "COUNT(CASE WHEN status = 'CLAIMED' THEN 1 END) as total_available, " + @@ -169,7 +175,35 @@ public interface PriceCouponClaimRecordMapper extends BaseMapper= #{startDate} AND claim_time <= #{endDate}") + "WHERE claim_time >= #{startDate} AND claim_time <= #{endDate} " + + "" + + "AND scenic_id = #{scenicId} " + + "" + + "") java.util.Map selectPeriodStats(@Param("startDate") String startDate, - @Param("endDate") String endDate); + @Param("endDate") String endDate, + @Param("scenicId") String scenicId); + + /** + * 根据景区ID查询优惠券领取记录 + */ + @Select("SELECT r.*, c.coupon_name, c.coupon_type, c.discount_value " + + "FROM price_coupon_claim_record r " + + "LEFT JOIN price_coupon_config c ON r.coupon_id = c.id " + + "WHERE r.scenic_id = #{scenicId} " + + "ORDER BY r.created_time DESC") + List selectByScenicIdForAdmin(@Param("scenicId") String scenicId); + + /** + * 统计景区优惠券使用情况 + */ + @Select("SELECT " + + "COUNT(*) as total_claimed, " + + "COUNT(CASE WHEN status = 'USED' THEN 1 END) as total_used, " + + "COUNT(CASE WHEN status = 'CLAIMED' THEN 1 END) as total_available, " + + "COUNT(CASE WHEN status = 'EXPIRED' THEN 1 END) as total_expired, " + + "COUNT(DISTINCT coupon_id) as total_coupon_types, " + + "COUNT(DISTINCT user_id) as total_users " + + "FROM price_coupon_claim_record WHERE scenic_id = #{scenicId}") + java.util.Map selectScenicCouponUsageStats(@Param("scenicId") String scenicId); } \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/pricing/mapper/PriceCouponConfigMapper.java b/src/main/java/com/ycwl/basic/pricing/mapper/PriceCouponConfigMapper.java index c44585d..d1075a5 100644 --- a/src/main/java/com/ycwl/basic/pricing/mapper/PriceCouponConfigMapper.java +++ b/src/main/java/com/ycwl/basic/pricing/mapper/PriceCouponConfigMapper.java @@ -44,10 +44,10 @@ public interface PriceCouponConfigMapper extends BaseMapper { */ @Insert("INSERT INTO price_coupon_config (coupon_name, coupon_type, discount_value, min_amount, " + "max_discount, applicable_products, total_quantity, used_quantity, valid_from, valid_until, " + - "is_active, created_time, updated_time) VALUES " + + "is_active, scenic_id, created_time, updated_time) VALUES " + "(#{couponName}, #{couponType}, #{discountValue}, #{minAmount}, #{maxDiscount}, " + "#{applicableProducts}, #{totalQuantity}, #{usedQuantity}, #{validFrom}, #{validUntil}, " + - "#{isActive}, NOW(), NOW())") + "#{isActive}, #{scenicId}, NOW(), NOW())") int insertCoupon(PriceCouponConfig coupon); /** @@ -57,7 +57,7 @@ public interface PriceCouponConfigMapper extends BaseMapper { "discount_value = #{discountValue}, min_amount = #{minAmount}, max_discount = #{maxDiscount}, " + "applicable_products = #{applicableProducts}, total_quantity = #{totalQuantity}, " + "valid_from = #{validFrom}, valid_until = #{validUntil}, is_active = #{isActive}, " + - "updated_time = NOW() WHERE id = #{id}") + "scenic_id = #{scenicId}, updated_time = NOW() WHERE id = #{id}") int updateCoupon(PriceCouponConfig coupon); // ==================== 管理端接口 ==================== @@ -80,11 +80,15 @@ public interface PriceCouponConfigMapper extends BaseMapper { "" + "AND coupon_name LIKE CONCAT('%', #{couponName}, '%')" + "" + + "" + + "AND scenic_id = #{scenicId}" + + "" + "" + "ORDER BY created_time DESC" + "") List selectByConditionsForAdmin(@Param("isActive") Boolean isActive, - @Param("couponName") String couponName); + @Param("couponName") String couponName, + @Param("scenicId") String scenicId); /** * 管理端:根据状态查询优惠券配置 @@ -103,4 +107,30 @@ public interface PriceCouponConfigMapper extends BaseMapper { */ @Update("UPDATE price_coupon_config SET deleted = 1, updated_time = NOW() WHERE id = #{id}") int deleteCoupon(Long id); + + /** + * 查询指定景区的有效优惠券配置 + */ + @Select("SELECT * FROM price_coupon_config WHERE is_active = 1 " + + "AND valid_from <= NOW() AND valid_until > NOW() " + + "AND used_quantity < total_quantity " + + "AND (scenic_id IS NULL OR scenic_id = #{scenicId})") + List selectValidCouponsByScenicId(@Param("scenicId") String scenicId); + + /** + * 管理端:根据景区ID查询优惠券配置 + */ + @Select("SELECT * FROM price_coupon_config WHERE scenic_id = #{scenicId} ORDER BY created_time DESC") + List selectByScenicIdForAdmin(@Param("scenicId") String scenicId); + + /** + * 统计景区优惠券配置数量 + */ + @Select("SELECT " + + "COUNT(*) as total_coupons, " + + "COUNT(CASE WHEN is_active = 1 THEN 1 END) as active_coupons, " + + "SUM(total_quantity) as total_quantity, " + + "SUM(used_quantity) as used_quantity " + + "FROM price_coupon_config WHERE scenic_id = #{scenicId}") + java.util.Map selectScenicCouponConfigStats(@Param("scenicId") String scenicId); } \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/pricing/service/ICouponManagementService.java b/src/main/java/com/ycwl/basic/pricing/service/ICouponManagementService.java index 61b6583..71013cf 100644 --- a/src/main/java/com/ycwl/basic/pricing/service/ICouponManagementService.java +++ b/src/main/java/com/ycwl/basic/pricing/service/ICouponManagementService.java @@ -44,7 +44,7 @@ public interface ICouponManagementService { * 分页查询优惠券配置 */ PageInfo getCouponConfigsPage(Integer pageNum, Integer pageSize, - Boolean isActive, String couponName); + Boolean isActive, String couponName, String scenicId); /** * 根据状态查询优惠券配置 @@ -68,7 +68,7 @@ public interface ICouponManagementService { */ PageInfo getClaimRecordsPage(Integer pageNum, Integer pageSize, Long userId, Long couponId, CouponStatus status, - String startTime, String endTime); + String startTime, String endTime, String scenicId); /** * 根据用户ID查询优惠券领取记录 @@ -98,10 +98,15 @@ public interface ICouponManagementService { /** * 查询时间范围内的统计数据 */ - Map getPeriodStats(String startDate, String endDate); + Map getPeriodStats(String startDate, String endDate, String scenicId); /** * 查询所有优惠券的使用统计概览 */ List> getAllCouponUsageOverview(); + + /** + * 查询景区优惠券统计 + */ + Map getScenicCouponStats(String scenicId); } \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/pricing/service/impl/CouponManagementServiceImpl.java b/src/main/java/com/ycwl/basic/pricing/service/impl/CouponManagementServiceImpl.java index c7ccd42..4342fdf 100644 --- a/src/main/java/com/ycwl/basic/pricing/service/impl/CouponManagementServiceImpl.java +++ b/src/main/java/com/ycwl/basic/pricing/service/impl/CouponManagementServiceImpl.java @@ -126,12 +126,12 @@ public class CouponManagementServiceImpl implements ICouponManagementService { @Override public PageInfo getCouponConfigsPage(Integer pageNum, Integer pageSize, - Boolean isActive, String couponName) { - log.info("分页查询优惠券配置,页码: {}, 页大小: {}, 状态: {}, 名称: {}", - pageNum, pageSize, isActive, couponName); + Boolean isActive, String couponName, String scenicId) { + log.info("分页查询优惠券配置,页码: {}, 页大小: {}, 状态: {}, 名称: {}, 景区ID: {}", + pageNum, pageSize, isActive, couponName, scenicId); PageHelper.startPage(pageNum, pageSize); - List configs = couponConfigMapper.selectByConditionsForAdmin(isActive, couponName); + List configs = couponConfigMapper.selectByConditionsForAdmin(isActive, couponName, scenicId); return new PageInfo<>(configs); } @@ -158,12 +158,12 @@ public class CouponManagementServiceImpl implements ICouponManagementService { @Override public PageInfo getClaimRecordsPage(Integer pageNum, Integer pageSize, Long userId, Long couponId, CouponStatus status, - String startTime, String endTime) { - log.info("分页查询优惠券领取记录,页码: {}, 页大小: {}, 用户ID: {}, 优惠券ID: {}, 状态: {}, 开始时间: {}, 结束时间: {}", - pageNum, pageSize, userId, couponId, status, startTime, endTime); + String startTime, String endTime, String scenicId) { + log.info("分页查询优惠券领取记录,页码: {}, 页大小: {}, 用户ID: {}, 优惠券ID: {}, 状态: {}, 开始时间: {}, 结束时间: {}, 景区ID: {}", + pageNum, pageSize, userId, couponId, status, startTime, endTime, scenicId); PageHelper.startPage(pageNum, pageSize); - List records = claimRecordMapper.selectByConditionsForAdmin(userId, couponId, status, startTime, endTime); + List records = claimRecordMapper.selectByConditionsForAdmin(userId, couponId, status, startTime, endTime, scenicId); return new PageInfo<>(records); } @@ -198,9 +198,9 @@ public class CouponManagementServiceImpl implements ICouponManagementService { } @Override - public Map getPeriodStats(String startDate, String endDate) { - log.info("查询时间范围统计,开始日期: {}, 结束日期: {}", startDate, endDate); - return claimRecordMapper.selectPeriodStats(startDate, endDate); + public Map getPeriodStats(String startDate, String endDate, String scenicId) { + log.info("查询时间范围统计,开始日期: {}, 结束日期: {}, 景区ID: {}", startDate, endDate, scenicId); + return claimRecordMapper.selectPeriodStats(startDate, endDate, scenicId); } @Override @@ -231,4 +231,23 @@ public class CouponManagementServiceImpl implements ICouponManagementService { return overview; } + + @Override + public Map getScenicCouponStats(String scenicId) { + log.info("查询景区优惠券统计,景区ID: {}", scenicId); + + // 获取景区优惠券配置统计 + Map configStats = couponConfigMapper.selectScenicCouponConfigStats(scenicId); + + // 获取景区优惠券使用统计 + Map usageStats = claimRecordMapper.selectScenicCouponUsageStats(scenicId); + + // 合并统计结果 + Map result = new HashMap<>(); + result.put("scenic_id", scenicId); + result.putAll(configStats); + result.putAll(usageStats); + + return result; + } } \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/pricing/service/impl/CouponServiceImpl.java b/src/main/java/com/ycwl/basic/pricing/service/impl/CouponServiceImpl.java index 4394dd5..a908f27 100644 --- a/src/main/java/com/ycwl/basic/pricing/service/impl/CouponServiceImpl.java +++ b/src/main/java/com/ycwl/basic/pricing/service/impl/CouponServiceImpl.java @@ -82,10 +82,29 @@ public class CouponServiceImpl implements ICouponService { @Override public boolean isCouponApplicable(PriceCouponConfig coupon, List products, BigDecimal totalAmount) { + // 1. 检查最小使用金额 if (totalAmount.compareTo(coupon.getMinAmount()) < 0) { return false; } + // 2. 检查景区限制 + if (coupon.getScenicId() != null && !coupon.getScenicId().isEmpty()) { + boolean hasMatchingScenicProduct = false; + for (ProductItem product : products) { + if (coupon.getScenicId().equals(product.getScenicId())) { + hasMatchingScenicProduct = true; + break; + } + } + if (!hasMatchingScenicProduct) { + log.debug("优惠券景区限制不匹配: 优惠券景区={}, 商品景区={}", + coupon.getScenicId(), + products.stream().map(ProductItem::getScenicId).distinct().toList()); + return false; + } + } + + // 3. 检查商品类型限制 if (coupon.getApplicableProducts() == null || coupon.getApplicableProducts().isEmpty()) { return true; } @@ -127,14 +146,19 @@ public class CouponServiceImpl implements ICouponService { LocalDateTime useTime = LocalDateTime.now(); - // 设置使用时间和订单信息 + // 设置使用时间、订单信息和景区信息 record.setStatus(CouponStatus.USED); record.setUseTime(useTime); record.setOrderId(request.getOrderId()); record.setUpdatedTime(LocalDateTime.now()); + // 如果请求中包含景区ID,记录到使用记录中 + if (request.getScenicId() != null && !request.getScenicId().isEmpty()) { + record.setScenicId(request.getScenicId()); + } + couponClaimRecordMapper.updateCouponStatus( - record.getId(), CouponStatus.USED, useTime, request.getOrderId()); + record.getId(), CouponStatus.USED, useTime, request.getOrderId(), request.getScenicId()); CouponUseResult result = new CouponUseResult(); result.setCouponId(request.getCouponId());