- 新增 ReconciliationCompleteCmd DTO用于对账完成请求 - 在 ReconciliationServiceI 中添加 complete 方法定义 - 在 ReconciliationGateway 中添加 complete 方法定义 - 实现 Gateway 层 complete 方法,包含状态校验逻辑 - 添加 ReconciliationCompleteCmdExe 执行器处理业务逻辑 - 在 ReconciliationServiceImpl 中注入并实现 complete 方法 - 在 Controller 中添加 completeReconciliation 接口 - 添加 B_BIZ_RECONCILIATION_NOT_PENDING 业务异常码 - 修复 ReconciliationGatewayImpl 中的插入顺序问题
8.1 KiB
| name | description |
|---|---|
| add-state-transition | 为实体添加状态流转接口(如:完成、取消等)。遵循 ERPTurbo 项目的 DDD 分层架构规范。 |
Add State Transition
为实体添加状态流转接口,遵循 DDD 分层架构规范。
⚠️ 重要规则
仅操作 erp-turbo-business 和 erp-turbo-admin 模块,禁止修改 erp-turbo-svc 模块!
详见:.claude/PROJECT_RULES.md
功能说明
为实体添加状态流转接口,例如:订单完成、对账取消、审核通过等。
输入格式
Entity: {实体名称}
Action: {操作名称}
TargetState: {目标状态值}
Comment: {操作中文描述}
示例:
Entity: Reconciliation
Action: Complete
TargetState: RECONCILED
Comment: 对账完成
工作流程
1. 创建 Cmd DTO
路径:erp-turbo-common/erp-turbo-api/src/main/java/com/xunhong/erp/turbo/api/biz/dto/cmd/
文件名: {Entity}{Action}Cmd.java
package com.xunhong.erp.turbo.api.biz.dto.cmd;
import com.xunhong.erp.turbo.base.dto.Command;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author shenyifei
*/
@Data
@Schema(title = "{Comment}")
@EqualsAndHashCode(callSuper = true)
public class {Entity}{Action}Cmd extends Command {
@Schema(title = "{EntityComment}ID", requiredMode = Schema.RequiredMode.REQUIRED, type = "string")
private Long {entityFieldName}Id;
}
2. 更新 Service 接口
路径:erp-turbo-common/erp-turbo-api/src/main/java/com/xunhong/erp/turbo/api/biz/api/{Entity}ServiceI.java
添加方法签名:
{Entity}VO {action}({Entity}{Action}Cmd {entity}{Action}Cmd);
3. 更新 Gateway 接口
路径:erp-turbo-business/erp-turbo-biz/src/main/java/com/xunhong/erp/turbo/biz/domain/gateway/{Entity}Gateway.java
添加方法签名:
{Entity} {action}({Entity}{Action}Cmd {entity}{Action}Cmd);
4. 实现 Gateway
路径:erp-turbo-business/erp-turbo-biz/src/main/java/com/xunhong/erp/turbo/biz/infrastructure/gateway/{Entity}GatewayImpl.java
添加 import:
import com.xunhong.erp.turbo.api.biz.dto.cmd.{Entity}{Action}Cmd;
import com.xunhong.erp.turbo.api.biz.dto.enums.{Entity}StateEnum;
实现方法:
@Override
public {Entity} {action}({Entity}{Action}Cmd cmd) {
LambdaQueryWrapper<{Entity}DO> queryWrapper = Wrappers.lambdaQuery({Entity}DO.class);
queryWrapper.eq({Entity}DO::get{Entity}Id, cmd.get{Entity}Id());
queryWrapper.select({Entity}DO::get{Entity}Id, {Entity}DO::getState);
queryWrapper.last("limit 1");
{Entity}DO {entity}DO = {entity}Mapper.selectOne(queryWrapper);
if (!{entity}DO.getState().equals({Entity}StateEnum.{CURRENT_STATE})) {
throw new BizException(BizErrorCode.B_BIZ_{ENTITY_UPPER}_NOT_{CURRENT_STATE_UPPER});
}
{entity}DO.setState({Entity}StateEnum.{TARGET_STATE});
{entity}Mapper.updateById({entity}DO);
return {entity}Convert.to{Entity}({entity}DO);
}
5. 创建 Executor
路径:erp-turbo-business/erp-turbo-biz/src/main/java/com/xunhong/erp/turbo/biz/app/executor/cmd/{Entity}{Action}CmdExe.java
package com.xunhong.erp.turbo.biz.app.executor.cmd;
import com.xunhong.erp.turbo.api.biz.dto.cmd.{Entity}{Action}Cmd;
import com.xunhong.erp.turbo.api.biz.dto.vo.{Entity}VO;
import com.xunhong.erp.turbo.biz.app.assembler.{Entity}Assembler;
import com.xunhong.erp.turbo.biz.domain.gateway.{Entity}Gateway;
import com.xunhong.erp.turbo.biz.domain.entity.{Entity};
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author shenyifei
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class {Entity}{Action}CmdExe {
private final {Entity}Gateway {entity}Gateway;
private final {Entity}Assembler {entity}Assembler;
public {Entity}VO execute({Entity}{Action}Cmd cmd) {
{Entity} {entity} = {entity}Gateway.{action}(cmd);
return {entity}Assembler.to{Entity}VO({entity});
}
}
6. 更新 ServiceImpl
路径:erp-turbo-business/erp-turbo-biz/src/main/java/com/xunhong/erp/turbo/biz/app/service/{Entity}ServiceImpl.java
添加字段注入:
private final {Entity}{Action}CmdExe {entity}{Action}CmdExe;
添加方法实现:
@Override
public {Entity}VO {action}({Entity}{Action}Cmd cmd) {
return {entity}{Action}CmdExe.execute(cmd);
}
7. 更新 Controller
路径:erp-turbo-admin/src/main/java/com/xunhong/erp/turbo/admin/controller/{Entity}Controller.java
添加 import:
import com.xunhong.erp.turbo.api.biz.dto.cmd.{Entity}{Action}Cmd;
添加接口方法:
@SaCheckLogin
@PostMapping("{action}{Entity}")
@Operation(summary = "{Comment}", method = "POST")
public SingleResponse<{Entity}VO> {action}{Entity}(
@RequestBody @Validated {Entity}{Action}Cmd cmd) {
return SingleResponse.of({entity}Service.{action}(cmd));
}
命名规范
| 类型 | 格式 | 示例 |
|---|---|---|
| 实体名 | PascalCase | Reconciliation, Order |
| 操作名 | PascalCase | Complete, Cancel, Approve |
| 方法名 | camelCase | complete, cancel, approve |
| 字段名 | camelCase | reconciliationId, orderId |
| 常量 | UPPER_SNAKE_CASE | RECONCILIATION, ORDER |
使用示例
示例 1:对账完成
Entity: Reconciliation
Action: Complete
TargetState: RECONCILED
Comment: 对账完成
CurrentState: PENDING
生成接口:POST /operation/completeReconciliation
示例 2:订单取消
Entity: Order
Action: Cancel
TargetState: CANCELLED
Comment: 取消订单
CurrentState: PENDING
生成接口:POST /operation/cancelOrder
示例 3:审核通过
Entity: PaymentTask
Action: Approve
TargetState: APPROVED
Comment: 审核通过
CurrentState: PENDING_APPROVAL
生成接口:POST /operation/approvePaymentTask
输出示例
✅ 已完成状态流转接口添加
========================================
创建文件:
✅ api/.../cmd/{Entity}{Action}Cmd.java (erp-turbo-common)
✅ biz/.../executor/cmd/{Entity}{Action}CmdExe.java (erp-turbo-business)
更新文件:
✅ api/.../api/{Entity}ServiceI.java (erp-turbo-common)
✅ biz/.../gateway/{Entity}Gateway.java (erp-turbo-business)
✅ biz/.../gateway/{Entity}GatewayImpl.java (erp-turbo-business)
✅ biz/.../service/{Entity}ServiceImpl.java (erp-turbo-business)
✅ admin/.../controller/{Entity}Controller.java (erp-turbo-admin)
接口路径: POST /{basePath}/{action}{Entity}
请求体: {"{entityFieldName}Id": 123}
状态流转: {CURRENT_STATE} → {TARGET_STATE}
注意事项
-
状态验证:
- Gateway 实现中应验证当前状态
- 使用
BizException抛出业务异常 - 错误码格式:
B_BIZ_{ENTITY}_NOT_{STATE}
-
查询优化:
- 使用
queryWrapper.select()只查询必要字段 - 减少数据传输和内存占用
- 使用
-
事务处理:
- 根据需要添加
@Transactional注解 - 涉及多表操作时务必使用事务
- 根据需要添加
-
接口一致性:
- 使用
@PostMapping - 使用
@RequestBody @Validated接收参数 - 返回类型统一为
SingleResponse<{Entity}VO>
- 使用
-
权限控制:
- 所有接口添加
@SaCheckLogin注解 - 根据需要添加其他权限验证
- 所有接口添加
-
Assemble 方法:
- 使用
to{Entity}VO()而非toVO() - 保持命名一致性
- 使用
文件搜索规则
使用 Glob 工具时,限定在特定模块:
# ✅ 正确:限定路径
erp-turbo-business/**/{Entity}*.java
erp-turbo-common/**/{Entity}*.java
erp-turbo-admin/**/{Entity}*.java
# ❌ 错误:会匹配到 svc 模块
**/*{Entity}*.java
常见状态流转模式
| 业务场景 | 当前状态 | 目标状态 | 操作名 |
|---|---|---|---|
| 对账完成 | PENDING | RECONCILED | Complete |
| 部分开票 | RECONCILED | PARTIAL_INVOICE | PartialInvoice |
| 完成开票 | PARTIAL_INVOICE | INVOICED | Invoice |
| 部分回款 | INVOICED | PARTIAL_PAYMENT | PartialPayment |
| 完成回款 | PARTIAL_PAYMENT | PAID | Payment |
| 订单取消 | PENDING | CANCELLED | Cancel |
| 审核通过 | PENDING | APPROVED | Approve |
| 审核驳回 | PENDING | REJECTED | Reject |