feat(approval): 新增资产审批相关功能及审批码校验

- 添加审批数量字段到ApprovalGoodsDTO和ApprovalGoodsEntity
- 新增ReturnApprovalAssetDTO用于资产审批列表展示
- 实现审批码校验接口及核销状态更新
- 新增资产审批分页查询接口及相关查询条件
- 添加审批码校验状态字段和申请人名字段
- 创建approval_goods_cell表用于记录商品格口分配
- 完善资产审批相关服务逻辑
This commit is contained in:
dzq 2025-06-14 11:40:51 +08:00
parent 460d34457e
commit 9f1a87e348
15 changed files with 244 additions and 0 deletions

View File

@ -1,5 +1,6 @@
package com.agileboot.api.controller;
import com.agileboot.common.constant.WeixinConstants;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.common.exception.ApiException;
@ -8,8 +9,10 @@ import com.agileboot.domain.shop.approval.ReturnApprovalApplicationService;
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.model.ReturnApprovalModel;
import com.agileboot.domain.shop.approval.query.SearchApiReturnApprovalQuery;
import com.agileboot.domain.shop.approval.query.SearchReturnApprovalAssetQuery;
import com.agileboot.domain.shop.approval.query.SearchReturnApprovalQuery;
import com.agileboot.domain.shop.order.OrderApplicationService;
import com.agileboot.domain.shop.order.db.ShopOrderGoodsEntity;
@ -151,4 +154,29 @@ public class ApprovalApiController {
List<ShopOrderGoodsEntity> list = approvalApplicationService.getApprovalOrderGoods(approvalId);
return ResponseDTO.ok(list);
}
@GetMapping("/list/asset")
@ApiOperation(value = "审批列表")
public ResponseDTO<PageDTO<ReturnApprovalAssetDTO>> listAsset(SearchReturnApprovalAssetQuery<ReturnApprovalEntity> query) {
PageDTO<ReturnApprovalAssetDTO> page = approvalApplicationService.getApprovalAssetPage(query);
return ResponseDTO.ok(page);
}
@PostMapping("/checkCode")
@ApiOperation(value = "校验审批码")
public ResponseDTO<String> checkCode(@RequestParam String corpid, @RequestParam Integer approvalType, @RequestParam String code) {
try {
if (StringUtils.isBlank(corpid)) {
corpid = WeixinConstants.corpid;
}
approvalApplicationService.checkCode(corpid, approvalType, code);
} catch (Exception e) {
return ResponseDTO.fail(new ApiException(ErrorCode.Internal.INTERNAL_ERROR, e.getMessage()));
}
return ResponseDTO.ok("校验成功");
}
}

View File

