From 07dd290645c99c173854e245599fa75b07adb099 Mon Sep 17 00:00:00 2001 From: dzq Date: Wed, 18 Jun 2025 15:12:36 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=AE=A1=E6=89=B9):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E8=AF=A6=E6=83=85=E5=92=8C=E5=BC=80=E6=9F=9C?= =?UTF-8?q?=E4=B8=AD=E7=8A=B6=E6=80=81=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加审批详情DTO和接口,支持查看审批详情信息 新增开柜中状态(4)及相关处理逻辑 重构审批状态查询条件,支持开柜中状态 新增分配商品格口功能接口 --- .../api/controller/ApprovalApiController.java | 32 ++- .../ReturnApprovalApplicationService.java | 237 ++++++++++++++++++ .../approval/db/ReturnApprovalEntity.java | 2 +- .../shop/approval/dto/ReturnApprovalDTO.java | 3 +- .../approval/dto/ReturnApprovalDetailDTO.java | 119 +++++++++ .../query/SearchReturnApprovalAssetQuery.java | 15 +- 6 files changed, 401 insertions(+), 7 deletions(-) create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/dto/ReturnApprovalDetailDTO.java diff --git a/agileboot-api/src/main/java/com/agileboot/api/controller/ApprovalApiController.java b/agileboot-api/src/main/java/com/agileboot/api/controller/ApprovalApiController.java index 470521f..be0440a 100644 --- a/agileboot-api/src/main/java/com/agileboot/api/controller/ApprovalApiController.java +++ b/agileboot-api/src/main/java/com/agileboot/api/controller/ApprovalApiController.java @@ -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 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 detailAsset(Long approval_id) { + return ResponseDTO.ok(approvalApplicationService.getApprovalDetail(approval_id)); + } + @GetMapping("/list/asset") @ApiOperation(value = "审批列表") diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/ReturnApprovalApplicationService.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/ReturnApprovalApplicationService.java index ec9a086..8baab18 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/ReturnApprovalApplicationService.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/ReturnApprovalApplicationService.java @@ -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 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 approvalGoodsList = approvalGoodsService.selectByApprovalId(model.getApprovalId()); + if (approvalGoodsList == null || approvalGoodsList.isEmpty()) { + throw new RuntimeException("未找到关联的订单商品"); + } + approvalGoodsList.forEach(approvalGoods -> { + approvalGoods.setApprovalQuantity(0); + }); + + // 获取关联的商品列表 + QueryWrapper goodsWrapper = new QueryWrapper<>(); + goodsWrapper.in("goods_id", approvalGoodsCommands.stream().map(ApprovalGoodsEntity::getGoodsId).distinct().collect(Collectors.toList())) + .eq("deleted", false); + List goodsList = shopGoodsService.list(goodsWrapper); + if (goodsList == null || goodsList.isEmpty()) { + throw new RuntimeException("未找到关联的商品"); + } + + // 初始化商品和格口模型列表 + List 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 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 approvalGoodsList = approvalGoodsService.selectByApprovalId(model.getApprovalId()); + if (approvalGoodsList == null || approvalGoodsList.isEmpty()) { + throw new RuntimeException("未找到关联的订单商品"); + } + approvalGoodsList.forEach(approvalGoods -> { + approvalGoods.setApprovalQuantity(0); + }); + + List approvalGoodsCellEntities = approvalGoodsCellService.selectByApprovalId(model.getApprovalId()); + + // 获取关联的商品列表 + QueryWrapper goodsWrapper = new QueryWrapper<>(); + goodsWrapper.in("goods_id", approvalGoodsList.stream().map(ApprovalGoodsEntity::getGoodsId).distinct().collect(Collectors.toList())) + .eq("deleted", false); + List goodsList = shopGoodsService.list(goodsWrapper); + if (goodsList == null || goodsList.isEmpty()) { + throw new RuntimeException("未找到关联的商品"); + } + + // 初始化商品和格口模型列表 + QueryWrapper cellEntityQueryWrapper = new QueryWrapper<>(); + cellEntityQueryWrapper.in("cell_id", approvalGoodsCellEntities.stream().map(ApprovalGoodsCellEntity::getCellId).collect(Collectors.toList())) + .eq("deleted", false); + List 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 getApprovalAssetPage(SearchReturnApprovalAssetQuery query) { Page page = approvalService.getApprovalAssetPage(query); List dtoList = page.getRecords().stream() diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/db/ReturnApprovalEntity.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/db/ReturnApprovalEntity.java index 46fb1bb..d5b4988 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/db/ReturnApprovalEntity.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/db/ReturnApprovalEntity.java @@ -122,7 +122,7 @@ public class ReturnApprovalEntity extends BaseEntity { @TableField("audit_name") private String auditName; - @ApiModelProperty("审批状态(1待审核 2已通过 3已驳回)") + @ApiModelProperty("审批状态(1待审核 2已通过 3已驳回 4开柜中)") @TableField("status") private Integer status; diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/dto/ReturnApprovalDTO.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/dto/ReturnApprovalDTO.java index 30e114f..1765b7e 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/dto/ReturnApprovalDTO.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/dto/ReturnApprovalDTO.java @@ -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 = "审批状态") diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/dto/ReturnApprovalDetailDTO.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/dto/ReturnApprovalDetailDTO.java new file mode 100644 index 0000000..385063e --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/dto/ReturnApprovalDetailDTO.java @@ -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 goodsList; + + /** + * 关联的商品格口分配信息 + */ + private List approvalGoodsCellList; +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/query/SearchReturnApprovalAssetQuery.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/query/SearchReturnApprovalAssetQuery.java index 2a8e599..51381cd 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/query/SearchReturnApprovalAssetQuery.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/query/SearchReturnApprovalAssetQuery.java @@ -43,9 +43,15 @@ public class SearchReturnApprovalAssetQuery extends AbstractPageQuery { 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 extends AbstractPageQuery { 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)); } }