You've already forked FrameTour-BE
Merge branch 'refs/heads/price_inquery'
All checks were successful
ZhenTu-BE/pipeline/head This commit looks good
All checks were successful
ZhenTu-BE/pipeline/head This commit looks good
This commit is contained in:
@@ -1,90 +1,75 @@
|
||||
# 价格查询系统 (Pricing Module) 开发指南
|
||||
|
||||
此文档为pricing包的专用开发指南,提供该模块的详细架构说明和开发最佳实践。
|
||||
此文档为 pricing 包的专用开发指南,基于当前代码实际结构进行说明与示例。
|
||||
|
||||
## 模块概览
|
||||
|
||||
价格查询系统 (`com.ycwl.basic.pricing`) 是一个独立的业务模块,提供商品定价、优惠券管理、券码管理和价格计算功能。采用分层架构设计,具备完整的CRUD操作、异常处理和数据统计功能。支持优惠券和券码的同时使用,券码优先级更高。
|
||||
`com.ycwl.basic.pricing` 提供商品定价、分层/套餐与一口价配置、优惠券管理、券码管理与使用记录、统一优惠检测与价格计算等能力。采用分层架构(controller/dto/entity/mapper/service),同时整合了 PageHelper 与 MyBatis‑Plus 的分页能力。优惠叠加采用统一检测与排序:券码 > 优惠券 > 一口价(受配置限制)。
|
||||
|
||||
## 目录结构
|
||||
## 目录结构(已对齐当前代码)
|
||||
|
||||
```
|
||||
com.ycwl.basic.pricing/
|
||||
├── controller/ # REST API控制器层
|
||||
│ ├── CouponManagementController.java # 优惠券管理API
|
||||
│ ├── PriceCalculationController.java # 价格计算API
|
||||
│ └── PricingConfigController.java # 价格配置管理API
|
||||
├── dto/ # 数据传输对象
|
||||
│ ├── BundleProductItem.java # 套餐商品项
|
||||
│ ├── CouponInfo.java # 优惠券信息
|
||||
│ ├── CouponUseRequest.java # 优惠券使用请求
|
||||
│ ├── CouponUseResult.java # 优惠券使用结果
|
||||
│ ├── DiscountDetail.java # 折扣详情
|
||||
│ ├── PriceCalculationRequest.java # 价格计算请求
|
||||
│ ├── PriceCalculationResult.java # 价格计算结果
|
||||
│ ├── PriceDetails.java # 价格详情
|
||||
│ ├── ProductItem.java # 商品项
|
||||
│ ├── ProductPriceInfo.java # 商品价格信息
|
||||
│ ├── VoucherInfo.java # 券码信息
|
||||
│ ├── DiscountDetectionContext.java # 优惠检测上下文
|
||||
│ ├── DiscountInfo.java # 优惠信息
|
||||
│ ├── DiscountResult.java # 优惠结果
|
||||
│ └── DiscountCombinationResult.java # 优惠组合结果
|
||||
├── entity/ # 数据库实体类
|
||||
│ ├── BaseEntity.java # 基础实体类
|
||||
│ ├── PriceBundleConfig.java # 套餐配置
|
||||
│ ├── PriceCouponClaimRecord.java # 优惠券领取记录
|
||||
│ ├── PriceCouponConfig.java # 优惠券配置
|
||||
│ ├── PriceProductConfig.java # 商品价格配置
|
||||
│ ├── PriceTierConfig.java # 分层价格配置
|
||||
│ ├── PriceVoucherBatchConfig.java # 券码批次配置
|
||||
│ └── PriceVoucherCode.java # 券码实体
|
||||
├── enums/ # 枚举类
|
||||
│ ├── CouponStatus.java # 优惠券状态
|
||||
│ ├── CouponType.java # 优惠券类型
|
||||
│ ├── ProductType.java # 商品类型
|
||||
│ ├── VoucherDiscountType.java # 券码优惠类型
|
||||
│ └── VoucherCodeStatus.java # 券码状态
|
||||
├── exception/ # 异常处理
|
||||
│ ├── CouponInvalidException.java # 优惠券无效异常
|
||||
│ ├── PriceCalculationException.java # 价格计算异常
|
||||
│ ├── PricingExceptionHandler.java # 定价异常处理器
|
||||
│ ├── ProductConfigNotFoundException.java # 商品配置未找到异常
|
||||
│ ├── VoucherInvalidException.java # 券码无效异常
|
||||
│ ├── VoucherAlreadyUsedException.java # 券码已使用异常
|
||||
│ ├── VoucherNotClaimableException.java # 券码不可领取异常
|
||||
│ └── DiscountDetectionException.java # 优惠检测异常
|
||||
├── handler/ # 自定义处理器
|
||||
│ └── BundleProductListTypeHandler.java # 套餐商品列表类型处理器
|
||||
├── mapper/ # MyBatis数据访问层
|
||||
│ ├── PriceBundleConfigMapper.java
|
||||
│ ├── PriceCouponClaimRecordMapper.java
|
||||
│ ├── PriceCouponConfigMapper.java
|
||||
│ ├── PriceProductConfigMapper.java
|
||||
│ ├── PriceTierConfigMapper.java
|
||||
│ ├── PriceVoucherBatchConfigMapper.java
|
||||
│ └── PriceVoucherCodeMapper.java
|
||||
└── service/ # 业务逻辑层
|
||||
├── ICouponManagementService.java # 优惠券管理服务接口
|
||||
├── ICouponService.java # 优惠券服务接口
|
||||
├── IPriceBundleService.java # 套餐服务接口
|
||||
├── IPriceCalculationService.java # 价格计算服务接口
|
||||
├── IPricingManagementService.java # 定价管理服务接口
|
||||
├── IProductConfigService.java # 商品配置服务接口
|
||||
├── IVoucherService.java # 券码服务接口
|
||||
├── IDiscountProvider.java # 优惠提供者接口
|
||||
├── IDiscountDetectionService.java # 优惠检测服务接口
|
||||
└── impl/ # 服务实现类
|
||||
├── CouponManagementServiceImpl.java
|
||||
├── CouponServiceImpl.java
|
||||
├── PriceBundleServiceImpl.java
|
||||
├── PriceCalculationServiceImpl.java
|
||||
├── PricingManagementServiceImpl.java
|
||||
├── ProductConfigServiceImpl.java
|
||||
├── VoucherServiceImpl.java
|
||||
├── CouponDiscountProvider.java
|
||||
├── VoucherDiscountProvider.java
|
||||
└── DiscountDetectionServiceImpl.java
|
||||
├── controller/ # REST API 控制器层
|
||||
│ ├── PriceCalculationController.java # 价格计算 + 用户可用券查询
|
||||
│ ├── PricingConfigController.java # 产品/阶梯/套餐(一口价)配置管理(含 admin 查询)
|
||||
│ ├── CouponManagementController.java # 优惠券配置/领取记录/统计(admin)
|
||||
│ ├── OnePricePurchaseController.java # 一口价配置管理(admin)
|
||||
│ ├── VoucherManagementController.java # 券码批次/券码/移动端领取与查询
|
||||
│ └── VoucherUsageController.java # 券码使用记录与统计查询
|
||||
├── dto/ # 数据传输对象
|
||||
│ ├── PriceCalculationRequest.java # 价格计算请求(含voucherCode/faceId/scenicId...)
|
||||
│ ├── PriceCalculationResult.java # 价格计算结果(含usedCoupon/usedVoucher/availableDiscounts)
|
||||
│ ├── ProductItem.java, ProductPriceInfo.java, PriceDetails.java
|
||||
│ ├── DiscountDetectionContext.java, DiscountInfo.java, DiscountDetail.java,
|
||||
│ │ DiscountResult.java, DiscountCombinationResult.java
|
||||
│ ├── BundleProductItem.java, MobilePriceCalculationRequest.java
|
||||
│ ├── OnePriceConfigRequest.java, OnePriceInfo.java
|
||||
│ ├── req/ # 券码管理请求DTO
|
||||
│ │ ├── VoucherBatchCreateReq(.java|V2)
|
||||
│ │ ├── VoucherBatchQueryReq.java, VoucherCodeQueryReq.java, VoucherClaimReq.java
|
||||
│ │ └── VoucherUsageHistoryReq.java
|
||||
│ └── resp/ # 券码管理响应DTO
|
||||
│ ├── VoucherBatchResp.java, VoucherBatchStatsResp.java
|
||||
│ ├── VoucherCodeResp.java, VoucherValidationResp.java
|
||||
│ ├── VoucherUsageRecordResp.java, VoucherUsageStatsResp.java, VoucherUsageSummaryResp.java
|
||||
│ └── VoucherPrintResp.java
|
||||
├── entity/ # 数据库实体类(MyBatis‑Plus)
|
||||
│ ├── PriceProductConfig.java, PriceTierConfig.java, PriceBundleConfig.java
|
||||
│ ├── PriceCouponConfig.java, PriceCouponClaimRecord.java
|
||||
│ ├── PriceVoucherBatchConfig.java, PriceVoucherCode.java, PriceVoucherUsageRecord.java
|
||||
│ ├── PriceOnePriceConfig.java # 一口价配置
|
||||
│ └── VoucherPrintRecord.java # 券码打印记录
|
||||
├── enums/ # 枚举类
|
||||
│ ├── ProductType.java, CouponType.java, CouponStatus.java
|
||||
│ ├── VoucherDiscountType.java, VoucherCodeStatus.java
|
||||
├── exception/ # 统一异常与业务异常
|
||||
│ ├── PricingExceptionHandler.java, PriceCalculationException.java
|
||||
│ ├── ProductConfigNotFoundException.java, DiscountDetectionException.java
|
||||
│ ├── CouponInvalidException.java, VoucherInvalidException.java,
|
||||
│ ├── VoucherAlreadyUsedException.java, VoucherNotClaimableException.java
|
||||
├── handler/ # MyBatis 类型处理器
|
||||
│ ├── BundleProductListTypeHandler.java # 套餐商品列表 JSON ↔ 对象列表
|
||||
│ └── ProductTypeListTypeHandler.java # 商品类型列表 JSON ↔ 枚举列表
|
||||
├── mapper/ # 数据访问接口(多为 MyBatis‑Plus Mapper)
|
||||
│ ├── PriceProductConfigMapper.java, PriceTierConfigMapper.java, PriceBundleConfigMapper.java
|
||||
│ ├── PriceCouponConfigMapper.java, PriceCouponClaimRecordMapper.java
|
||||
│ ├── PriceVoucherBatchConfigMapper.java, PriceVoucherCodeMapper.java, PriceVoucherUsageRecordMapper.java
|
||||
│ └── PriceOnePriceConfigMapper.java, VoucherPrintRecordMapper.java
|
||||
└── service/ # 业务层接口与实现
|
||||
├── IPriceCalculationService.java, IDiscountDetectionService.java, IDiscountProvider.java
|
||||
├── IProductConfigService.java, IPricingManagementService.java, IPriceBundleService.java
|
||||
├── ICouponService.java, ICouponManagementService.java
|
||||
├── IOnePricePurchaseService.java, IVoucherService.java, IVoucherUsageService.java
|
||||
├── VoucherBatchService.java, VoucherCodeService.java, VoucherPrintService.java
|
||||
└── impl/
|
||||
├── PriceCalculationServiceImpl.java, DiscountDetectionServiceImpl.java
|
||||
├── ProductConfigServiceImpl.java, PricingManagementServiceImpl.java, PriceBundleServiceImpl.java
|
||||
├── CouponServiceImpl.java, CouponManagementServiceImpl.java, CouponDiscountProvider.java
|
||||
├── VoucherServiceImpl.java, VoucherDiscountProvider.java,
|
||||
├── VoucherBatchServiceImpl.java, VoucherCodeServiceImpl.java, VoucherPrintServiceImpl.java,
|
||||
├── VoucherUsageServiceImpl.java,
|
||||
└── OnePricePurchaseServiceImpl.java, OnePricePurchaseDiscountProvider.java
|
||||
```
|
||||
|
||||
## 核心功能
|
||||
@@ -92,94 +77,91 @@ com.ycwl.basic.pricing/
|
||||
### 1. 价格计算引擎
|
||||
|
||||
#### API端点
|
||||
- `POST /api/pricing/calculate` - 执行价格计算
|
||||
- `POST /api/pricing/calculate` — 执行价格计算(预览模式默认开启)
|
||||
- `GET /api/pricing/coupons/my-coupons` — 查询用户可用优惠券
|
||||
|
||||
#### 计算流程
|
||||
```java
|
||||
// 价格计算核心流程
|
||||
1. 验证PriceCalculationRequest请求参数
|
||||
2. 加载商品基础配置 (PriceProductConfig)
|
||||
3. 应用分层定价规则 (PriceTierConfig)
|
||||
4. 处理套餐商品逻辑 (BundleProductItem)
|
||||
5. 使用统一优惠检测系统处理券码和优惠券
|
||||
6. 按优先级应用优惠:券码 > 优惠券
|
||||
7. 计算最终价格并返回详细结果
|
||||
// 价格计算核心流程(IPriceCalculationService / PriceCalculationServiceImpl)
|
||||
1. 校验 PriceCalculationRequest(包含 voucherCode / scenicId / faceId / autoUseXXX)
|
||||
2. 加载商品基础配置 (PriceProductConfig),匹配分层规则 (PriceTierConfig)、套餐等
|
||||
3. 构造 DiscountDetectionContext,统一检测可用优惠(券码/优惠券/一口价)
|
||||
4. 按优先级与可叠加规则应用优惠:券码 > 优惠券 > 一口价(受 canUseCoupon/canUseVoucher 控制)
|
||||
5. 汇总 DiscountDetail,计算 finalAmount / discountAmount 并返回 PriceCalculationResult
|
||||
```
|
||||
|
||||
#### 关键类
|
||||
- `PriceCalculationService`: 价格计算核心逻辑
|
||||
- `IPriceCalculationService` / `PriceCalculationServiceImpl`: 价格计算核心逻辑
|
||||
- `PriceCalculationRequest`: 计算请求DTO
|
||||
- `PriceCalculationResult`: 计算结果DTO
|
||||
- `IDiscountDetectionService`: 统一优惠检测与组合
|
||||
|
||||
### 2. 优惠券管理系统
|
||||
|
||||
#### API端点
|
||||
- `GET /api/pricing/admin/coupons/` - 分页查询优惠券配置
|
||||
- `POST /api/pricing/admin/coupons/` - 创建优惠券配置
|
||||
- `PUT /api/pricing/admin/coupons/{id}` - 更新优惠券配置
|
||||
- `DELETE /api/pricing/admin/coupons/{id}` - 删除优惠券配置
|
||||
- `GET /api/pricing/admin/coupons/{id}/claims` - 查询优惠券领取记录
|
||||
- `GET /api/pricing/admin/coupons/{id}/stats` - 获取优惠券统计信息
|
||||
#### API端点(管理端,见 `CouponManagementController`)
|
||||
- `POST /api/pricing/admin/coupons/configs` — 创建配置
|
||||
- `PUT /api/pricing/admin/coupons/configs/{id}` — 更新配置
|
||||
- `DELETE /api/pricing/admin/coupons/configs/{id}` — 删除配置
|
||||
- `PUT /api/pricing/admin/coupons/configs/{id}/status` — 启用/禁用
|
||||
- `GET /api/pricing/admin/coupons/configs` — 全量配置(含禁用)
|
||||
- `GET /api/pricing/admin/coupons/configs/page` — 分页查询
|
||||
- `GET /api/pricing/admin/coupons/claim-records[/*]` — 领取记录列表/分页/按条件查询
|
||||
- `GET /api/pricing/admin/coupons/stats/{couponId}[/*]` — 使用统计/明细/概览
|
||||
|
||||
#### 优惠券类型
|
||||
#### 枚举定义(简述)
|
||||
```java
|
||||
public enum CouponType {
|
||||
PERCENTAGE, // 百分比折扣
|
||||
FIXED_AMOUNT // 固定金额减免
|
||||
}
|
||||
|
||||
public enum CouponStatus {
|
||||
CLAIMED, // 已领取
|
||||
USED, // 已使用
|
||||
EXPIRED // 已过期
|
||||
}
|
||||
// 实际枚举包含 code/description 字段,并提供 fromCode 工具方法
|
||||
public enum CouponType { PERCENTAGE("percentage", ...), FIXED_AMOUNT("fixed_amount", ...) }
|
||||
public enum CouponStatus { CLAIMED("claimed", ...), USED("used", ...), EXPIRED("expired", ...) }
|
||||
```
|
||||
|
||||
#### 关键特性
|
||||
- **商品类型限制**: 通过`applicableProducts` JSON字段控制适用商品
|
||||
- **消费限制**: 支持最小消费金额和最大折扣限制
|
||||
- **时效性**: 基于时间的有效期控制
|
||||
- **统计分析**: 完整的使用统计和分析功能
|
||||
- 商品类型限制:通过 JSON 字段(结合 `ProductTypeListTypeHandler`)控制适用商品
|
||||
- 消费限制:支持最小消费金额、最大折扣限制
|
||||
- 时效性:基于时间的有效期控制
|
||||
- 统计分析:完整的使用统计与分析能力
|
||||
|
||||
### 3. 商品配置管理
|
||||
|
||||
#### API端点
|
||||
- `GET /api/pricing/config/products` - 查询商品配置
|
||||
- `POST /api/pricing/config/products` - 创建商品配置
|
||||
- `PUT /api/pricing/config/products/{id}` - 更新商品配置
|
||||
#### API端点(摘)
|
||||
- `GET /api/pricing/config/products` — 查询商品配置
|
||||
- `POST /api/pricing/config/products` — 创建商品配置
|
||||
- `PUT /api/pricing/config/products/{id}` — 更新商品配置
|
||||
- `GET /api/pricing/config/tiers[/*]`、`/bundles[/*]` — 阶梯/一口价配置查询
|
||||
|
||||
#### 商品类型定义
|
||||
#### 商品类型定义(对齐实际)
|
||||
```java
|
||||
// 实际定义(带 code/description,并提供 fromCode):
|
||||
public enum ProductType {
|
||||
VLOG_VIDEO("vlog_video", "Vlog视频"),
|
||||
RECORDING_SET("recording_set", "录像集"),
|
||||
PHOTO_SET("photo_set", "照相集"),
|
||||
PHOTO_PRINT("photo_print", "照片打印"),
|
||||
MACHINE_PRINT("machine_print", "一体机打印");
|
||||
VLOG_VIDEO("VLOG_VIDEO", "Vlog视频"),
|
||||
RECORDING_SET("RECORDING_SET", "录像集"),
|
||||
PHOTO_SET("PHOTO_SET", "照相集"),
|
||||
PHOTO_PRINT("PHOTO_PRINT", "照片打印"),
|
||||
MACHINE_PRINT("MACHINE_PRINT", "一体机打印");
|
||||
}
|
||||
```
|
||||
|
||||
#### 分层定价
|
||||
支持基于数量的分层定价策略,通过`PriceTierConfig`实体配置不同数量区间的单价。
|
||||
支持基于数量的分层定价策略,通过 `PriceTierConfig` 配置不同数量区间的单价。
|
||||
|
||||
## 开发最佳实践
|
||||
|
||||
### 1. 添加新商品类型
|
||||
|
||||
```java
|
||||
// 步骤1: 在ProductType枚举中添加新类型
|
||||
// 步骤1: 在 ProductType 枚举中添加新类型(含 code/description)
|
||||
public enum ProductType {
|
||||
// 现有类型...
|
||||
NEW_PRODUCT("new_product", "新商品类型");
|
||||
NEW_PRODUCT("NEW_PRODUCT", "新商品类型");
|
||||
}
|
||||
|
||||
// 步骤2: 在数据库中添加default配置
|
||||
// 步骤2: 在数据库中添加 default 配置
|
||||
INSERT INTO price_product_config (product_type, base_price, ...)
|
||||
VALUES ('new_product', 100.00, ...);
|
||||
VALUES ('NEW_PRODUCT', 100.00, ...);
|
||||
|
||||
// 步骤3: 添加分层定价配置(可选)
|
||||
INSERT INTO price_tier_config (product_type, min_quantity, max_quantity, unit_price, ...)
|
||||
VALUES ('new_product', 1, 10, 95.00, ...);
|
||||
VALUES ('NEW_PRODUCT', 1, 10, 95.00, ...);
|
||||
|
||||
// 步骤4: 更新前端产品类型映射
|
||||
```
|
||||
@@ -187,14 +169,14 @@ VALUES ('new_product', 1, 10, 95.00, ...);
|
||||
### 2. 扩展优惠券类型
|
||||
|
||||
```java
|
||||
// 步骤1: 在CouponType枚举中添加新类型
|
||||
// 步骤1: 在 CouponType 中添加新类型
|
||||
public enum CouponType {
|
||||
PERCENTAGE,
|
||||
FIXED_AMOUNT,
|
||||
NEW_COUPON_TYPE // 新增类型
|
||||
}
|
||||
|
||||
// 步骤2: 在CouponServiceImpl中实现计算逻辑
|
||||
// 步骤2: 在 CouponServiceImpl 中实现计算逻辑
|
||||
@Override
|
||||
public BigDecimal calculateDiscount(CouponConfig coupon, BigDecimal originalPrice) {
|
||||
return switch (coupon.getCouponType()) {
|
||||
@@ -204,19 +186,17 @@ public BigDecimal calculateDiscount(CouponConfig coupon, BigDecimal originalPric
|
||||
};
|
||||
}
|
||||
|
||||
// 步骤3: 更新applicableProducts验证规则
|
||||
// 步骤3: 更新 applicableProducts 验证规则(如有)
|
||||
```
|
||||
|
||||
### 3. 自定义TypeHandler使用
|
||||
|
||||
项目使用MyBatis自定义TypeHandler处理复杂JSON字段:
|
||||
### 3. 自定义 TypeHandler 使用
|
||||
|
||||
```java
|
||||
// BundleProductListTypeHandler处理套餐商品列表
|
||||
// BundleProductListTypeHandler 处理套餐商品列表
|
||||
@MappedTypes(List.class)
|
||||
@MappedJdbcTypes(JdbcType.VARCHAR)
|
||||
public class BundleProductListTypeHandler extends BaseTypeHandler<List<BundleProductItem>> {
|
||||
// JSON序列化/反序列化逻辑
|
||||
// JSON 序列化/反序列化逻辑
|
||||
}
|
||||
|
||||
// 在实体类中使用
|
||||
@@ -224,6 +204,9 @@ public class SomeEntity {
|
||||
@TableField(typeHandler = BundleProductListTypeHandler.class)
|
||||
private List<BundleProductItem> bundleProducts;
|
||||
}
|
||||
|
||||
// ProductTypeListTypeHandler 处理商品类型列表(券码可用商品类型)
|
||||
public class ProductTypeListTypeHandler extends BaseTypeHandler<List<ProductType>> { /* ... */ }
|
||||
```
|
||||
|
||||
### 4. 异常处理模式
|
||||
@@ -231,12 +214,10 @@ public class SomeEntity {
|
||||
```java
|
||||
// 自定义异常类
|
||||
public class PriceCalculationException extends RuntimeException {
|
||||
public PriceCalculationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
public PriceCalculationException(String message) { super(message); }
|
||||
}
|
||||
|
||||
// 在PricingExceptionHandler中统一处理
|
||||
// 在 PricingExceptionHandler 中统一处理
|
||||
@ExceptionHandler(PriceCalculationException.class)
|
||||
public ApiResponse<String> handlePriceCalculationException(PriceCalculationException e) {
|
||||
return ApiResponse.fail(ErrorCode.PRICE_CALCULATION_ERROR, e.getMessage());
|
||||
@@ -245,107 +226,39 @@ public ApiResponse<String> handlePriceCalculationException(PriceCalculationExcep
|
||||
|
||||
### 5. 分页查询实现
|
||||
|
||||
```java
|
||||
// 使用PageHelper实现分页
|
||||
```
|
||||
// 使用 PageHelper 实现分页(优惠券相关)
|
||||
@Override
|
||||
public PageInfo<CouponConfig> getCouponsByPage(int pageNum, int pageSize, String status, String name) {
|
||||
PageHelper.startPage(pageNum, pageSize);
|
||||
|
||||
QueryWrapper<CouponConfig> queryWrapper = new QueryWrapper<>();
|
||||
if (StringUtils.hasText(status)) {
|
||||
queryWrapper.eq("status", status);
|
||||
}
|
||||
if (StringUtils.hasText(name)) {
|
||||
queryWrapper.like("name", name);
|
||||
}
|
||||
|
||||
List<CouponConfig> list = couponConfigMapper.selectList(queryWrapper);
|
||||
return new PageInfo<>(list);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 1. 单元测试
|
||||
每个服务类都应有对应的测试类,重点测试:
|
||||
- 价格计算逻辑的准确性
|
||||
- 优惠券适用性验证
|
||||
- 边界条件处理
|
||||
- 异常场景覆盖
|
||||
|
||||
### 2. 集成测试
|
||||
- 数据库操作测试
|
||||
- JSON序列化测试
|
||||
- 分页功能测试
|
||||
- API端点测试
|
||||
|
||||
### 3. 配置验证测试
|
||||
- `DefaultConfigValidationTest`: 验证default配置的完整性和正确性
|
||||
- 确保所有ProductType都有对应的基础配置
|
||||
|
||||
## 数据库设计
|
||||
|
||||
### 核心表结构
|
||||
- `price_product_config`: 商品价格基础配置
|
||||
- `price_tier_config`: 分层定价配置
|
||||
- `price_bundle_config`: 套餐配置
|
||||
- `price_coupon_config`: 优惠券配置
|
||||
- `price_coupon_claim_record`: 优惠券领取记录
|
||||
|
||||
### 关键字段设计
|
||||
- JSON字段处理: `applicable_products`使用JSON存储适用商品类型列表
|
||||
- 时间字段: 统一使用`LocalDateTime`类型
|
||||
- 价格字段: 使用`BigDecimal`确保精度
|
||||
- 状态字段: 使用枚举类型确保数据一致性
|
||||
|
||||
## 性能优化建议
|
||||
|
||||
1. **数据库查询优化**
|
||||
- 为常用查询字段添加索引
|
||||
- 使用分页查询避免大量数据加载
|
||||
- 优化复杂的JOIN查询
|
||||
|
||||
2. **缓存策略**
|
||||
- 对商品配置进行缓存,减少数据库访问
|
||||
- 使用Redis缓存热点优惠券信息
|
||||
|
||||
3. **计算性能**
|
||||
- 价格计算使用BigDecimal确保精度
|
||||
- 批量计算时考虑并行处理
|
||||
|
||||
## 安全考虑
|
||||
|
||||
1. **输入验证**
|
||||
- 严格验证所有输入参数
|
||||
- 防止SQL注入和XSS攻击
|
||||
|
||||
2. **权限控制**
|
||||
- 管理接口需要适当的权限验证
|
||||
- 用户只能访问自己的优惠券记录
|
||||
|
||||
3. **数据完整性**
|
||||
- 使用事务确保数据一致性
|
||||
- 关键操作添加审计日志
|
||||
```
|
||||
// 使用 MyBatis‑Plus 的 Page(券码相关)
|
||||
Page<VoucherBatchResp> page = voucherBatchService.queryBatchList(req);
|
||||
Page<VoucherCodeResp> page = voucherCodeService.queryCodeList(req);
|
||||
```
|
||||
|
||||
## 券码管理系统 (Voucher System)
|
||||
|
||||
### 1. 核心特性
|
||||
|
||||
券码系统是从原`voucher`包迁移而来,现已完全集成到pricing包中,与优惠券系统并行工作。
|
||||
券码系统由原独立模块迁移并完全集成到 pricing 包中,与优惠券系统并行工作。
|
||||
|
||||
#### 券码优惠类型
|
||||
#### 券码优惠类型(简述)
|
||||
```java
|
||||
public enum VoucherDiscountType {
|
||||
FREE_ALL(0, "全场免费"), // 所有商品免费,优先级最高且不可叠加
|
||||
FREE_ALL(0, "全场免费"), // 优先级最高,且不可叠加
|
||||
REDUCE_PRICE(1, "商品降价"), // 每个商品减免固定金额
|
||||
DISCOUNT(2, "商品打折") // 每个商品按百分比打折
|
||||
DISCOUNT(2, "商品打折"); // 每个商品按百分比打折
|
||||
}
|
||||
```
|
||||
|
||||
#### 券码状态流转
|
||||
#### 券码状态(简述)
|
||||
```
|
||||
UNCLAIMED(0) → CLAIMED_UNUSED(1) → USED(2)
|
||||
未领取 → 已领取未使用 → 已使用
|
||||
UNCLAIMED(0) → CLAIMED_AVAILABLE/CLAIMED_UNUSED(1) → USED(2) → CLAIMED_EXHAUSTED(3) → EXPIRED(4)
|
||||
```
|
||||
|
||||
### 2. 数据库表结构
|
||||
@@ -360,15 +273,38 @@ UNCLAIMED(0) → CLAIMED_UNUSED(1) → USED(2)
|
||||
- 用户限制:同一用户在同一景区只能领取一次券码
|
||||
- 时间追踪:记录领取时间、使用时间
|
||||
|
||||
### 3. 关键业务规则
|
||||
### 3. API 概览(对齐当前控制器)
|
||||
|
||||
管理端/服务端:`VoucherManagementController`
|
||||
- `POST /api/pricing/voucher/batch/create`、`/batch/create/v2` — 创建券码批次
|
||||
- `POST /api/pricing/voucher/batch/list` — 批次分页列表
|
||||
- `GET /api/pricing/voucher/batch/{id}` — 批次详情
|
||||
- `GET /api/pricing/voucher/batch/{id}/stats` — 批次统计
|
||||
- `PUT /api/pricing/voucher/batch/{id}/status` — 批次启用/禁用
|
||||
- `POST /api/pricing/voucher/codes` — 券码分页列表
|
||||
- `PUT /api/pricing/voucher/code/{id}/use` — 标记某券码为已使用
|
||||
- `GET /api/pricing/voucher/scenic/{scenicId}/users` — 景区用户券码概览
|
||||
|
||||
移动端:`VoucherManagementController`
|
||||
- `POST /api/pricing/voucher/mobile/claim` — 领取券码
|
||||
- `GET /api/pricing/voucher/mobile/my-codes` — 我的券码列表
|
||||
|
||||
使用记录:`VoucherUsageController`
|
||||
- `POST /api/pricing/voucher/usage/history` — 使用记录分页
|
||||
- `GET /api/pricing/voucher/usage/{voucherCode}/records` — 按券码查询记录
|
||||
- `GET /api/pricing/voucher/usage/{voucherCode}/stats` — 券码统计
|
||||
- `GET /api/pricing/voucher/usage/user/{faceId}/scenic/{scenicId}` — 用户在景区的记录
|
||||
- `GET /api/pricing/voucher/usage/batch/{batchId}/stats` — 批次使用统计
|
||||
|
||||
### 4. 关键业务规则
|
||||
|
||||
#### 领取限制
|
||||
- 同一`faceId`在同一`scenicId`中只能领取一次券码
|
||||
- 同一 `faceId` 在同一 `scenicId` 中只能领取一次券码
|
||||
- 只有启用状态的批次才能领取券码
|
||||
- 批次必须有可用券码才能成功领取
|
||||
|
||||
#### 使用验证
|
||||
- 券码必须是`CLAIMED_UNUSED`状态才能使用
|
||||
- 券码必须为可用状态(CLAIMED_AVAILABLE/CLAIMED_UNUSED)
|
||||
- 必须验证券码与景区的匹配关系
|
||||
- 使用后自动更新批次统计数据
|
||||
|
||||
@@ -376,7 +312,7 @@ UNCLAIMED(0) → CLAIMED_UNUSED(1) → USED(2)
|
||||
|
||||
### 1. 架构设计
|
||||
|
||||
采用策略模式设计的可扩展优惠检测系统,支持多种优惠类型的统一管理和自动优化组合。
|
||||
采用策略模式的可扩展优惠检测系统,统一管理并自动组合多种优惠类型。
|
||||
|
||||
#### 核心接口
|
||||
```java
|
||||
@@ -395,7 +331,7 @@ public interface IDiscountDetectionService {
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 优惠提供者实现
|
||||
### 2. 优惠提供者实现(当前实现与优先级)
|
||||
|
||||
#### VoucherDiscountProvider (优先级: 100)
|
||||
- 处理券码优惠逻辑
|
||||
@@ -407,33 +343,29 @@ public interface IDiscountDetectionService {
|
||||
- 自动选择最优优惠券
|
||||
- 可与券码叠加使用(除全场免费券码外)
|
||||
|
||||
#### OnePricePurchaseDiscountProvider (优先级: 60)
|
||||
- 处理一口价优惠逻辑(景区级统一价格)
|
||||
- 仅当一口价小于当前金额时产生优惠;是否可与券码/优惠券叠加由配置 `canUseCoupon/canUseVoucher` 决定
|
||||
|
||||
### 3. 优惠应用策略
|
||||
|
||||
#### 优先级规则
|
||||
```
|
||||
券码优惠 (Priority: 100) → 优惠券优惠 (Priority: 80)
|
||||
券码 (100) → 优惠券 (80) → 一口价 (60)
|
||||
```
|
||||
|
||||
#### 叠加逻辑
|
||||
```java
|
||||
原价 → 应用券码优惠 → 应用优惠券优惠 → 最终价格
|
||||
原价 → 券码 → 优惠券 → 一口价 → 最终价格
|
||||
|
||||
特殊情况:
|
||||
- 全场免费券码:最终价格直接为0,不再应用其他优惠
|
||||
- 其他券码类型:可与优惠券叠加使用
|
||||
- 全场免费券码:直接最终价=0,停止后续优惠
|
||||
- 一口价:可叠加性由配置 canUseCoupon / canUseVoucher 控制
|
||||
```
|
||||
|
||||
#### 显示顺序
|
||||
```
|
||||
1. 券码优惠 (sortOrder: 1)
|
||||
2. 限时立减 (sortOrder: 2)
|
||||
3. 优惠券优惠 (sortOrder: 3)
|
||||
4. 一口价优惠 (sortOrder: 4)
|
||||
```
|
||||
#### 扩展支持
|
||||
|
||||
### 4. 扩展支持
|
||||
|
||||
#### 添加新优惠类型
|
||||
##### 添加新优惠类型
|
||||
```java
|
||||
@Component
|
||||
public class FlashSaleDiscountProvider implements IDiscountProvider {
|
||||
@@ -441,23 +373,23 @@ public class FlashSaleDiscountProvider implements IDiscountProvider {
|
||||
public String getProviderType() { return "LIMITED_TIME"; }
|
||||
|
||||
@Override
|
||||
public int getPriority() { return 90; } // 介于券码和优惠券之间
|
||||
public int getPriority() { return 90; } // 示例:介于券码和优惠券之间
|
||||
|
||||
// 实现其他方法...
|
||||
}
|
||||
```
|
||||
|
||||
#### 动态注册
|
||||
##### 动态注册
|
||||
```java
|
||||
// 系统启动时自动扫描所有IDiscountProvider实现类
|
||||
// 按优先级排序并注册到DiscountDetectionService中
|
||||
// 系统启动时自动扫描所有 IDiscountProvider 实现类
|
||||
// 按优先级排序并注册到 DiscountDetectionService 中
|
||||
```
|
||||
|
||||
## API接口扩展
|
||||
## API 接口扩展
|
||||
|
||||
### 1. 价格计算接口扩展
|
||||
|
||||
#### 新增请求参数
|
||||
#### 新增请求参数(已存在)
|
||||
```java
|
||||
public class PriceCalculationRequest {
|
||||
// 原有字段...
|
||||
@@ -469,7 +401,7 @@ public class PriceCalculationRequest {
|
||||
}
|
||||
```
|
||||
|
||||
#### 新增响应字段
|
||||
#### 新增响应字段(已存在)
|
||||
```java
|
||||
public class PriceCalculationResult {
|
||||
// 原有字段...
|
||||
@@ -478,70 +410,53 @@ public class PriceCalculationResult {
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 券码管理接口
|
||||
### 2. 一口价配置管理(OnePrice)
|
||||
|
||||
#### 移动端接口
|
||||
- `POST /api/pricing/mobile/voucher/claim` - 领取券码
|
||||
- `GET /api/pricing/mobile/voucher/my-codes` - 我的券码列表
|
||||
`OnePricePurchaseController`(管理端):
|
||||
- `GET /api/pricing/admin/one-price/` — 分页查询
|
||||
- `GET /api/pricing/admin/one-price/all` — 全量查询
|
||||
- `GET /api/pricing/admin/one-price/{id}` — 详情
|
||||
- `POST /api/pricing/admin/one-price/` — 创建
|
||||
- `PUT /api/pricing/admin/one-price/{id}` — 更新
|
||||
- `DELETE /api/pricing/admin/one-price/{id}` — 删除
|
||||
- `PUT /api/pricing/admin/one-price/{id}/status` — 启用/禁用
|
||||
- `GET /api/pricing/admin/one-price/scenic/{scenicId}` — 按景区查询启用配置
|
||||
- `GET /api/pricing/admin/one-price/check/{scenicId}` — 景区是否适用一口价
|
||||
|
||||
#### 管理端接口
|
||||
- `POST /api/pricing/admin/voucher/batch/create` - 创建券码批次
|
||||
- `GET /api/pricing/admin/voucher/batch/list` - 批次列表查询
|
||||
- `GET /api/pricing/admin/voucher/codes` - 券码列表查询
|
||||
## 测试策略
|
||||
|
||||
## 开发最佳实践更新
|
||||
### 1. 单元测试
|
||||
建议覆盖:
|
||||
- 价格计算核心流程与边界
|
||||
- 优惠券/券码/一口价适用性与叠加规则
|
||||
- 异常场景与异常处理器
|
||||
|
||||
### 1. 优惠检测开发
|
||||
```java
|
||||
// 检测上下文构建
|
||||
DiscountDetectionContext context = new DiscountDetectionContext();
|
||||
context.setUserId(userId);
|
||||
context.setFaceId(faceId);
|
||||
context.setScenicId(scenicId);
|
||||
context.setProducts(products);
|
||||
context.setCurrentAmount(amount);
|
||||
context.setVoucherCode(voucherCode);
|
||||
### 2. 集成测试
|
||||
- 数据库读写与分页
|
||||
- JSON 序列化/反序列化(TypeHandler)
|
||||
- API 端点的入参/出参校验
|
||||
|
||||
// 使用统一服务检测优惠
|
||||
DiscountCombinationResult result = discountDetectionService
|
||||
.calculateOptimalCombination(context);
|
||||
```
|
||||
### 3. 配置校验
|
||||
- 校验各 ProductType 的默认配置完整性
|
||||
- 关键枚举与配置代码路径的兼容性
|
||||
|
||||
### 2. 券码服务使用
|
||||
```java
|
||||
// 验证券码
|
||||
VoucherInfo voucherInfo = voucherService.validateAndGetVoucherInfo(
|
||||
voucherCode, faceId, scenicId);
|
||||
## 数据库设计
|
||||
|
||||
// 计算券码优惠
|
||||
BigDecimal discount = voucherService.calculateVoucherDiscount(
|
||||
voucherInfo, context);
|
||||
|
||||
// 标记券码已使用
|
||||
voucherService.markVoucherAsUsed(voucherCode, "订单使用");
|
||||
```
|
||||
|
||||
### 3. 异常处理扩展
|
||||
```java
|
||||
// 券码相关异常
|
||||
try {
|
||||
// 券码操作
|
||||
} catch (VoucherInvalidException e) {
|
||||
// 券码无效
|
||||
} catch (VoucherAlreadyUsedException e) {
|
||||
// 券码已使用
|
||||
} catch (VoucherNotClaimableException e) {
|
||||
// 券码不可领取
|
||||
}
|
||||
```
|
||||
|
||||
## 数据库扩展
|
||||
### 核心表结构(摘)
|
||||
- `price_product_config`: 商品价格基础配置
|
||||
- `price_tier_config`: 分层定价配置
|
||||
- `price_bundle_config`: 套餐配置
|
||||
- `price_coupon_config`: 优惠券配置
|
||||
- `price_coupon_claim_record`: 优惠券领取记录
|
||||
|
||||
### 新增表结构
|
||||
- `price_voucher_batch_config`: 券码批次配置表
|
||||
- `price_voucher_code`: 券码表
|
||||
- `price_voucher_usage_record`: 券码使用记录表
|
||||
- `voucher_print_record`: 券码打印记录表
|
||||
- `price_one_price_config`: 一口价配置表
|
||||
|
||||
### 索引优化
|
||||
### 索引优化(示例)
|
||||
```sql
|
||||
-- 券码查询优化
|
||||
CREATE INDEX idx_voucher_code ON price_voucher_code(code);
|
||||
@@ -549,9 +464,21 @@ CREATE INDEX idx_face_scenic ON price_voucher_code(face_id, scenic_id);
|
||||
|
||||
-- 批次查询优化
|
||||
CREATE INDEX idx_scenic_broker ON price_voucher_batch_config(scenic_id, broker_id);
|
||||
|
||||
-- 使用记录与打印记录查询优化(示例)
|
||||
CREATE INDEX idx_usage_code ON price_voucher_usage_record(voucher_code);
|
||||
CREATE INDEX idx_usage_face_scenic ON price_voucher_usage_record(face_id, scenic_id);
|
||||
CREATE INDEX idx_print_face_scenic ON voucher_print_record(face_id, scenic_id);
|
||||
```
|
||||
|
||||
### 性能考虑
|
||||
- 券码表可能数据量较大,考虑按景区分表
|
||||
- 券码表可能数据量较大,考虑按景区维度分表或归档
|
||||
- 定期清理已删除的过期数据
|
||||
- 使用数据完整性检查SQL验证统计数据准确性
|
||||
- 使用数据完整性检查 SQL 验证统计数据准确性
|
||||
|
||||
## 兼容性与注意事项
|
||||
|
||||
- 本模块使用 PageHelper(优惠券相关)与 MyBatis‑Plus(券码/一口价等)并存,请根据对应 Service/Mapper 选择分页与查询方式。
|
||||
- 优惠优先级及叠加规则以各 Provider 与业务配置为准,避免在外层重复实现优先级判断逻辑。
|
||||
- 若扩展新的优惠类型,务必实现 `IDiscountProvider` 并在 `IDiscountDetectionService` 中完成注册(当前实现通过组件扫描自动注册并排序)。
|
||||
|
||||
|
@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ycwl.basic.pricing.entity.PriceVoucherBatchConfig;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -19,7 +21,12 @@ public interface PriceVoucherBatchConfigMapper extends BaseMapper<PriceVoucherBa
|
||||
* @param brokerId 推客ID
|
||||
* @return 批次列表
|
||||
*/
|
||||
List<PriceVoucherBatchConfig> selectActiveBatchesByScenicAndBroker(@Param("scenicId") Long scenicId,
|
||||
@Select("SELECT id, batch_name, scenic_id, broker_id, discount_type, discount_value, applicable_products, " +
|
||||
"total_count, used_count, claimed_count, status, create_time, update_time, " +
|
||||
"create_by, update_by, deleted, deleted_at " +
|
||||
"FROM price_voucher_batch_config WHERE scenic_id = #{scenicId} AND broker_id = #{brokerId} " +
|
||||
"AND status = 1 AND deleted = 0 ORDER BY create_time DESC")
|
||||
List<PriceVoucherBatchConfig> selectActiveBatchesByScenicAndBroker(@Param("scenicId") Long scenicId,
|
||||
@Param("brokerId") Long brokerId);
|
||||
|
||||
/**
|
||||
@@ -28,6 +35,8 @@ public interface PriceVoucherBatchConfigMapper extends BaseMapper<PriceVoucherBa
|
||||
* @param increment 增量(可为负数)
|
||||
* @return 影响行数
|
||||
*/
|
||||
@Update("UPDATE price_voucher_batch_config SET claimed_count = claimed_count + #{increment}, " +
|
||||
"update_time = NOW() WHERE id = #{batchId} AND deleted = 0")
|
||||
int updateClaimedCount(@Param("batchId") Long batchId, @Param("increment") Integer increment);
|
||||
|
||||
/**
|
||||
@@ -36,6 +45,8 @@ public interface PriceVoucherBatchConfigMapper extends BaseMapper<PriceVoucherBa
|
||||
* @param increment 增量(可为负数)
|
||||
* @return 影响行数
|
||||
*/
|
||||
@Update("UPDATE price_voucher_batch_config SET used_count = used_count + #{increment}, " +
|
||||
"update_time = NOW() WHERE id = #{batchId} AND deleted = 0")
|
||||
int updateUsedCount(@Param("batchId") Long batchId, @Param("increment") Integer increment);
|
||||
|
||||
/**
|
||||
@@ -43,6 +54,10 @@ public interface PriceVoucherBatchConfigMapper extends BaseMapper<PriceVoucherBa
|
||||
* @param batchId 批次ID
|
||||
* @return 统计信息
|
||||
*/
|
||||
@Select("SELECT id, batch_name, scenic_id, broker_id, discount_type, discount_value, applicable_products, " +
|
||||
"total_count, used_count, claimed_count, status, create_time, update_time, " +
|
||||
"create_by, update_by, deleted, deleted_at " +
|
||||
"FROM price_voucher_batch_config WHERE id = #{batchId} AND deleted = 0")
|
||||
PriceVoucherBatchConfig selectBatchStats(@Param("batchId") Long batchId);
|
||||
|
||||
/**
|
||||
@@ -50,5 +65,10 @@ public interface PriceVoucherBatchConfigMapper extends BaseMapper<PriceVoucherBa
|
||||
* @param voucherCode 券码
|
||||
* @return 券码批次配置
|
||||
*/
|
||||
@Select("SELECT b.id, b.batch_name, b.scenic_id, b.broker_id, b.discount_type, b.discount_value, b.applicable_products, " +
|
||||
"b.total_count, b.used_count, b.claimed_count, b.status, b.create_time, b.update_time, " +
|
||||
"b.create_by, b.update_by, b.deleted, b.deleted_at " +
|
||||
"FROM price_voucher_batch_config b INNER JOIN price_voucher_code c ON b.id = c.batch_id " +
|
||||
"WHERE c.code = #{voucherCode} AND b.deleted = 0 AND c.deleted = 0")
|
||||
PriceVoucherBatchConfig selectByVoucherCode(@Param("voucherCode") String voucherCode);
|
||||
}
|
@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ycwl.basic.pricing.entity.PriceVoucherCode;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
@@ -19,6 +21,9 @@ public interface PriceVoucherCodeMapper extends BaseMapper<PriceVoucherCode> {
|
||||
* @param code 券码
|
||||
* @return 券码信息
|
||||
*/
|
||||
@Select("SELECT id, batch_id, scenic_id, code, status, face_id, claimed_time, used_time, " +
|
||||
"current_use_count, last_used_time, remark, create_time, update_time, deleted, deleted_at " +
|
||||
"FROM price_voucher_code WHERE code = #{code} AND deleted = 0 LIMIT 1")
|
||||
PriceVoucherCode selectByCode(@Param("code") String code);
|
||||
|
||||
/**
|
||||
@@ -27,6 +32,7 @@ public interface PriceVoucherCodeMapper extends BaseMapper<PriceVoucherCode> {
|
||||
* @param scenicId 景区ID
|
||||
* @return 数量
|
||||
*/
|
||||
@Select("SELECT COUNT(1) FROM price_voucher_code WHERE face_id = #{faceId} AND scenic_id = #{scenicId} AND deleted = 0")
|
||||
Integer countByFaceIdAndScenicId(@Param("faceId") Long faceId, @Param("scenicId") Long scenicId);
|
||||
|
||||
/**
|
||||
@@ -35,7 +41,11 @@ public interface PriceVoucherCodeMapper extends BaseMapper<PriceVoucherCode> {
|
||||
* @param scenicId 景区ID
|
||||
* @return 券码列表
|
||||
*/
|
||||
List<PriceVoucherCode> selectAvailableVouchersByFaceIdAndScenicId(@Param("faceId") Long faceId,
|
||||
@Select("SELECT id, batch_id, scenic_id, code, status, face_id, claimed_time, used_time, " +
|
||||
"current_use_count, last_used_time, remark, create_time, update_time, deleted, deleted_at " +
|
||||
"FROM price_voucher_code WHERE face_id = #{faceId} AND scenic_id = #{scenicId} AND status = 1 AND deleted = 0 " +
|
||||
"ORDER BY claimed_time DESC")
|
||||
List<PriceVoucherCode> selectAvailableVouchersByFaceIdAndScenicId(@Param("faceId") Long faceId,
|
||||
@Param("scenicId") Long scenicId);
|
||||
|
||||
/**
|
||||
@@ -44,7 +54,10 @@ public interface PriceVoucherCodeMapper extends BaseMapper<PriceVoucherCode> {
|
||||
* @param limit 限制数量
|
||||
* @return 券码列表
|
||||
*/
|
||||
List<PriceVoucherCode> selectUnclaimedVouchersByBatchId(@Param("batchId") Long batchId,
|
||||
@Select("SELECT id, batch_id, scenic_id, code, status, face_id, claimed_time, used_time, " +
|
||||
"current_use_count, last_used_time, remark, create_time, update_time, deleted, deleted_at " +
|
||||
"FROM price_voucher_code WHERE batch_id = #{batchId} AND status = 0 AND deleted = 0 LIMIT #{limit}")
|
||||
List<PriceVoucherCode> selectUnclaimedVouchersByBatchId(@Param("batchId") Long batchId,
|
||||
@Param("limit") Integer limit);
|
||||
|
||||
/**
|
||||
@@ -54,8 +67,10 @@ public interface PriceVoucherCodeMapper extends BaseMapper<PriceVoucherCode> {
|
||||
* @param claimedTime 领取时间
|
||||
* @return 影响行数
|
||||
*/
|
||||
int claimVoucher(@Param("id") Long id,
|
||||
@Param("faceId") Long faceId,
|
||||
@Update("UPDATE price_voucher_code SET status = 1, face_id = #{faceId}, claimed_time = #{claimedTime}, " +
|
||||
"update_time = NOW() WHERE id = #{id} AND status = 0 AND deleted = 0")
|
||||
int claimVoucher(@Param("id") Long id,
|
||||
@Param("faceId") Long faceId,
|
||||
@Param("claimedTime") LocalDateTime claimedTime);
|
||||
|
||||
/**
|
||||
@@ -63,6 +78,9 @@ public interface PriceVoucherCodeMapper extends BaseMapper<PriceVoucherCode> {
|
||||
* @param batchId 批次ID
|
||||
* @return 券码列表
|
||||
*/
|
||||
@Select("SELECT id, batch_id, scenic_id, code, status, face_id, claimed_time, used_time, " +
|
||||
"current_use_count, last_used_time, remark, create_time, update_time, deleted, deleted_at " +
|
||||
"FROM price_voucher_code WHERE batch_id = #{batchId} AND deleted = 0 ORDER BY create_time DESC")
|
||||
List<PriceVoucherCode> selectByBatchId(@Param("batchId") Long batchId);
|
||||
|
||||
/**
|
||||
@@ -71,7 +89,14 @@ public interface PriceVoucherCodeMapper extends BaseMapper<PriceVoucherCode> {
|
||||
* @param scenicId 景区ID(可选)
|
||||
* @return 券码列表
|
||||
*/
|
||||
List<PriceVoucherCode> selectUserVouchers(@Param("faceId") Long faceId,
|
||||
@Select("<script>" +
|
||||
"SELECT id, batch_id, scenic_id, code, status, face_id, claimed_time, used_time, " +
|
||||
"current_use_count, last_used_time, remark, create_time, update_time, deleted, deleted_at " +
|
||||
"FROM price_voucher_code WHERE face_id = #{faceId}" +
|
||||
"<if test='scenicId != null'> AND scenic_id = #{scenicId}</if>" +
|
||||
" AND deleted = 0 ORDER BY claimed_time DESC" +
|
||||
"</script>")
|
||||
List<PriceVoucherCode> selectUserVouchers(@Param("faceId") Long faceId,
|
||||
@Param("scenicId") Long scenicId);
|
||||
|
||||
/**
|
||||
@@ -79,6 +104,9 @@ public interface PriceVoucherCodeMapper extends BaseMapper<PriceVoucherCode> {
|
||||
* @param batchId 批次ID
|
||||
* @return 可用券码
|
||||
*/
|
||||
@Select("SELECT id, batch_id, scenic_id, code, status, face_id, claimed_time, used_time, " +
|
||||
"current_use_count, last_used_time, remark, create_time, update_time, deleted, deleted_at " +
|
||||
"FROM price_voucher_code WHERE batch_id = #{batchId} AND status = 0 AND deleted = 0 LIMIT 1")
|
||||
PriceVoucherCode findFirstAvailableByBatchId(@Param("batchId") Long batchId);
|
||||
|
||||
/**
|
||||
@@ -86,5 +114,10 @@ public interface PriceVoucherCodeMapper extends BaseMapper<PriceVoucherCode> {
|
||||
* @param scenicId 景区ID
|
||||
* @return 可用券码
|
||||
*/
|
||||
@Select("SELECT pvc.id, pvc.batch_id, pvc.scenic_id, pvc.code, pvc.status, pvc.face_id, pvc.claimed_time, pvc.used_time, " +
|
||||
"pvc.current_use_count, pvc.last_used_time, pvc.remark, pvc.create_time, pvc.update_time, pvc.deleted, pvc.deleted_at " +
|
||||
"FROM price_voucher_code pvc WHERE pvc.scenic_id = #{scenicId} AND pvc.status = 0 AND pvc.deleted = 0 " +
|
||||
"AND NOT EXISTS (SELECT 1 FROM voucher_print_record vpr WHERE vpr.voucher_code_id = pvc.id AND vpr.deleted = 0) " +
|
||||
"ORDER BY RAND() LIMIT 1")
|
||||
PriceVoucherCode findRandomUnprintedVoucher(@Param("scenicId") Long scenicId);
|
||||
}
|
@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ycwl.basic.pricing.entity.VoucherPrintRecord;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
/**
|
||||
* 优惠券打印记录Mapper
|
||||
@@ -17,6 +19,9 @@ public interface VoucherPrintRecordMapper extends BaseMapper<VoucherPrintRecord>
|
||||
* @param scenicId 景区ID
|
||||
* @return 打印记录
|
||||
*/
|
||||
@Select("SELECT id, code, face_id, broker_id, scenic_id, voucher_code_id, voucher_code, " +
|
||||
"print_status, error_message, create_time, update_time, deleted, deleted_at " +
|
||||
"FROM voucher_print_record WHERE face_id = #{faceId} AND scenic_id = #{scenicId} AND deleted = 0 LIMIT 1")
|
||||
VoucherPrintRecord selectByFaceBrokerScenic(@Param("faceId") Long faceId,
|
||||
@Param("scenicId") Long scenicId);
|
||||
|
||||
@@ -25,6 +30,9 @@ public interface VoucherPrintRecordMapper extends BaseMapper<VoucherPrintRecord>
|
||||
* @param voucherCodeId 券码ID
|
||||
* @return 打印记录
|
||||
*/
|
||||
@Select("SELECT id, code, face_id, broker_id, scenic_id, voucher_code_id, voucher_code, " +
|
||||
"print_status, error_message, create_time, update_time, deleted, deleted_at " +
|
||||
"FROM voucher_print_record WHERE voucher_code_id = #{voucherCodeId} AND deleted = 0 LIMIT 1")
|
||||
VoucherPrintRecord selectByVoucherCodeId(@Param("voucherCodeId") Long voucherCodeId);
|
||||
|
||||
/**
|
||||
@@ -34,7 +42,9 @@ public interface VoucherPrintRecordMapper extends BaseMapper<VoucherPrintRecord>
|
||||
* @param errorMessage 错误信息(可为null)
|
||||
* @return 影响行数
|
||||
*/
|
||||
int updatePrintStatus(@Param("id") Long id,
|
||||
@Param("printStatus") Integer printStatus,
|
||||
@Update("UPDATE voucher_print_record SET print_status = #{printStatus}, error_message = #{errorMessage}, " +
|
||||
"update_time = NOW() WHERE id = #{id}")
|
||||
int updatePrintStatus(@Param("id") Long id,
|
||||
@Param("printStatus") Integer printStatus,
|
||||
@Param("errorMessage") String errorMessage);
|
||||
}
|
Reference in New Issue
Block a user