first commit
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
# 优惠券中心模块 (ruoyi-mall-coupon)
|
||||
|
||||
## 模块简介
|
||||
|
||||
`ruoyi-mall-coupon` 是商城系统的优惠券中心模块,提供独立的优惠券服务,支持发券、核销、过期处理等功能。
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 1. 优惠券管理 ✅
|
||||
|
||||
- ✅ 优惠券CRUD操作
|
||||
- ✅ 优惠券类型管理(满减、折扣、现金)
|
||||
- ✅ 优惠券发放规则配置
|
||||
- ✅ 优惠券有效期管理
|
||||
- ✅ 优惠券状态管理(启用/禁用)
|
||||
- ✅ 优惠券导出功能
|
||||
|
||||
### 2. 用户优惠券 ✅
|
||||
|
||||
- ✅ 用户领券
|
||||
- ✅ 用户优惠券列表查询
|
||||
- ✅ 优惠券使用(订单结算时调用)
|
||||
- ✅ 优惠券退还(订单取消时调用)
|
||||
- ✅ 优惠券过期处理(定时任务)✅
|
||||
|
||||
### 3. 优惠券统计
|
||||
|
||||
- [ ] 发放统计(可在管理端通过列表查询实现)
|
||||
- [ ] 使用统计(可在管理端通过列表查询实现)
|
||||
- [ ] 核销统计(可在管理端通过列表查询实现)
|
||||
|
||||
## 数据库表
|
||||
|
||||
- `mall_coupon` - 优惠券表
|
||||
- `mall_coupon_user` - 用户优惠券表
|
||||
|
||||
详细表结构请参考:`script/sql/ry_mall.sql`
|
||||
|
||||
## 模块结构
|
||||
|
||||
```
|
||||
org.dromara.mall.coupon
|
||||
├── controller
|
||||
│ ├── admin // 管理端API
|
||||
│ │ ├── AdminMallCouponController.java
|
||||
│ │ └── AdminMallCouponUserController.java
|
||||
│ └── app // 用户端API
|
||||
│ ├── AppMallCouponController.java
|
||||
│ └── AppMallCouponUserController.java
|
||||
├── domain
|
||||
│ ├── MallCoupon.java
|
||||
│ ├── MallCouponUser.java
|
||||
│ ├── bo // 业务对象
|
||||
│ │ ├── MallCouponBo.java
|
||||
│ │ └── MallCouponUserBo.java
|
||||
│ └── vo // 视图对象
|
||||
│ ├── MallCouponVo.java
|
||||
│ └── MallCouponUserVo.java
|
||||
├── mapper
|
||||
│ ├── MallCouponMapper.java
|
||||
│ └── MallCouponUserMapper.java
|
||||
├── service
|
||||
│ ├── MallCouponService.java
|
||||
│ ├── MallCouponUserService.java
|
||||
│ └── impl
|
||||
│ ├── MallCouponServiceImpl.java
|
||||
│ └── MallCouponUserServiceImpl.java
|
||||
├── job // 定时任务
|
||||
│ └── MallCouponJob.java
|
||||
└── config
|
||||
└── MallCouponAutoConfiguration.java
|
||||
```
|
||||
|
||||
## API接口
|
||||
|
||||
### 管理端接口
|
||||
|
||||
#### 优惠券管理 (`/mall/coupon`)
|
||||
|
||||
- `GET /mall/coupon/list` - 查询优惠券列表(分页)
|
||||
- `GET /mall/coupon/{id}` - 获取优惠券详情
|
||||
- `POST /mall/coupon` - 新增优惠券
|
||||
- `PUT /mall/coupon` - 修改优惠券
|
||||
- `DELETE /mall/coupon/{ids}` - 删除优惠券
|
||||
- `POST /mall/coupon/export` - 导出优惠券列表
|
||||
- `PUT /mall/coupon/changeStatus/{id}` - 启用/禁用优惠券
|
||||
|
||||
#### 用户优惠券管理 (`/mall/coupon/user`)
|
||||
|
||||
- `GET /mall/coupon/user/list` - 查询用户优惠券列表(分页)
|
||||
- `GET /mall/coupon/user/{id}` - 获取用户优惠券详情
|
||||
- `DELETE /mall/coupon/user/{ids}` - 删除用户优惠券
|
||||
- `POST /mall/coupon/user/export` - 导出用户优惠券列表
|
||||
|
||||
### 移动端接口
|
||||
|
||||
#### 优惠券 (`/app/mall/coupon`)
|
||||
|
||||
- `GET /app/mall/coupon/available/list` - 查询可领取的优惠券列表
|
||||
- `GET /app/mall/coupon/{id}` - 获取优惠券详情
|
||||
|
||||
#### 用户优惠券 (`/app/mall/coupon/user`)
|
||||
|
||||
- `GET /app/mall/coupon/user/list` - 查询用户优惠券列表
|
||||
- `GET /app/mall/coupon/user/available/list` - 查询用户可用优惠券列表(未使用且未过期)
|
||||
- `GET /app/mall/coupon/user/{id}` - 获取用户优惠券详情
|
||||
- `POST /app/mall/coupon/user/receive/{couponId}` - 领取优惠券
|
||||
|
||||
## 优惠券类型说明
|
||||
|
||||
- **0 - 满减券**: 需要设置优惠金额和使用门槛
|
||||
- **1 - 折扣券**: 需要设置折扣率(百分比)和使用门槛
|
||||
- **2 - 现金券**: 需要设置优惠金额,无使用门槛
|
||||
|
||||
## 依赖模块
|
||||
|
||||
- `ruoyi-common-*` - 通用工具模块
|
||||
- `ruoyi-common-excel` - Excel导出功能
|
||||
- `ruoyi-common-satoken` - 用户身份认证
|
||||
|
||||
## 待实现功能
|
||||
|
||||
- [ ] 优惠券统计功能(可在管理端通过列表查询和筛选实现)
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 订单结算时使用优惠券
|
||||
|
||||
在订单提交时,可以调用 `MallCouponUserService.useCoupon(couponUserId, orderId)` 来使用优惠券。
|
||||
|
||||
### 订单取消时退还优惠券
|
||||
|
||||
在订单取消时,可以调用 `MallCouponUserService.returnCoupon(couponUserId)` 来退还优惠券。
|
||||
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-mall</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-mall-coupon</artifactId>
|
||||
|
||||
<description>
|
||||
ruoyi-mall-coupon 优惠券中心模块
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-doc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-log</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-excel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-satoken</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package org.dromara.mall.coupon.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 优惠券中心自动配置类
|
||||
* 主要用于扫描优惠券中心模块的组件
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@ComponentScan(basePackages = "org.dromara.mall.coupon")
|
||||
@ConditionalOnProperty(prefix = "ruoyi.mall.coupon", name = "enabled", havingValue = "true", matchIfMissing = true)
|
||||
public class MallCouponAutoConfiguration {
|
||||
|
||||
public MallCouponAutoConfiguration() {
|
||||
log.info("优惠券中心模块已启用");
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
package org.dromara.mall.coupon.controller.admin;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.mall.coupon.domain.bo.MallCouponBo;
|
||||
import org.dromara.mall.coupon.domain.vo.CouponStatisticsVo;
|
||||
import org.dromara.mall.coupon.domain.vo.MallCouponVo;
|
||||
import org.dromara.mall.coupon.service.MallCouponService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 优惠券管理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "管理端-优惠券管理", description = "优惠券管理接口")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/mall/coupon")
|
||||
public class AdminMallCouponController extends BaseController {
|
||||
|
||||
private final MallCouponService mallCouponService;
|
||||
|
||||
/**
|
||||
* 查询优惠券列表
|
||||
*/
|
||||
@Operation(summary = "查询优惠券列表", description = "分页查询优惠券列表")
|
||||
@SaCheckPermission("mall:coupon:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<MallCouponVo> list(@Parameter(description = "优惠券查询条件") MallCouponBo bo,
|
||||
@Parameter(description = "分页参数") PageQuery pageQuery) {
|
||||
return mallCouponService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出售后申请列表
|
||||
*/
|
||||
@Operation(summary = "导出优惠券列表", description = "导出优惠券到Excel")
|
||||
@SaCheckPermission("mall:coupon:export")
|
||||
@Log(title = "优惠券", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(@Parameter(description = "优惠券查询条件") MallCouponBo bo,
|
||||
@Parameter(description = "响应对象") HttpServletResponse response) {
|
||||
List<MallCouponVo> list = mallCouponService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "优惠券", MallCouponVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取优惠券详细信息
|
||||
*/
|
||||
@Operation(summary = "获取优惠券详情", description = "根据优惠券ID获取详细信息")
|
||||
@SaCheckPermission("mall:coupon:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<MallCouponVo> getInfo(@Parameter(description = "优惠券ID", required = true)
|
||||
@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(mallCouponService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增优惠券
|
||||
*/
|
||||
@Operation(summary = "新增优惠券", description = "创建新的优惠券")
|
||||
@SaCheckPermission("mall:coupon:add")
|
||||
@Log(title = "优惠券", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public R<Void> add(@Parameter(description = "优惠券信息") @Validated @RequestBody MallCouponBo bo) {
|
||||
return toAjax(mallCouponService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改优惠券
|
||||
*/
|
||||
@Operation(summary = "修改优惠券", description = "更新优惠券信息")
|
||||
@SaCheckPermission("mall:coupon:edit")
|
||||
@Log(title = "优惠券", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public R<Void> edit(@Parameter(description = "优惠券信息") @Validated @RequestBody MallCouponBo bo) {
|
||||
return toAjax(mallCouponService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除优惠券
|
||||
*/
|
||||
@Operation(summary = "删除优惠券", description = "删除优惠券")
|
||||
@SaCheckPermission("mall:coupon:remove")
|
||||
@Log(title = "优惠券", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@Parameter(description = "优惠券ID数组", required = true)
|
||||
@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(mallCouponService.deleteWithValidByIds(Arrays.asList(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用/禁用优惠券
|
||||
*/
|
||||
@Operation(summary = "启用/禁用优惠券", description = "更改优惠券状态")
|
||||
@SaCheckPermission("mall:coupon:edit")
|
||||
@Log(title = "优惠券", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/changeStatus/{id}")
|
||||
public R<Void> changeStatus(@Parameter(description = "优惠券ID", required = true)
|
||||
@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id,
|
||||
@Parameter(description = "状态", required = true)
|
||||
@NotNull(message = "状态不能为空")
|
||||
@RequestParam Integer status) {
|
||||
return toAjax(mallCouponService.changeStatus(id, status));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取优惠券统计信息
|
||||
*/
|
||||
@Operation(summary = "获取优惠券统计信息", description = "获取优惠券的发放、使用、核销等统计数据")
|
||||
@SaCheckPermission("mall:coupon:query")
|
||||
@GetMapping("/statistics")
|
||||
public R<CouponStatisticsVo> getStatistics(
|
||||
@Parameter(description = "优惠券ID,为空则统计所有优惠券")
|
||||
@RequestParam(required = false) Long couponId) {
|
||||
return R.ok(mallCouponService.getStatistics(couponId));
|
||||
}
|
||||
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package org.dromara.mall.coupon.controller.admin;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.mall.coupon.domain.bo.MallCouponUserBo;
|
||||
import org.dromara.mall.coupon.domain.vo.MallCouponUserVo;
|
||||
import org.dromara.mall.coupon.service.MallCouponUserService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户优惠券管理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "管理端-用户优惠券管理", description = "用户优惠券管理接口")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/mall/coupon/user")
|
||||
public class AdminMallCouponUserController extends BaseController {
|
||||
|
||||
private final MallCouponUserService mallCouponUserService;
|
||||
|
||||
/**
|
||||
* 查询用户优惠券列表
|
||||
*/
|
||||
@Operation(summary = "查询用户优惠券列表", description = "分页查询用户优惠券列表")
|
||||
@SaCheckPermission("mall:coupon:user:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<MallCouponUserVo> list(@Parameter(description = "用户优惠券查询条件") MallCouponUserBo bo,
|
||||
@Parameter(description = "分页参数") PageQuery pageQuery) {
|
||||
return mallCouponUserService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出用户优惠券列表
|
||||
*/
|
||||
@Operation(summary = "导出用户优惠券列表", description = "导出用户优惠券到Excel")
|
||||
@SaCheckPermission("mall:coupon:user:export")
|
||||
@Log(title = "用户优惠券", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(@Parameter(description = "用户优惠券查询条件") MallCouponUserBo bo,
|
||||
@Parameter(description = "响应对象") HttpServletResponse response) {
|
||||
List<MallCouponUserVo> list = mallCouponUserService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "用户优惠券", MallCouponUserVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户优惠券详细信息
|
||||
*/
|
||||
@Operation(summary = "获取用户优惠券详情", description = "根据用户优惠券ID获取详细信息")
|
||||
@SaCheckPermission("mall:coupon:user:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<MallCouponUserVo> getInfo(@Parameter(description = "用户优惠券ID", required = true)
|
||||
@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(mallCouponUserService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户优惠券
|
||||
*/
|
||||
@Operation(summary = "删除用户优惠券", description = "删除用户优惠券")
|
||||
@SaCheckPermission("mall:coupon:user:remove")
|
||||
@Log(title = "用户优惠券", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@Parameter(description = "用户优惠券ID数组", required = true)
|
||||
@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(mallCouponUserService.deleteWithValidByIds(Arrays.asList(ids), true));
|
||||
}
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package org.dromara.mall.coupon.controller.app;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.mall.coupon.domain.vo.MallCouponVo;
|
||||
import org.dromara.mall.coupon.service.MallCouponService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 优惠券(移动端)
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "移动端-优惠券", description = "优惠券接口")
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/mall/coupon")
|
||||
public class AppMallCouponController {
|
||||
|
||||
private final MallCouponService mallCouponService;
|
||||
|
||||
/**
|
||||
* 查询可领取的优惠券列表
|
||||
*/
|
||||
@Operation(summary = "查询可领取的优惠券列表", description = "查询用户可以领取的优惠券列表")
|
||||
@GetMapping("/available/list")
|
||||
public R<List<MallCouponVo>> getAvailableList() {
|
||||
List<MallCouponVo> list = mallCouponService.queryAvailableList();
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取优惠券详情
|
||||
*/
|
||||
@Operation(summary = "获取优惠券详情", description = "根据优惠券ID获取详细信息")
|
||||
@GetMapping("/{id}")
|
||||
public R<MallCouponVo> getInfo(@Parameter(description = "优惠券ID", required = true)
|
||||
@PathVariable Long id) {
|
||||
return R.ok(mallCouponService.queryById(id));
|
||||
}
|
||||
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package org.dromara.mall.coupon.controller.app;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.mall.coupon.domain.bo.MallCouponUserBo;
|
||||
import org.dromara.mall.coupon.domain.vo.MallCouponUserVo;
|
||||
import org.dromara.mall.coupon.service.MallCouponUserService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户优惠券(移动端)
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Tag(name = "移动端-用户优惠券", description = "用户优惠券接口")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/mall/coupon/user")
|
||||
public class AppMallCouponUserController {
|
||||
|
||||
private final MallCouponUserService mallCouponUserService;
|
||||
|
||||
/**
|
||||
* 查询用户优惠券列表
|
||||
*/
|
||||
@Operation(summary = "查询用户优惠券列表", description = "查询当前用户的优惠券列表")
|
||||
@GetMapping("/list")
|
||||
public R<TableDataInfo<MallCouponUserVo>> list(@Parameter(description = "用户优惠券查询条件") MallCouponUserBo bo,
|
||||
@Parameter(description = "分页参数") PageQuery pageQuery) {
|
||||
// 移动端只能查询当前用户的优惠券
|
||||
TableDataInfo<MallCouponUserVo> result = mallCouponUserService.queryPageList(bo, pageQuery);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户可用优惠券列表
|
||||
*/
|
||||
@Operation(summary = "查询用户可用优惠券列表", description = "查询当前用户可用的优惠券列表(未使用且未过期)")
|
||||
@GetMapping("/available/list")
|
||||
public R<List<MallCouponUserVo>> getAvailableList() {
|
||||
Long userId = org.dromara.common.satoken.utils.LoginHelper.getUserId();
|
||||
List<MallCouponUserVo> list = mallCouponUserService.queryAvailableList(userId);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户优惠券详情
|
||||
*/
|
||||
@Operation(summary = "获取用户优惠券详情", description = "根据用户优惠券ID获取详细信息")
|
||||
@GetMapping("/{id}")
|
||||
public R<MallCouponUserVo> getInfo(@Parameter(description = "用户优惠券ID", required = true)
|
||||
@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(mallCouponUserService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 领取优惠券
|
||||
*/
|
||||
@Operation(summary = "领取优惠券", description = "用户领取优惠券")
|
||||
@PostMapping("/receive/{couponId}")
|
||||
public R<Void> receiveCoupon(@Parameter(description = "优惠券ID", required = true)
|
||||
@NotNull(message = "优惠券ID不能为空")
|
||||
@PathVariable Long couponId) {
|
||||
return R.ok(mallCouponUserService.receiveCoupon(couponId));
|
||||
}
|
||||
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
package org.dromara.mall.coupon.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 优惠券对象 mall_coupon
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode
|
||||
@TableName("mall_coupon")
|
||||
public class MallCoupon implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 优惠券ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 优惠券名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 优惠券类型(0满减 1折扣 2现金)
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 优惠金额(分)
|
||||
*/
|
||||
private Integer discountAmount;
|
||||
|
||||
/**
|
||||
* 折扣率(%)
|
||||
*/
|
||||
private BigDecimal discountRate;
|
||||
|
||||
/**
|
||||
* 使用门槛(分)
|
||||
*/
|
||||
private Integer minAmount;
|
||||
|
||||
/**
|
||||
* 发放总数(null表示不限)
|
||||
*/
|
||||
private Integer totalCount;
|
||||
|
||||
/**
|
||||
* 已使用数量
|
||||
*/
|
||||
private Integer usedCount;
|
||||
|
||||
/**
|
||||
* 每人限领数量
|
||||
*/
|
||||
private Integer perLimit;
|
||||
|
||||
/**
|
||||
* 有效开始时间
|
||||
*/
|
||||
private Date validStartTime;
|
||||
|
||||
/**
|
||||
* 有效结束时间
|
||||
*/
|
||||
private Date validEndTime;
|
||||
|
||||
/**
|
||||
* 状态(0启用 1禁用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package org.dromara.mall.coupon.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户优惠券对象 mall_coupon_user
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@TableName("mall_coupon_user")
|
||||
public class MallCouponUser {
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 优惠券ID
|
||||
*/
|
||||
private Long couponId;
|
||||
|
||||
/**
|
||||
* 状态(0未使用 1已使用 2已过期)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 使用时间
|
||||
*/
|
||||
private Date usedTime;
|
||||
|
||||
/**
|
||||
* 使用的订单ID
|
||||
*/
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 领取时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
package org.dromara.mall.coupon.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.mall.coupon.domain.MallCoupon;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 优惠券业务对象 mall_coupon
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = MallCoupon.class, reverseConvertGenerate = false)
|
||||
public class MallCouponBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 优惠券ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 优惠券名称
|
||||
*/
|
||||
@NotBlank(message = "优惠券名称不能为空")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 优惠券类型(0满减 1折扣 2现金)
|
||||
*/
|
||||
@NotNull(message = "优惠券类型不能为空")
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 优惠金额(分)
|
||||
*/
|
||||
@Min(value = 0, message = "优惠金额不能为负数")
|
||||
private Integer discountAmount;
|
||||
|
||||
/**
|
||||
* 折扣率(%)
|
||||
*/
|
||||
@Min(value = 0, message = "折扣率不能为负数")
|
||||
private BigDecimal discountRate;
|
||||
|
||||
/**
|
||||
* 使用门槛(分)
|
||||
*/
|
||||
@Min(value = 0, message = "使用门槛不能为负数")
|
||||
private Integer minAmount;
|
||||
|
||||
/**
|
||||
* 发放总数(null表示不限)
|
||||
*/
|
||||
@Min(value = 1, message = "发放总数必须大于0")
|
||||
private Integer totalCount;
|
||||
|
||||
/**
|
||||
* 已使用数量
|
||||
*/
|
||||
private Integer usedCount;
|
||||
|
||||
/**
|
||||
* 每人限领数量
|
||||
*/
|
||||
@Min(value = 1, message = "每人限领数量必须大于0")
|
||||
private Integer perLimit;
|
||||
|
||||
/**
|
||||
* 有效开始时间
|
||||
*/
|
||||
@NotNull(message = "有效开始时间不能为空")
|
||||
private Date validStartTime;
|
||||
|
||||
/**
|
||||
* 有效结束时间
|
||||
*/
|
||||
@NotNull(message = "有效结束时间不能为空")
|
||||
private Date validEndTime;
|
||||
|
||||
/**
|
||||
* 状态(0启用 1禁用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package org.dromara.mall.coupon.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.dromara.mall.coupon.domain.MallCouponUser;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户优惠券业务对象 mall_coupon_user
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@AutoMapper(target = MallCouponUser.class, reverseConvertGenerate = false)
|
||||
public class MallCouponUserBo {
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@NotNull(message = "用户ID不能为空")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 优惠券ID
|
||||
*/
|
||||
@NotNull(message = "优惠券ID不能为空")
|
||||
private Long couponId;
|
||||
|
||||
/**
|
||||
* 状态(0未使用 1已使用 2已过期)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 使用时间
|
||||
*/
|
||||
private Date usedTime;
|
||||
|
||||
/**
|
||||
* 使用的订单ID
|
||||
*/
|
||||
private Long orderId;
|
||||
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package org.dromara.mall.coupon.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 优惠券统计数据视图对象
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
public class CouponStatisticsVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 优惠券ID
|
||||
*/
|
||||
private Long couponId;
|
||||
|
||||
/**
|
||||
* 优惠券名称
|
||||
*/
|
||||
private String couponName;
|
||||
|
||||
/**
|
||||
* 发放总数(已领取数量)
|
||||
*/
|
||||
private Long issuedCount;
|
||||
|
||||
/**
|
||||
* 使用数量(已使用数量)
|
||||
*/
|
||||
private Long usedCount;
|
||||
|
||||
/**
|
||||
* 使用率(使用数量/发放数量,百分比)
|
||||
*/
|
||||
private Double usageRate;
|
||||
|
||||
/**
|
||||
* 核销金额(分,基于订单优惠券使用记录表)
|
||||
*/
|
||||
private Long redeemedAmount;
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package org.dromara.mall.coupon.domain.vo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.mall.coupon.domain.MallCouponUser;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户优惠券视图对象 mall_coupon_user
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@AutoMapper(target = MallCouponUser.class)
|
||||
public class MallCouponUserVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 优惠券ID
|
||||
*/
|
||||
private Long couponId;
|
||||
|
||||
/**
|
||||
* 状态(0未使用 1已使用 2已过期)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 使用时间
|
||||
*/
|
||||
private Date usedTime;
|
||||
|
||||
/**
|
||||
* 使用的订单ID
|
||||
*/
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 领取时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 优惠券信息(关联查询)
|
||||
*/
|
||||
private MallCouponVo couponInfo;
|
||||
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
package org.dromara.mall.coupon.domain.vo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.mall.coupon.domain.MallCoupon;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 优惠券视图对象 mall_coupon
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Data
|
||||
@AutoMapper(target = MallCoupon.class)
|
||||
public class MallCouponVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 优惠券ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 优惠券名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 优惠券类型(0满减 1折扣 2现金)
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 优惠金额(分)
|
||||
*/
|
||||
private Integer discountAmount;
|
||||
|
||||
/**
|
||||
* 折扣率(%)
|
||||
*/
|
||||
private BigDecimal discountRate;
|
||||
|
||||
/**
|
||||
* 使用门槛(分)
|
||||
*/
|
||||
private Integer minAmount;
|
||||
|
||||
/**
|
||||
* 发放总数(null表示不限)
|
||||
*/
|
||||
private Integer totalCount;
|
||||
|
||||
/**
|
||||
* 已使用数量
|
||||
*/
|
||||
private Integer usedCount;
|
||||
|
||||
/**
|
||||
* 每人限领数量
|
||||
*/
|
||||
private Integer perLimit;
|
||||
|
||||
/**
|
||||
* 有效开始时间
|
||||
*/
|
||||
private Date validStartTime;
|
||||
|
||||
/**
|
||||
* 有效结束时间
|
||||
*/
|
||||
private Date validEndTime;
|
||||
|
||||
/**
|
||||
* 状态(0启用 1禁用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package org.dromara.mall.coupon.job;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.mall.coupon.service.MallCouponUserService;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 优惠券定时任务
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class MallCouponJob {
|
||||
|
||||
private final MallCouponUserService couponUserService;
|
||||
|
||||
/**
|
||||
* 优惠券过期处理任务
|
||||
* 每天凌晨2点执行一次
|
||||
* 处理所有已过期的优惠券,将状态更新为已过期(status=2)
|
||||
*/
|
||||
@Scheduled(cron = "0 0 2 * * ?")
|
||||
public void processExpiredCoupons() {
|
||||
log.info("开始执行优惠券过期处理任务");
|
||||
try {
|
||||
couponUserService.processExpiredCoupons();
|
||||
log.info("优惠券过期处理任务执行完成");
|
||||
} catch (Exception e) {
|
||||
log.error("优惠券过期处理任务执行失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package org.dromara.mall.coupon.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.mall.coupon.domain.MallCoupon;
|
||||
import org.dromara.mall.coupon.domain.vo.MallCouponVo;
|
||||
|
||||
/**
|
||||
* 优惠券Mapper接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Mapper
|
||||
public interface MallCouponMapper extends BaseMapperPlus<MallCoupon, MallCouponVo> {
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package org.dromara.mall.coupon.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.mall.coupon.domain.MallCouponUser;
|
||||
import org.dromara.mall.coupon.domain.vo.MallCouponUserVo;
|
||||
|
||||
/**
|
||||
* 用户优惠券Mapper接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@Mapper
|
||||
public interface MallCouponUserMapper extends BaseMapperPlus<MallCouponUser, MallCouponUserVo> {
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package org.dromara.mall.coupon.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.mall.coupon.domain.bo.MallCouponBo;
|
||||
import org.dromara.mall.coupon.domain.vo.CouponStatisticsVo;
|
||||
import org.dromara.mall.coupon.domain.vo.MallCouponVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 优惠券Service接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface MallCouponService {
|
||||
|
||||
/**
|
||||
* 查询优惠券
|
||||
*/
|
||||
MallCouponVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 查询优惠券列表
|
||||
*/
|
||||
TableDataInfo<MallCouponVo> queryPageList(MallCouponBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询优惠券列表
|
||||
*/
|
||||
List<MallCouponVo> queryList(MallCouponBo bo);
|
||||
|
||||
/**
|
||||
* 查询可领取的优惠券列表(移动端)
|
||||
*/
|
||||
List<MallCouponVo> queryAvailableList();
|
||||
|
||||
/**
|
||||
* 新增优惠券
|
||||
*/
|
||||
Boolean insertByBo(MallCouponBo bo);
|
||||
|
||||
/**
|
||||
* 修改优惠券
|
||||
*/
|
||||
Boolean updateByBo(MallCouponBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除优惠券信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 启用/禁用优惠券
|
||||
*/
|
||||
Boolean changeStatus(Long id, Integer status);
|
||||
|
||||
/**
|
||||
* 获取优惠券统计信息
|
||||
*
|
||||
* @param couponId 优惠券ID,如果为空则统计所有优惠券
|
||||
* @return 优惠券统计数据
|
||||
*/
|
||||
CouponStatisticsVo getStatistics(Long couponId);
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package org.dromara.mall.coupon.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.mall.coupon.domain.bo.MallCouponUserBo;
|
||||
import org.dromara.mall.coupon.domain.vo.MallCouponUserVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户优惠券Service接口
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
public interface MallCouponUserService {
|
||||
|
||||
/**
|
||||
* 查询用户优惠券
|
||||
*/
|
||||
MallCouponUserVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 查询用户优惠券列表
|
||||
*/
|
||||
TableDataInfo<MallCouponUserVo> queryPageList(MallCouponUserBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询用户优惠券列表
|
||||
*/
|
||||
List<MallCouponUserVo> queryList(MallCouponUserBo bo);
|
||||
|
||||
/**
|
||||
* 查询用户可用优惠券列表
|
||||
*/
|
||||
List<MallCouponUserVo> queryAvailableList(Long userId);
|
||||
|
||||
/**
|
||||
* 用户领取优惠券
|
||||
*/
|
||||
Boolean receiveCoupon(Long couponId);
|
||||
|
||||
/**
|
||||
* 使用优惠券(订单结算时调用)
|
||||
*/
|
||||
Boolean useCoupon(Long couponUserId, Long orderId);
|
||||
|
||||
/**
|
||||
* 退还优惠券(订单取消时调用)
|
||||
*/
|
||||
Boolean returnCoupon(Long couponUserId);
|
||||
|
||||
/**
|
||||
* 批量删除用户优惠券信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 处理过期优惠券(定时任务调用)
|
||||
*/
|
||||
void processExpiredCoupons();
|
||||
|
||||
}
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
package org.dromara.mall.coupon.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.mall.coupon.domain.MallCoupon;
|
||||
import org.dromara.mall.coupon.domain.MallCouponUser;
|
||||
import org.dromara.mall.coupon.domain.bo.MallCouponBo;
|
||||
import org.dromara.mall.coupon.domain.vo.CouponStatisticsVo;
|
||||
import org.dromara.mall.coupon.domain.vo.MallCouponVo;
|
||||
import org.dromara.mall.coupon.mapper.MallCouponMapper;
|
||||
import org.dromara.mall.coupon.mapper.MallCouponUserMapper;
|
||||
import org.dromara.mall.coupon.service.MallCouponService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 优惠券Service业务层处理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class MallCouponServiceImpl implements MallCouponService {
|
||||
|
||||
private final MallCouponMapper baseMapper;
|
||||
private final MallCouponUserMapper couponUserMapper;
|
||||
|
||||
/**
|
||||
* 查询优惠券
|
||||
*/
|
||||
@Override
|
||||
public MallCouponVo queryById(Long id) {
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询优惠券列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<MallCouponVo> queryPageList(MallCouponBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<MallCoupon> lqw = buildQueryWrapper(bo);
|
||||
Page<MallCouponVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询优惠券列表
|
||||
*/
|
||||
@Override
|
||||
public List<MallCouponVo> queryList(MallCouponBo bo) {
|
||||
LambdaQueryWrapper<MallCoupon> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询可领取的优惠券列表(移动端)
|
||||
*/
|
||||
@Override
|
||||
public List<MallCouponVo> queryAvailableList() {
|
||||
LambdaQueryWrapper<MallCoupon> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(MallCoupon::getStatus, 0); // 启用状态
|
||||
Date now = new Date();
|
||||
lqw.le(MallCoupon::getValidStartTime, now); // 已开始
|
||||
lqw.ge(MallCoupon::getValidEndTime, now); // 未结束
|
||||
// 发放总数未限制或已发放数量小于总数
|
||||
lqw.and(wrapper -> wrapper
|
||||
.isNull(MallCoupon::getTotalCount)
|
||||
.or(wrapper2 -> wrapper2.apply("used_count < total_count"))
|
||||
);
|
||||
lqw.orderByDesc(MallCoupon::getCreateTime);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<MallCoupon> buildQueryWrapper(MallCouponBo bo) {
|
||||
LambdaQueryWrapper<MallCoupon> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.like(StringUtils.isNotBlank(bo.getName()), MallCoupon::getName, bo.getName());
|
||||
lqw.eq(bo.getType() != null, MallCoupon::getType, bo.getType());
|
||||
lqw.eq(bo.getStatus() != null, MallCoupon::getStatus, bo.getStatus());
|
||||
lqw.ge(bo.getValidStartTime() != null, MallCoupon::getValidStartTime, bo.getValidStartTime());
|
||||
lqw.le(bo.getValidEndTime() != null, MallCoupon::getValidEndTime, bo.getValidEndTime());
|
||||
lqw.orderByDesc(MallCoupon::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增优惠券
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean insertByBo(MallCouponBo bo) {
|
||||
MallCoupon add = MapstructUtils.convert(bo, MallCoupon.class);
|
||||
validEntityBeforeSave(add);
|
||||
|
||||
// 设置默认值
|
||||
if (add.getMinAmount() == null) {
|
||||
add.setMinAmount(0);
|
||||
}
|
||||
if (add.getUsedCount() == null) {
|
||||
add.setUsedCount(0);
|
||||
}
|
||||
if (add.getPerLimit() == null) {
|
||||
add.setPerLimit(1);
|
||||
}
|
||||
if (add.getStatus() == null) {
|
||||
add.setStatus(0); // 默认启用
|
||||
}
|
||||
|
||||
// 校验优惠券类型和对应字段
|
||||
validateCouponType(add);
|
||||
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改优惠券
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean updateByBo(MallCouponBo bo) {
|
||||
MallCoupon update = MapstructUtils.convert(bo, MallCoupon.class);
|
||||
validEntityBeforeSave(update);
|
||||
|
||||
// 校验优惠券类型和对应字段
|
||||
validateCouponType(update);
|
||||
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(MallCoupon entity) {
|
||||
// 校验有效期
|
||||
if (entity.getValidStartTime() != null && entity.getValidEndTime() != null) {
|
||||
if (entity.getValidEndTime().before(entity.getValidStartTime())) {
|
||||
throw new ServiceException("有效结束时间不能早于开始时间");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验优惠券类型和对应字段
|
||||
*/
|
||||
private void validateCouponType(MallCoupon entity) {
|
||||
if (entity.getType() == null) {
|
||||
return;
|
||||
}
|
||||
// 0-满减,1-折扣,2-现金
|
||||
if (entity.getType() == 0) {
|
||||
// 满减类型必须设置优惠金额
|
||||
if (entity.getDiscountAmount() == null || entity.getDiscountAmount() <= 0) {
|
||||
throw new ServiceException("满减类型优惠券必须设置优惠金额");
|
||||
}
|
||||
} else if (entity.getType() == 1) {
|
||||
// 折扣类型必须设置折扣率
|
||||
if (entity.getDiscountRate() == null || entity.getDiscountRate().compareTo(java.math.BigDecimal.ZERO) <= 0) {
|
||||
throw new ServiceException("折扣类型优惠券必须设置折扣率");
|
||||
}
|
||||
if (entity.getDiscountRate().compareTo(new java.math.BigDecimal("100")) > 0) {
|
||||
throw new ServiceException("折扣率不能大于100%");
|
||||
}
|
||||
} else if (entity.getType() == 2) {
|
||||
// 现金类型必须设置优惠金额
|
||||
if (entity.getDiscountAmount() == null || entity.getDiscountAmount() <= 0) {
|
||||
throw new ServiceException("现金类型优惠券必须设置优惠金额");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除优惠券
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// 可以添加业务校验逻辑,如:已使用数量大于0的优惠券不能删除
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用/禁用优惠券
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean changeStatus(Long id, Integer status) {
|
||||
MallCoupon coupon = baseMapper.selectById(id);
|
||||
if (coupon == null) {
|
||||
throw new ServiceException("优惠券不存在");
|
||||
}
|
||||
if (status != 0 && status != 1) {
|
||||
throw new ServiceException("状态值不正确");
|
||||
}
|
||||
coupon.setStatus(status);
|
||||
return baseMapper.updateById(coupon) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取优惠券统计信息
|
||||
*/
|
||||
@Override
|
||||
public CouponStatisticsVo getStatistics(Long couponId) {
|
||||
CouponStatisticsVo vo = new CouponStatisticsVo();
|
||||
vo.setCouponId(couponId);
|
||||
|
||||
// 如果指定了优惠券ID,获取优惠券信息
|
||||
if (couponId != null) {
|
||||
MallCouponVo couponVo = baseMapper.selectVoById(couponId);
|
||||
if (couponVo != null) {
|
||||
vo.setCouponName(couponVo.getName());
|
||||
}
|
||||
}
|
||||
|
||||
// 统计发放数量(已领取数量,即mall_coupon_user表中的总记录数)
|
||||
LambdaQueryWrapper<MallCouponUser> issuedWrapper = new LambdaQueryWrapper<>();
|
||||
if (couponId != null) {
|
||||
issuedWrapper.eq(MallCouponUser::getCouponId, couponId);
|
||||
}
|
||||
Long issuedCount = couponUserMapper.selectCount(issuedWrapper);
|
||||
vo.setIssuedCount(issuedCount != null ? issuedCount : 0L);
|
||||
|
||||
// 统计使用数量(status=1的记录数)
|
||||
LambdaQueryWrapper<MallCouponUser> usedWrapper = new LambdaQueryWrapper<>();
|
||||
if (couponId != null) {
|
||||
usedWrapper.eq(MallCouponUser::getCouponId, couponId);
|
||||
}
|
||||
usedWrapper.eq(MallCouponUser::getStatus, 1); // 已使用
|
||||
Long usedCount = couponUserMapper.selectCount(usedWrapper);
|
||||
vo.setUsedCount(usedCount != null ? usedCount : 0L);
|
||||
|
||||
// 计算使用率
|
||||
if (vo.getIssuedCount() > 0) {
|
||||
double usageRate = (double) vo.getUsedCount() / vo.getIssuedCount() * 100;
|
||||
vo.setUsageRate(Math.round(usageRate * 100.0) / 100.0);
|
||||
} else {
|
||||
vo.setUsageRate(0.0);
|
||||
}
|
||||
|
||||
// 核销金额统计(基于mall_order_coupon表,需要在交易中心模块查询)
|
||||
// 由于跨模块依赖问题,这里暂时设为0
|
||||
// 如果需要在优惠券模块直接查询,可以考虑通过Feign调用交易中心模块的接口,或者将统计功能放在交易中心模块
|
||||
// 当前实现:如果交易中心模块已实现订单优惠券记录,可以通过依赖注入MallOrderCouponService来查询
|
||||
// TODO: 考虑通过服务间调用或事件机制来获取核销金额统计
|
||||
vo.setRedeemedAmount(0L);
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
}
|
||||
+296
@@ -0,0 +1,296 @@
|
||||
package org.dromara.mall.coupon.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.mall.coupon.domain.MallCoupon;
|
||||
import org.dromara.mall.coupon.domain.MallCouponUser;
|
||||
import org.dromara.mall.coupon.domain.bo.MallCouponUserBo;
|
||||
import org.dromara.mall.coupon.domain.vo.MallCouponUserVo;
|
||||
import org.dromara.mall.coupon.domain.vo.MallCouponVo;
|
||||
import org.dromara.mall.coupon.mapper.MallCouponMapper;
|
||||
import org.dromara.mall.coupon.mapper.MallCouponUserMapper;
|
||||
import org.dromara.mall.coupon.service.MallCouponUserService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 用户优惠券Service业务层处理
|
||||
*
|
||||
* @author pengles
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class MallCouponUserServiceImpl implements MallCouponUserService {
|
||||
|
||||
private final MallCouponUserMapper baseMapper;
|
||||
private final MallCouponMapper couponMapper;
|
||||
|
||||
/**
|
||||
* 查询用户优惠券
|
||||
*/
|
||||
@Override
|
||||
public MallCouponUserVo queryById(Long id) {
|
||||
MallCouponUserVo vo = baseMapper.selectVoById(id);
|
||||
if (vo != null && vo.getCouponId() != null) {
|
||||
// 关联查询优惠券信息
|
||||
MallCouponVo couponVo = couponMapper.selectVoById(vo.getCouponId());
|
||||
vo.setCouponInfo(couponVo);
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户优惠券列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<MallCouponUserVo> queryPageList(MallCouponUserBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<MallCouponUser> lqw = buildQueryWrapper(bo);
|
||||
Page<MallCouponUserVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
|
||||
// 关联查询优惠券信息
|
||||
fillCouponInfo(result.getRecords());
|
||||
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户优惠券列表
|
||||
*/
|
||||
@Override
|
||||
public List<MallCouponUserVo> queryList(MallCouponUserBo bo) {
|
||||
LambdaQueryWrapper<MallCouponUser> lqw = buildQueryWrapper(bo);
|
||||
List<MallCouponUserVo> list = baseMapper.selectVoList(lqw);
|
||||
|
||||
// 关联查询优惠券信息
|
||||
fillCouponInfo(list);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户可用优惠券列表
|
||||
*/
|
||||
@Override
|
||||
public List<MallCouponUserVo> queryAvailableList(Long userId) {
|
||||
LambdaQueryWrapper<MallCouponUser> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(MallCouponUser::getUserId, userId);
|
||||
lqw.eq(MallCouponUser::getStatus, 0); // 未使用
|
||||
lqw.orderByDesc(MallCouponUser::getCreateTime);
|
||||
|
||||
List<MallCouponUserVo> list = baseMapper.selectVoList(lqw);
|
||||
|
||||
// 过滤已过期的优惠券
|
||||
Date now = new Date();
|
||||
list = list.stream().filter(vo -> {
|
||||
if (vo.getCouponId() == null) {
|
||||
return false;
|
||||
}
|
||||
MallCouponVo couponVo = couponMapper.selectVoById(vo.getCouponId());
|
||||
if (couponVo == null || couponVo.getStatus() != 0) {
|
||||
return false;
|
||||
}
|
||||
return couponVo.getValidEndTime() != null && couponVo.getValidEndTime().after(now);
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// 关联查询优惠券信息
|
||||
fillCouponInfo(list);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充优惠券信息
|
||||
*/
|
||||
private void fillCouponInfo(List<MallCouponUserVo> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (MallCouponUserVo vo : list) {
|
||||
if (vo.getCouponId() != null) {
|
||||
MallCouponVo couponVo = couponMapper.selectVoById(vo.getCouponId());
|
||||
vo.setCouponInfo(couponVo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<MallCouponUser> buildQueryWrapper(MallCouponUserBo bo) {
|
||||
LambdaQueryWrapper<MallCouponUser> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(bo.getUserId() != null, MallCouponUser::getUserId, bo.getUserId());
|
||||
lqw.eq(bo.getCouponId() != null, MallCouponUser::getCouponId, bo.getCouponId());
|
||||
lqw.eq(bo.getStatus() != null, MallCouponUser::getStatus, bo.getStatus());
|
||||
lqw.orderByDesc(MallCouponUser::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户领取优惠券
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean receiveCoupon(Long couponId) {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
|
||||
// 查询优惠券信息
|
||||
MallCoupon coupon = couponMapper.selectById(couponId);
|
||||
if (coupon == null) {
|
||||
throw new ServiceException("优惠券不存在");
|
||||
}
|
||||
if (coupon.getStatus() != 0) {
|
||||
throw new ServiceException("优惠券已禁用");
|
||||
}
|
||||
|
||||
// 校验有效期
|
||||
Date now = new Date();
|
||||
if (coupon.getValidStartTime().after(now) || coupon.getValidEndTime().before(now)) {
|
||||
throw new ServiceException("优惠券不在有效期内");
|
||||
}
|
||||
|
||||
// 校验发放数量
|
||||
if (coupon.getTotalCount() != null) {
|
||||
if (coupon.getUsedCount() >= coupon.getTotalCount()) {
|
||||
throw new ServiceException("优惠券已发放完毕");
|
||||
}
|
||||
}
|
||||
|
||||
// 校验每人限领数量
|
||||
LambdaQueryWrapper<MallCouponUser> countWrapper = new LambdaQueryWrapper<>();
|
||||
countWrapper.eq(MallCouponUser::getUserId, userId);
|
||||
countWrapper.eq(MallCouponUser::getCouponId, couponId);
|
||||
Long receivedCount = baseMapper.selectCount(countWrapper);
|
||||
if (receivedCount >= coupon.getPerLimit()) {
|
||||
throw new ServiceException("已达到每人限领数量");
|
||||
}
|
||||
|
||||
// 创建用户优惠券记录
|
||||
MallCouponUser couponUser = new MallCouponUser();
|
||||
couponUser.setUserId(userId);
|
||||
couponUser.setCouponId(couponId);
|
||||
couponUser.setStatus(0); // 未使用
|
||||
couponUser.setCreateTime(now);
|
||||
|
||||
boolean flag = baseMapper.insert(couponUser) > 0;
|
||||
|
||||
if (flag) {
|
||||
// 更新优惠券已发放数量(注意:这里used_count实际存储的是已发放数量,不是已使用数量)
|
||||
// 如果业务需要区分,可以考虑增加字段
|
||||
LambdaUpdateWrapper<MallCoupon> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(MallCoupon::getId, couponId);
|
||||
updateWrapper.setSql("used_count = used_count + 1");
|
||||
couponMapper.update(null, updateWrapper);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用优惠券(订单结算时调用)
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean useCoupon(Long couponUserId, Long orderId) {
|
||||
MallCouponUser couponUser = baseMapper.selectById(couponUserId);
|
||||
if (couponUser == null) {
|
||||
throw new ServiceException("用户优惠券不存在");
|
||||
}
|
||||
if (couponUser.getStatus() != 0) {
|
||||
throw new ServiceException("优惠券已使用或已过期");
|
||||
}
|
||||
|
||||
// 校验优惠券是否过期
|
||||
MallCoupon coupon = couponMapper.selectById(couponUser.getCouponId());
|
||||
if (coupon == null) {
|
||||
throw new ServiceException("优惠券不存在");
|
||||
}
|
||||
Date now = new Date();
|
||||
if (coupon.getValidEndTime().before(now)) {
|
||||
throw new ServiceException("优惠券已过期");
|
||||
}
|
||||
|
||||
// 更新用户优惠券状态
|
||||
couponUser.setStatus(1); // 已使用
|
||||
couponUser.setUsedTime(now);
|
||||
couponUser.setOrderId(orderId);
|
||||
|
||||
return baseMapper.updateById(couponUser) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退还优惠券(订单取消时调用)
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean returnCoupon(Long couponUserId) {
|
||||
MallCouponUser couponUser = baseMapper.selectById(couponUserId);
|
||||
if (couponUser == null) {
|
||||
throw new ServiceException("用户优惠券不存在");
|
||||
}
|
||||
if (couponUser.getStatus() != 1) {
|
||||
throw new ServiceException("优惠券状态不正确,无法退还");
|
||||
}
|
||||
|
||||
// 校验优惠券是否过期
|
||||
MallCoupon coupon = couponMapper.selectById(couponUser.getCouponId());
|
||||
if (coupon == null) {
|
||||
throw new ServiceException("优惠券不存在");
|
||||
}
|
||||
Date now = new Date();
|
||||
if (coupon.getValidEndTime().before(now)) {
|
||||
// 已过期,状态改为已过期
|
||||
couponUser.setStatus(2);
|
||||
} else {
|
||||
// 未过期,状态改为未使用
|
||||
couponUser.setStatus(0);
|
||||
}
|
||||
couponUser.setUsedTime(null);
|
||||
couponUser.setOrderId(null);
|
||||
|
||||
return baseMapper.updateById(couponUser) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除用户优惠券
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// 可以添加业务校验逻辑
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理过期优惠券(定时任务调用)
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processExpiredCoupons() {
|
||||
Date now = new Date();
|
||||
|
||||
// 查询所有未使用的用户优惠券
|
||||
LambdaQueryWrapper<MallCouponUser> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(MallCouponUser::getStatus, 0); // 未使用
|
||||
List<MallCouponUser> list = baseMapper.selectList(lqw);
|
||||
|
||||
for (MallCouponUser couponUser : list) {
|
||||
MallCoupon coupon = couponMapper.selectById(couponUser.getCouponId());
|
||||
if (coupon != null && coupon.getValidEndTime().before(now)) {
|
||||
// 优惠券已过期,更新状态
|
||||
couponUser.setStatus(2); // 已过期
|
||||
baseMapper.updateById(couponUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
# Auto Configure
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.dromara.mall.coupon.config.MallCouponAutoConfiguration
|
||||
Reference in New Issue
Block a user