feat(审批): 新增审批详情和开柜中状态处理

添加审批详情DTO和接口,支持查看审批详情信息
新增开柜中状态(4)及相关处理逻辑
重构审批状态查询条件,支持开柜中状态
新增分配商品格口功能接口
This commit is contained in:
dzq 2025-06-18 15:12:36 +08:00
parent ef875a0810
commit 07dd290645
6 changed files with 401 additions and 7 deletions

View File

@ -12,6 +12,7 @@ import com.agileboot.domain.shop.approval.command.AddReturnApprovalCommand;
import com.agileboot.domain.shop.approval.command.UpdateReturnApprovalCommand;
import com.agileboot.domain.shop.approval.db.ReturnApprovalEntity;
import com.agileboot.domain.shop.approval.dto.ReturnApprovalAssetDTO;
import com.agileboot.domain.shop.approval.dto.ReturnApprovalDetailDTO;
import com.agileboot.domain.shop.approval.model.ReturnApprovalModel;
import com.agileboot.domain.shop.approval.query.SearchApiReturnApprovalQuery;
import com.agileboot.domain.shop.approval.query.SearchReturnApprovalAssetQuery;
@ -103,7 +104,7 @@ public class ApprovalApiController {
try {
if (command.getStatus() == 2) {
approvalApplicationService.approveAssetApproval(command);
approvalApplicationService.updateApprovalStatusAndComplete(command);
} else if (command.getStatus() == 3) {
approvalApplicationService.rejectAssetApproval(command);
} else {
@ -124,6 +125,29 @@ public class ApprovalApiController {
}
}
@PostMapping("/handle/allocateApprovalGoods")
@ApiOperation(value = "处理审批操作")
public ResponseDTO<String> allocateApprovalGoods(@Valid @RequestBody UpdateReturnApprovalCommand command) {
if (command.getApprovalId() == null) {
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "审批ID不能为空"));
}
try {
approvalApplicationService.allocateApprovalGoodsCells(command);
return ResponseDTO.ok("操作成功");
} catch (Exception e) {
log.error("审批操作失败", e);
// 记录支付操作日志
AddPaymentOperationLogCommand paymentOperationLogCommand = new AddPaymentOperationLogCommand();
paymentOperationLogCommand.setOperationType("handleAssetApproval");
paymentOperationLogCommand.setStatus(2);
paymentOperationLogCommand.setRemark(ExceptionUtils.getStackTrace(e));
paymentOperationLogCommand.setParams(JSONUtil.toJsonStr(command));
paymentOperationLogCommand.initBaseEntity();
paymentOperationLogApplicationService.addPaymentOperationLog(paymentOperationLogCommand);
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, e.getMessage()));
}
}
/**
* 提交退货审批申请
@ -176,6 +200,12 @@ public class ApprovalApiController {
return ResponseDTO.ok(list);
}
@GetMapping("/detail/asset")
@ApiOperation(value = "审批列表")
public ResponseDTO<ReturnApprovalDetailDTO> detailAsset(Long approval_id) {
return ResponseDTO.ok(approvalApplicationService.getApprovalDetail(approval_id));
}
@GetMapping("/list/asset")
@ApiOperation(value = "审批列表")

View File

@ -34,6 +34,7 @@ import com.agileboot.domain.shop.approval.command.UpdateReturnApprovalCommand;
import com.agileboot.domain.shop.approval.db.ReturnApprovalEntity;
import com.agileboot.domain.shop.approval.db.ReturnApprovalService;
import com.agileboot.domain.shop.approval.dto.ReturnApprovalAssetDTO;
import com.agileboot.domain.shop.approval.dto.ReturnApprovalDetailDTO;
import com.agileboot.domain.shop.approval.model.ReturnApprovalModel;
import com.agileboot.domain.shop.approval.model.ReturnApprovalModelFactory;
import com.agileboot.domain.shop.approval.query.SearchApiReturnApprovalQuery;
@ -301,6 +302,231 @@ public class ReturnApprovalApplicationService {
}
/**
* 处理库存分配并创建addApprovalGoodsCellList
*/
public void allocateApprovalGoodsCells(UpdateReturnApprovalCommand command) {
List<UpdateApprovalGoodsCommand> approvalGoodsCommands = command.getApprovalGoodsList();
if (approvalGoodsCommands == null || approvalGoodsCommands.isEmpty()) {
throw new RuntimeException("审批通过的耗材列表不能为空");
}
// 加载退货审批模型
ReturnApprovalModel model = modelFactory.loadById(command.getApprovalId());
// 设置审批人信息
if (StringUtils.isNotBlank(command.getAuditName())) {
model.setAuditName(command.getAuditName());
} else if (StringUtils.isNotBlank(command.getUserid())) {
QyUserEntity qyUserEntity = qyUserService.getUserByUserIdAndCorpid(command.getUserid(), model.getCorpid());
if (null != qyUserEntity) {
model.setAuditName(qyUserEntity.getName());
}
}
// 获取关联的订单商品列表
List<ApprovalGoodsEntity> approvalGoodsList = approvalGoodsService.selectByApprovalId(model.getApprovalId());
if (approvalGoodsList == null || approvalGoodsList.isEmpty()) {
throw new RuntimeException("未找到关联的订单商品");
}
approvalGoodsList.forEach(approvalGoods -> {
approvalGoods.setApprovalQuantity(0);
});
// 获取关联的商品列表
QueryWrapper<ShopGoodsEntity> goodsWrapper = new QueryWrapper<>();
goodsWrapper.in("goods_id", approvalGoodsCommands.stream().map(ApprovalGoodsEntity::getGoodsId).distinct().collect(Collectors.toList()))
.eq("deleted", false);
List<ShopGoodsEntity> goodsList = shopGoodsService.list(goodsWrapper);
if (goodsList == null || goodsList.isEmpty()) {
throw new RuntimeException("未找到关联的商品");
}
// 初始化商品和格口模型列表
List<ApprovalGoodsCellEntity> addApprovalGoodsCellList = new ArrayList<>();
for (ApprovalGoodsEntity approvalGoodsCommand : approvalGoodsCommands) {
if (approvalGoodsCommand.getApprovalQuantity() == null || approvalGoodsCommand.getApprovalQuantity().compareTo(0) <= 0) {
continue;
}
ApprovalGoodsEntity approvalGoods = approvalGoodsList.stream()
.filter(g -> g.getApprovalGoodsId().equals(approvalGoodsCommand.getApprovalGoodsId())).findFirst().orElse(null);
if (approvalGoods == null) {
throw new RuntimeException("未找到关联的订单商品");
}
if (approvalGoods.getApplyQuantity().compareTo(approvalGoodsCommand.getApprovalQuantity()) < 0) {
throw new RuntimeException("审批数量不能大于申请数量");
}
approvalGoods.setApprovalQuantity(approvalGoodsCommand.getApprovalQuantity());
ShopGoodsEntity goods = goodsList.stream()
.filter(g -> g.getGoodsId().equals(approvalGoodsCommand.getGoodsId())).findFirst().orElse(null);
if (goods == null) {
throw new RuntimeException("未找到关联的商品");
}
if (goods.getStock().compareTo(approvalGoodsCommand.getApprovalQuantity()) < 0) {
throw new RuntimeException("商品库存不足");
}
List<CabinetCellEntity> cells = cabinetCellService.selectByGoodsId(approvalGoodsCommand.getGoodsId());
// 如果没有找到对应的格口抛出异常
if (cells == null || cells.isEmpty()) {
throw new RuntimeException("未找到关联的格口");
}
// 按库存数量从大到小排序
cells.sort(Comparator.comparingInt(CabinetCellEntity::getStock).reversed());
// 遍历格口列表从库存最多的格口开始分配直到满足需求
int remainingQuantity = approvalGoodsCommand.getApprovalQuantity();
for (CabinetCellEntity cell : cells) {
SmartCabinetEntity smartCabinetEntity = smartCabinetService.getByCabinetId(cell.getCabinetId());
if (smartCabinetEntity == null) {
throw new RuntimeException("未找到关联的柜子");
}
ShopEntity shop = shopService.getById(smartCabinetEntity.getShopId());
ApprovalGoodsCellEntity addApprovalGoodsCellCommand = new ApprovalGoodsCellEntity();
addApprovalGoodsCellCommand.initBaseEntity();
addApprovalGoodsCellCommand.setApprovalId(command.getApprovalId());
addApprovalGoodsCellCommand.setApprovalGoodsId(approvalGoodsCommand.getApprovalGoodsId());
addApprovalGoodsCellCommand.setCabinetId(smartCabinetEntity.getCabinetId());
addApprovalGoodsCellCommand.setCabinetName(smartCabinetEntity.getCabinetName());
addApprovalGoodsCellCommand.setCellId(cell.getCellId());
addApprovalGoodsCellCommand.setCellNo(cell.getCellNo());
if (shop != null) {
addApprovalGoodsCellCommand.setShopId(shop.getShopId());
addApprovalGoodsCellCommand.setShopName(shop.getShopName());
}
addApprovalGoodsCellList.add(addApprovalGoodsCellCommand);
if (cell.getStock() >= remainingQuantity) {
addApprovalGoodsCellCommand.setAllocateQuantity(remainingQuantity);
cell.setStock(cell.getStock() - remainingQuantity);
remainingQuantity = 0;
break;
} else {
addApprovalGoodsCellCommand.setAllocateQuantity(cell.getStock());
remainingQuantity -= cell.getStock();
cell.setStock(0);
}
}
// 如果还有剩余数量说明库存不足
if (remainingQuantity > 0) {
throw new RuntimeException("商品" + goods.getGoodsName() + "在柜子中的库存不足");
}
goods.setStock(goods.getStock() - approvalGoodsCommand.getApprovalQuantity());
}
// 更新审批状态为通过
model.validateApprovalStatus();
model.setAuditImages(command.getAuditImages());
model.setAuditRemark(command.getAuditRemark());
model.setAuditUserid(command.getAuditUserid());
// 开始执行数据库操作
model.setStatus(4); // 2表示审核通过状态
model.updateById();
// 批量插入审批商品格口关联表
approvalGoodsCellService.saveBatch(addApprovalGoodsCellList);
}
/**
* 执行更新审批状态为通过以及之后的操作
*/
public void updateApprovalStatusAndComplete(UpdateReturnApprovalCommand command) {
// 加载退货审批模型
ReturnApprovalModel model = modelFactory.loadById(command.getApprovalId());
// 设置审批人信息
if (StringUtils.isNotBlank(command.getAuditName())) {
model.setAuditName(command.getAuditName());
} else if (StringUtils.isNotBlank(command.getUserid())) {
QyUserEntity qyUserEntity = qyUserService.getUserByUserIdAndCorpid(command.getUserid(), model.getCorpid());
if (null != qyUserEntity) {
model.setAuditName(qyUserEntity.getName());
}
}
// 获取关联的订单商品列表
List<ApprovalGoodsEntity> approvalGoodsList = approvalGoodsService.selectByApprovalId(model.getApprovalId());
if (approvalGoodsList == null || approvalGoodsList.isEmpty()) {
throw new RuntimeException("未找到关联的订单商品");
}
approvalGoodsList.forEach(approvalGoods -> {
approvalGoods.setApprovalQuantity(0);
});
List<ApprovalGoodsCellEntity> approvalGoodsCellEntities = approvalGoodsCellService.selectByApprovalId(model.getApprovalId());
// 获取关联的商品列表
QueryWrapper<ShopGoodsEntity> goodsWrapper = new QueryWrapper<>();
goodsWrapper.in("goods_id", approvalGoodsList.stream().map(ApprovalGoodsEntity::getGoodsId).distinct().collect(Collectors.toList()))
.eq("deleted", false);
List<ShopGoodsEntity> goodsList = shopGoodsService.list(goodsWrapper);
if (goodsList == null || goodsList.isEmpty()) {
throw new RuntimeException("未找到关联的商品");
}
// 初始化商品和格口模型列表
QueryWrapper<CabinetCellEntity> cellEntityQueryWrapper = new QueryWrapper<>();
cellEntityQueryWrapper.in("cell_id", approvalGoodsCellEntities.stream().map(ApprovalGoodsCellEntity::getCellId).collect(Collectors.toList()))
.eq("deleted", false);
List<CabinetCellEntity> cabinetCellList = cabinetCellService.list(cellEntityQueryWrapper);
for (ApprovalGoodsCellEntity approvalGoodsCell : approvalGoodsCellEntities) {
if (approvalGoodsCell.getAllocateQuantity() == null || approvalGoodsCell.getAllocateQuantity().compareTo(0) <= 0) {
continue;
}
ApprovalGoodsEntity approvalGoods = approvalGoodsList.stream()
.filter(g -> g.getApprovalGoodsId().equals(approvalGoodsCell.getApprovalGoodsId())).findFirst().orElse(null);
if (approvalGoods == null) {
throw new RuntimeException("未找到关联的订单商品");
}
ShopGoodsEntity goods = goodsList.stream()
.filter(g -> g.getGoodsId().equals(approvalGoods.getGoodsId())).findFirst().orElse(null);
if (goods == null) {
throw new RuntimeException("未找到关联的商品");
}
if (goods.getStock().compareTo(approvalGoodsCell.getAllocateQuantity()) < 0) {
throw new RuntimeException("商品库存不足");
}
CabinetCellEntity cell = cabinetCellList.stream()
.filter(c -> c.getCellId().equals(approvalGoodsCell.getCellId()))
.findFirst().orElse(null);
// 如果没有找到对应的格口抛出异常
if (cell == null) {
throw new RuntimeException("未找到关联的格口");
}
goods.setStock(goods.getStock() - approvalGoodsCell.getAllocateQuantity());
cell.setStock(cell.getStock() - approvalGoodsCell.getAllocateQuantity());
}
// 更新审批状态为通过
model.validateApprovalStatus();
model.setAuditImages(command.getAuditImages());
model.setAuditRemark(command.getAuditRemark());
model.setAuditUserid(command.getAuditUserid());
model.setApprovalTime(new Date());
// 调用固资通服务的出库方法
assetApplicationService.consumeOutput(model.getCorpid(), model.getApplyUserid(), model.getAuditUserid(),
model, approvalGoodsList, goodsList);
// 开始执行数据库操作
model.setStatus(2); // 2表示审核通过状态
model.updateById();
// 批量更新商品库存
goodsList.forEach(ShopGoodsEntity::updateById);
// 批量更新格口库存
cabinetCellList.forEach(CabinetCellEntity::updateById);
// 批量更新审批商品表
approvalGoodsList.forEach(ApprovalGoodsEntity::updateById);
}
/**
* 审批通过资产退货申请
* @param command 更新退货审批命令包含审批ID审批人信息等
@ -561,6 +787,17 @@ public class ReturnApprovalApplicationService {
return approvalGoodsCellService.selectByApprovalId(approvalId);
}
public ReturnApprovalDetailDTO getApprovalDetail(Long approvalId) {
ReturnApprovalEntity approval = approvalService.getById(approvalId);
if (approval == null) {
throw new RuntimeException("未找到对应的审批记录");
}
ReturnApprovalDetailDTO detailDTO = new ReturnApprovalDetailDTO(approval);
detailDTO.setGoodsList(approvalGoodsService.selectByApprovalId(approvalId));
detailDTO.setApprovalGoodsCellList(approvalGoodsCellService.selectByApprovalId(approvalId));
return detailDTO;
}
public PageDTO<ReturnApprovalAssetDTO> getApprovalAssetPage(SearchReturnApprovalAssetQuery<ReturnApprovalEntity> query) {
Page<ReturnApprovalEntity> page = approvalService.getApprovalAssetPage(query);
List<ReturnApprovalAssetDTO> dtoList = page.getRecords().stream()

View File

@ -122,7 +122,7 @@ public class ReturnApprovalEntity extends BaseEntity<ReturnApprovalEntity> {
@TableField("audit_name")
private String auditName;
@ApiModelProperty("审批状态(1待审核 2已通过 3已驳回)")
@ApiModelProperty("审批状态(1待审核 2已通过 3已驳回 4开柜中)")
@TableField("status")
private Integer status;

View File

@ -28,6 +28,7 @@ public class ReturnApprovalDTO {
case 1: return "待审核";
case 2: return "已通过";
case 3: return "已驳回";
case 4: return "开柜中";
default: return "未知状态";
}
}
@ -100,7 +101,7 @@ public class ReturnApprovalDTO {
@ExcelColumn(name = "审批人")
private String auditName;
@ExcelColumn(name = "审批状态(1待审核 2已通过 3已驳回)")
@ExcelColumn(name = "审批状态(1待审核 2已通过 3已驳回 4开柜中)")
private Integer status;
@ExcelColumn(name = "审批状态")

View File

@ -0,0 +1,119 @@
package com.agileboot.domain.shop.approval.dto;
import cn.hutool.core.bean.BeanUtil;
import com.agileboot.common.annotation.ExcelColumn;
import com.agileboot.common.annotation.ExcelSheet;
import com.agileboot.domain.shop.approval.db.ReturnApprovalEntity;
import com.agileboot.domain.shop.approvalGoods.db.ApprovalGoodsEntity;
import com.agileboot.domain.shop.approvalGoodsCell.db.ApprovalGoodsCellEntity;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
@ExcelSheet(name = "审批详情")
public class ReturnApprovalDetailDTO {
public ReturnApprovalDetailDTO(ReturnApprovalEntity entity) {
if (entity != null) {
BeanUtil.copyProperties(entity, this);
this.statusStr = convertStatus(entity.getStatus());
}
}
private String convertStatus(Integer status) {
if (status == null) return "-";
switch (status) {
case 1: return "待审核";
case 2: return "已通过";
case 3: return "已驳回";
case 4: return "开柜中";
default: return "未知状态";
}
}
@ExcelColumn(name = "审批编号")
private Long approvalId;
@ExcelColumn(name = "关联订单ID")
private Long orderId;
@ExcelColumn(name = "关联商品ID")
private Long goodsId;
@ExcelColumn(name = "关联订单商品ID")
private Long orderGoodsId;
@ExcelColumn(name = "外部归属类型的商品ID")
private Long externalGoodsId;
@ExcelColumn(name = "外部归属类型的审批ID")
private Long externalApprovalId;
@ExcelColumn(name = "审批码")
private String code;
private Integer codeCheck;
@ExcelColumn(name = "企业微信id")
private String corpid;
@ExcelColumn(name = "申请人企业UserID")
private String applyUserid;
@ExcelColumn(name = "申请人")
private String applyUserName;
@ExcelColumn(name = "审批人企业UserID")
private String auditUserid;
@ExcelColumn(name = "申请数量")
private Integer applyQuantity;
@ExcelColumn(name = "审批类型")
private Integer approvalType;
@ExcelColumn(name = "申请说明")
private String applyRemark;
@ExcelColumn(name = "归还数量")
private Integer returnQuantity;
@ExcelColumn(name = "商品单价")
private BigDecimal goodsPrice;
@ExcelColumn(name = "退还金额")
private BigDecimal returnAmount;
@ExcelColumn(name = "归还图片")
private String returnImages;
@ExcelColumn(name = "审核图片")
private String auditImages;
@ExcelColumn(name = "归还说明")
private String returnRemark;
@ExcelColumn(name = "审核说明")
private String auditRemark;
@ExcelColumn(name = "审批人")
private String auditName;
@ExcelColumn(name = "审批状态(1待审核 2已通过 3已驳回 4开柜中)")
private Integer status;
@ExcelColumn(name = "审批状态")
private String statusStr;
/**
* 关联的商品信息
*/
private List<ApprovalGoodsEntity> goodsList;
/**
* 关联的商品格口分配信息
*/
private List<ApprovalGoodsCellEntity> approvalGoodsCellList;
}

View File

@ -43,9 +43,15 @@ public class SearchReturnApprovalAssetQuery<T> extends AbstractPageQuery<T> {
if (status == null && handleStatus!= null) {
if (handleStatus == 0) {
queryWrapper.eq("ra.status", 1);
queryWrapper.and(wrapper ->
wrapper.eq("ra.status", 1)
.or()
.eq("ra.status", 4));
} else if (handleStatus == 1) {
queryWrapper.ne("ra.status", 1);
queryWrapper.and(wrapper ->
wrapper.eq("ra.status", 2)
.or()
.eq("ra.status", 3));
}
}
@ -53,9 +59,10 @@ public class SearchReturnApprovalAssetQuery<T> extends AbstractPageQuery<T> {
if (searchStr.matches("\\d{6}")) {
queryWrapper.eq("ra.code", searchStr);
} else {
queryWrapper.like("ra.apply_user_name", searchStr)
queryWrapper.and(wrapper ->
wrapper.like("ra.apply_user_name", searchStr)
.or()
.like("ag.goods_name", searchStr);
.like("ag.goods_name", searchStr));
}
}