@ -129,6 +129,7 @@ public class AssetApplicationService {
if (returnApprovalCommand.getApprovalType() == null) {
returnApprovalCommand.setApprovalType(1);
}
returnApprovalCommand.setApplyUserid(postAssetApprovalCommand.getUserid());
ReturnApprovalModel returnApprovalModel = returnApprovalModelFactory.create();
returnApprovalModel.initBaseEntity();

View File

@ -21,10 +21,14 @@ 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.db.ReturnApprovalService;
import com.agileboot.domain.shop.approval.dto.ReturnApprovalAssetDTO;
import com.agileboot.domain.shop.approval.model.ReturnApprovalModel;
import com.agileboot.domain.shop.approval.model.ReturnApprovalModelFactory;
import com.agileboot.domain.shop.approval.query.SearchApiReturnApprovalQuery;
import com.agileboot.domain.shop.approval.query.SearchReturnApprovalAssetQuery;
import com.agileboot.domain.shop.approval.query.SearchReturnApprovalQuery;
import com.agileboot.domain.shop.approvalGoods.db.ApprovalGoodsEntity;
import com.agileboot.domain.shop.approvalGoods.db.ApprovalGoodsService;
import com.agileboot.domain.shop.goods.model.GoodsModel;
import com.agileboot.domain.shop.goods.model.GoodsModelFactory;
import com.agileboot.domain.shop.order.db.ShopOrderGoodsEntity;
@ -37,6 +41,7 @@ import com.agileboot.domain.shop.payment.PaymentApplicationService;
import com.agileboot.domain.shop.payment.dto.RefundVO;
import com.agileboot.domain.shop.paymentOperationLog.PaymentOperationLogApplicationService;
import com.agileboot.domain.shop.paymentOperationLog.command.AddPaymentOperationLogCommand;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.math.BigDecimal;
@ -72,6 +77,7 @@ public class ReturnApprovalApplicationService {
private final QyUserService userService;
private final PaymentOperationLogApplicationService paymentOperationLogApplicationService;
private final AssetApplicationService assetApplicationService;
private final ApprovalGoodsService approvalGoodsService;
/**
* 获取退货审批列表
@ -439,6 +445,33 @@ public class ReturnApprovalApplicationService {
return shopOrderGoodsService.selectOrderGoodsByApprovalId(approvalId);
}
public PageDTO<ReturnApprovalAssetDTO> getApprovalAssetPage(SearchReturnApprovalAssetQuery<ReturnApprovalEntity> query) {
Page<ReturnApprovalEntity> page = approvalService.getApprovalAssetPage(query);
List<ReturnApprovalAssetDTO> dtoList = page.getRecords().stream()
.map(ReturnApprovalAssetDTO::new)
.collect(java.util.stream.Collectors.toList());
if (!dtoList.isEmpty()) {
QueryWrapper<ApprovalGoodsEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.in("approval_id",
page.getRecords().stream()
.map(ReturnApprovalEntity::getApprovalId)
.collect(java.util.stream.Collectors.toList()))
.eq("deleted", false);
List<ApprovalGoodsEntity> approvalGoodsEntities = approvalGoodsService.list(queryWrapper);
for (ReturnApprovalAssetDTO dto : dtoList) {
List<ApprovalGoodsEntity> goodsList = approvalGoodsEntities.stream()
.filter(g -> g.getApprovalId().equals(dto.getApprovalId()))
.collect(java.util.stream.Collectors.toList());
dto.setGoodsList(goodsList);
}
}
return new PageDTO<>(dtoList, page.getTotal());
}
/**
* 审批驳回退货申请
* @param command 更新退货审批命令包含驳回原因
@ -461,4 +494,27 @@ public class ReturnApprovalApplicationService {
model.setApprovalTime(new Date());
model.updateById();
}
/**
* 验证审批码有效性并更新核销状态
* @param corpid 企业微信ID
* @param approvalType 审批类型0为借还柜 1为固资通
* @param code 审批码
* @throws RuntimeException 当审批码无效或已核销时抛出
*/
public void checkCode(String corpid, Integer approvalType, String code) {
QueryWrapper<ReturnApprovalEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("corpid", corpid)
.eq("approval_type", approvalType)
.eq("code", code)
.eq("code_check", 0)
.eq("deleted", false);
ReturnApprovalEntity approval = approvalService.getOne(queryWrapper);
if (approval == null) {
throw new RuntimeException("无效的审批码");
}
approval.setCodeCheck(1);
approval.updateById();
}
}

View File

@ -58,6 +58,10 @@ public class ReturnApprovalEntity extends BaseEntity<ReturnApprovalEntity> {
@TableField("code")
private String code;
@ApiModelProperty("审批码校验状态(0未核销 1已核销)")
@TableField("code_check")
private Integer codeCheck;
@ApiModelProperty("企业微信id")
@TableField("corpid")
private String corpid;
@ -66,6 +70,10 @@ public class ReturnApprovalEntity extends BaseEntity<ReturnApprovalEntity> {
@TableField("apply_userid")
private String applyUserid;
@ApiModelProperty("申请人")
@TableField("apply_user_name")
private String applyUserName;
@ApiModelProperty("审批人企业UserID")
@TableField("audit_userid")
private String auditUserid;

View File

@ -26,6 +26,7 @@ public interface ReturnApprovalMapper extends BaseMapper<ReturnApprovalEntity> {
"${ew.customSqlSegment}")
Page<ReturnApprovalEntity> selectApprovalWithGoodsInfo(Page<ReturnApprovalEntity> page,
@Param(Constants.WRAPPER) Wrapper<ReturnApprovalEntity> queryWrapper);
@Select("SELECT ra.*, sog.goods_name AS goodsName, sog.cover_img AS coverImg, " +
"so.mobile, so.userid, so.name, so.payment_method AS paymentMethod " +

View File

@ -25,4 +25,6 @@ public interface ReturnApprovalService extends IService<ReturnApprovalEntity> {
ReturnApprovalEntity getByOrderId(Long orderId);
Page<ReturnApprovalEntity> selectApprovalWithGoodsInfo(AbstractPageQuery<ReturnApprovalEntity> query);
Page<ReturnApprovalEntity> getApprovalAssetPage(AbstractPageQuery<ReturnApprovalEntity> query);
}

View File

@ -48,4 +48,9 @@ public class ReturnApprovalServiceImpl extends ServiceImpl<ReturnApprovalMapper,
public Page<ReturnApprovalEntity> selectApprovalWithGoodsInfo(AbstractPageQuery<ReturnApprovalEntity> query) {
return this.baseMapper.selectApprovalWithGoodsInfo(query.toPage(), query.toQueryWrapper());
}
@Override
public Page<ReturnApprovalEntity> getApprovalAssetPage(AbstractPageQuery<ReturnApprovalEntity> query) {
return this.page(query.toPage(), query.toQueryWrapper());
}
}

View File

@ -0,0 +1,21 @@
package com.agileboot.domain.shop.approval.dto;
import com.agileboot.domain.shop.approval.db.ReturnApprovalEntity;
import com.agileboot.domain.shop.approvalGoods.db.ApprovalGoodsEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.beans.BeanUtils;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
public class ReturnApprovalAssetDTO extends ReturnApprovalEntity {
public ReturnApprovalAssetDTO(ReturnApprovalEntity entity) {
if (entity != null) {
BeanUtils.copyProperties(entity, this);
}
}
private List<ApprovalGoodsEntity> goodsList;
}

View File

@ -53,12 +53,17 @@ public class ReturnApprovalDTO {
@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;

View File

@ -19,8 +19,10 @@ public class SearchApiReturnApprovalQuery<T> extends AbstractPageQuery<T> {
private Long externalGoodsId;
private Long externalApprovalId;
private String code;
private Integer codeCheck;
private String corpid;
private String applyUserid;
private String applyUserName;
private String auditUserid;
private Integer applyQuantity;
private Integer approvalType;
@ -42,9 +44,11 @@ public class SearchApiReturnApprovalQuery<T> extends AbstractPageQuery<T> {
.eq(externalGoodsId != null, "ra.external_goods_id", externalGoodsId)
.eq(externalApprovalId != null, "ra.external_approval_id", externalApprovalId)
.eq(StrUtil.isNotEmpty(code), "ra.code", code)
.eq(codeCheck != null, "ra.code_check", codeCheck)
.eq(approvalType != null, "ra.approval_type", approvalType)
.eq(StrUtil.isNotEmpty(corpid), "ra.corpid", corpid)
.eq(StrUtil.isNotEmpty(applyUserid), "ra.apply_userid", applyUserid)
.eq(StrUtil.isNotEmpty(applyUserName), "ra.apply_user_name", applyUserName)
.eq(StrUtil.isNotEmpty(auditUserid), "ra.audit_userid", auditUserid)
.like(StrUtil.isNotEmpty(goodsName), "sog.goods_name", goodsName)
.between(startTime != null && endTime != null, "ra.create_time", startTime, endTime)

View File

@ -0,0 +1,66 @@
package com.agileboot.domain.shop.approval.query;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.core.page.AbstractPageQuery;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@EqualsAndHashCode(callSuper = true)
@Data
public class SearchReturnApprovalAssetQuery<T> extends AbstractPageQuery<T> {
private Long approvalId;
private Long orderId;
private Long goodsId;
private Integer status;
private Long externalGoodsId;
private Long externalApprovalId;
private String code;
private Integer codeCheck;
private String corpid;
private String applyUserid;
private String applyUserName;
private String auditUserid;
private Integer applyQuantity;
private Integer approvalType;
private String applyRemark;
private String returnRemark;
private String auditRemark;
private Date startTime;
private Date endTime;
private String paymentMethod;
private Date approvalTime;
@Override
public QueryWrapper<T> addQueryCondition() {
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
queryWrapper
.eq(approvalId != null, "approval_id", approvalId)
.eq(orderId != null, "order_id", orderId)
.eq(goodsId != null, "goods_id", goodsId)
.eq(status != null, "status", status)
.eq(externalGoodsId != null, "external_goods_id", externalGoodsId)
.eq(externalApprovalId != null, "external_approval_id", externalApprovalId)
.eq(StrUtil.isNotEmpty(code), "code", code)
.eq(codeCheck!= null, "code_check", codeCheck)
.eq(approvalType != null, "approval_type", approvalType)
.eq(StrUtil.isNotEmpty(corpid), "corpid", corpid)
.eq(StrUtil.isNotEmpty(applyUserid), "apply_userid", applyUserid)
.eq(StrUtil.isNotEmpty(applyUserName), "apply_user_name", applyUserName)
.eq(StrUtil.isNotEmpty(auditUserid), "audit_userid", auditUserid)
.like(StrUtil.isNotEmpty(returnRemark), "return_remark", returnRemark)
.like(StrUtil.isNotEmpty(auditRemark), "audit_remark", auditRemark)
.between(approvalTime != null, "approval_time",
approvalTime == null ? null : DateUtil.beginOfDay(approvalTime).toJdkDate(),
approvalTime == null ? null : DateUtil.endOfDay(approvalTime).toJdkDate())
.orderByDesc("create_time");
this.timeRangeColumn = "create_time";
return queryWrapper;
}
}

View File

@ -21,6 +21,7 @@ public class SearchReturnApprovalQuery<T> extends AbstractPageQuery<T> {
private String code;
private String corpid;
private String applyUserid;
private String applyUserName;
private String auditUserid;
private Integer applyQuantity;
private Integer approvalType;
@ -47,6 +48,7 @@ public class SearchReturnApprovalQuery<T> extends AbstractPageQuery<T> {
.eq(approvalType != null, "ra.approval_type", approvalType)
.eq(StrUtil.isNotEmpty(corpid), "ra.corpid", corpid)
.eq(StrUtil.isNotEmpty(applyUserid), "ra.apply_userid", applyUserid)
.eq(StrUtil.isNotEmpty(applyUserName), "ra.apply_user_name", applyUserName)
.eq(StrUtil.isNotEmpty(auditUserid), "ra.audit_userid", auditUserid)
.like(StrUtil.isNotEmpty(returnRemark), "ra.return_remark", returnRemark)
.like(StrUtil.isNotEmpty(auditRemark), "ra.audit_remark", auditRemark)

View File

@ -64,6 +64,10 @@ public class ApprovalGoodsEntity extends BaseEntity<ApprovalGoodsEntity> {
@TableField("apply_quantity")
private Integer applyQuantity;
@ApiModelProperty("审批数量")
@TableField("approval_quantity")
private Integer approvalQuantity;
@ApiModelProperty("封面图URL")
@TableField("cover_img")
private String coverImg;

View File

@ -46,6 +46,9 @@ public class ApprovalGoodsDTO {
@ExcelColumn(name = "申请数量")
private Integer applyQuantity;
@ExcelColumn(name = "审批数量")
private Integer approvalQuantity;
@ExcelColumn(name = "封面图URL")
private String coverImg;
}

View File

@ -25,3 +25,41 @@ AFTER `balance_enable`;
ALTER TABLE `return_approval`
ADD COLUMN `code` varchar(32) DEFAULT NULL COMMENT '审批码'
AFTER `external_approval_id`;
ALTER TABLE `return_approval`
ADD COLUMN `code_check` TINYINT NOT NULL DEFAULT 0 COMMENT '审批码校验 0未核销 1已核销'
AFTER `code`;
ALTER TABLE `return_approval`
ADD COLUMN `apply_user_name` varchar(30) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '申请人'
AFTER `apply_userid`;
ALTER TABLE `approval_goods`
ADD COLUMN `approval_quantity` int DEFAULT NULL COMMENT '审批数量'
AFTER `apply_quantity`;
CREATE TABLE `approval_goods_cell` (
`approval_goods_cell_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`approval_id` bigint NOT NULL COMMENT '审批ID',
`approval_goods_id` bigint NOT NULL COMMENT '申请领用商品ID',
`shop_id` bigint NULL COMMENT '商店ID',
`cabinet_id` bigint NOT NULL COMMENT '柜机ID',
`cell_id` bigint NOT NULL COMMENT '格口ID',
`allocate_quantity` int NOT NULL COMMENT '分配数量',
`shop_name` varchar(100) NULL COMMENT '商店名称',
`cabinet_name` varchar(100) NULL COMMENT '柜机名称',
`cell_no` int NULL COMMENT '格口号',
`creator_id` bigint NULL DEFAULT '0' COMMENT '创建者ID',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater_id` bigint NULL DEFAULT '0' COMMENT '更新者ID',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标志0存在 1删除',
PRIMARY KEY (`approval_goods_cell_id`),
UNIQUE KEY `uk_approval_goods_cell` (`approval_goods_id`, `cell_id`),
KEY `idx_approval_id` (`approval_id`),
KEY `idx_approval_goods_id` (`approval_goods_id`),
KEY `idx_shop_id` (`shop_id`),
KEY `idx_cabinet_id` (`cabinet_id`),
KEY `idx_cell_id` (`cell_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='申请领用商品格口分配表';