feat:添加盘点记录及导出接口

main
HuangHuiKang 2 weeks ago
parent 3aaf69cf8e
commit bd02378ab7

@ -10,16 +10,10 @@ import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckApproveRecordRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckAuditReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckGenerateByLocationReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckGenerateByProductReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckSubmitReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.*;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckApproveRecordDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO;
@ -186,6 +180,64 @@ public class ErpStockCheckController {
ExcelUtils.write(response, "库存盘点单.xls", "数据", ErpStockCheckRespVO.class, list);
}
@GetMapping("/record-page")
@Operation(summary = "获得库存盘点记录分页")
@PreAuthorize("@ss.hasPermission('erp:stock-check:query')")
public CommonResult<PageResult<ErpStockCheckRecordRespVO>> getStockCheckRecordPage(
@Valid ErpStockCheckRecordPageReqVO pageReqVO) {
return success(buildStockCheckRecordVOPageResult(stockCheckService.getStockCheckRecordPage(pageReqVO)));
}
@GetMapping("/record-export-excel")
@Operation(summary = "导出库存盘点记录 Excel")
@PreAuthorize("@ss.hasPermission('erp:stock-check:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportStockCheckRecordExcel(@Valid ErpStockCheckRecordPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<ErpStockCheckRecordRespVO> list = buildStockCheckRecordVOPageResult(
stockCheckService.getStockCheckRecordPage(pageReqVO)).getList();
ExcelUtils.write(response, "库存盘点记录.xls", "数据", ErpStockCheckRecordRespVO.class, list);
}
private PageResult<ErpStockCheckRecordRespVO> buildStockCheckRecordVOPageResult(PageResult<ErpStockCheckItemDO> pageResult) {
if (CollUtil.isEmpty(pageResult.getList())) {
return PageResult.empty(pageResult.getTotal());
}
Map<Long, ErpStockCheckDO> stockCheckMap = stockCheckService.getStockCheckMap(
convertSet(pageResult.getList(), ErpStockCheckItemDO::getCheckId));
Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(
convertSet(pageResult.getList(), ErpStockCheckItemDO::getProductId));
Map<Long, ErpProductUnitDO> unitMap = productUnitService.getProductUnitMap(convertSet(productMap.values(), ErpProductRespVO::getUnitId));
Map<Long, ErpWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(
convertSet(pageResult.getList(), ErpStockCheckItemDO::getWarehouseId));
Map<Long, WarehouseAreaDO> areaMap = warehouseAreaService.getWarehouseAreaMap(
convertSet(pageResult.getList(), ErpStockCheckItemDO::getAreaId));
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(stockCheckMap.values(),
stockCheck -> Stream.of(NumberUtils.parseLong(stockCheck.getCreator()))));
return BeanUtils.toBean(pageResult, ErpStockCheckRecordRespVO.class, record -> {
MapUtils.findAndThen(stockCheckMap, record.getCheckId(), stockCheck -> {
record.setNo(stockCheck.getNo())
.setCheckTime(stockCheck.getCheckTime())
.setSourceType(stockCheck.getSourceType())
.setCategoryType(stockCheck.getCategoryType())
.setCheckStatus(stockCheck.getCheckStatus())
.setStatus(stockCheck.getStatus())
.setCreator(stockCheck.getCreator())
.setCreateTime(stockCheck.getCreateTime());
MapUtils.findAndThen(userMap, NumberUtils.parseLong(stockCheck.getCreator()), user -> record.setCreatorName(user.getNickname()));
});
MapUtils.findAndThen(productMap, record.getProductId(), product -> record.setProductName(product.getName())
.setProductBarCode(product.getBarCode()).setCategoryName(product.getCategoryName()));
MapUtils.findAndThen(productMap, record.getProductId(), product ->
MapUtils.findAndThen(unitMap, product.getUnitId(), unit -> record.setProductUnitName(unit.getName())));
MapUtils.findAndThen(warehouseMap, record.getWarehouseId(), warehouse -> record.setWarehouseName(warehouse.getName()));
if (record.getAreaName() == null) {
MapUtils.findAndThen(areaMap, record.getAreaId(), area -> record.setAreaName(area.getAreaName()));
}
});
}
private PageResult<ErpStockCheckRespVO> buildStockCheckVOPageResult(PageResult<ErpStockCheckDO> pageResult) {
if (CollUtil.isEmpty(pageResult.getList())) {
return PageResult.empty(pageResult.getTotal());

@ -0,0 +1,54 @@
package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - ERP 库存盘点记录分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ErpStockCheckRecordPageReqVO extends PageParam {
@Schema(description = "盘点单号", example = "QCPD20260623001")
private String no;
@Schema(description = "盘点时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] checkTime;
@Schema(description = "生成来源类型1-按库存2-按产品", example = "1")
private Integer sourceType;
@Schema(description = "产品分类类型", example = "1")
private Integer categoryType;
@Schema(description = "盘点状态0-未盘点1-已盘点", example = "1")
private Integer checkStatus;
@Schema(description = "审核状态", example = "20")
private Integer status;
@Schema(description = "产品编号", example = "1")
private Long productId;
@Schema(description = "仓库编号", example = "1")
private Long warehouseId;
@Schema(description = "库区编号", example = "1")
private Long areaId;
@Schema(description = "创建人")
private String creator;
@Schema(description = "盘点记录项 id 集合,导出使用")
private String ids;
}

@ -0,0 +1,124 @@
package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.module.erp.enums.DictTypeConstants;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.module.erp.enums.DictTypeConstants.AUDIT_STATUS;
import static cn.iocoder.yudao.module.erp.enums.DictTypeConstants.PRODUCT_CATEGORY_TYPE;
@Schema(description = "管理后台 - ERP 库存盘点记录 Response VO")
@Data
@ExcelIgnoreUnannotated
public class ErpStockCheckRecordRespVO {
@Schema(description = "盘点记录项编号", example = "11756")
@ExcelProperty("盘点记录项编号")
private Long id;
@Schema(description = "盘点单编号", example = "11756")
private Long checkId;
@Schema(description = "盘点单号", example = "QCPD20260623001")
@ExcelProperty("盘点单号")
private String no;
@Schema(description = "盘点时间")
@ExcelProperty("盘点时间")
private LocalDateTime checkTime;
@Schema(description = "生成来源类型1-按库存2-按产品", example = "1")
@ExcelProperty(value = "生成来源类型", converter = DictConvert.class)
@DictFormat("erp_stock_check_source_type")
private Integer sourceType;
@Schema(description = "产品分类类型", example = "1")
@ExcelProperty(value = "产品分类类型", converter = DictConvert.class)
@DictFormat(PRODUCT_CATEGORY_TYPE)
private Integer categoryType;
@Schema(description = "盘点状态0-未盘点1-已盘点", example = "1")
@ExcelProperty("盘点状态")
private Integer checkStatus;
@Schema(description = "审核状态", example = "20")
@ExcelProperty(value = "审核状态", converter = DictConvert.class)
@DictFormat(AUDIT_STATUS)
private Integer status;
@Schema(description = "产品编号", example = "3113")
private Long productId;
@Schema(description = "产品名称", example = "苹果")
@ExcelProperty("产品名称")
private String productName;
@Schema(description = "产品条码", example = "A9985")
@ExcelProperty("产品条码")
private String productBarCode;
@Schema(description = "产品分类", example = "水果")
@ExcelProperty("产品分类")
private String categoryName;
@Schema(description = "产品单位名称", example = "个")
@ExcelProperty("单位")
private String productUnitName;
@Schema(description = "仓库编号", example = "3113")
private Long warehouseId;
@Schema(description = "仓库名称", example = "成品仓")
@ExcelProperty("仓库名称")
private String warehouseName;
@Schema(description = "库区编号", example = "1")
private Long areaId;
@Schema(description = "库区名称", example = "A区")
@ExcelProperty("库区名称")
private String areaName;
@Schema(description = "产品单价", example = "100.00")
@ExcelProperty("产品单价")
private BigDecimal productPrice;
@Schema(description = "账面数量", example = "100.00")
@ExcelProperty("账面数量")
private BigDecimal stockCount;
@Schema(description = "实际数量", example = "95.00")
@ExcelProperty("实际数量")
private BigDecimal actualCount;
@Schema(description = "盈亏数量", example = "-5.00")
@ExcelProperty("盈亏数量")
private BigDecimal count;
@Schema(description = "合计金额", example = "500.00")
@ExcelProperty("合计金额")
private BigDecimal totalPrice;
@Schema(description = "备注", example = "随便")
@ExcelProperty("备注")
private String remark;
@Schema(description = "创建人", example = "1")
private String creator;
@Schema(description = "创建人名称", example = "张三")
@ExcelProperty("创建人")
private String creatorName;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

@ -1,11 +1,18 @@
package cn.iocoder.yudao.module.erp.dal.mysql.stock;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckRecordPageReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO;
import com.alibaba.excel.util.StringUtils;
import org.apache.ibatis.annotations.Mapper;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* ERP Mapper
@ -15,6 +22,56 @@ import java.util.List;
@Mapper
public interface ErpStockCheckItemMapper extends BaseMapperX<ErpStockCheckItemDO> {
DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
default PageResult<ErpStockCheckItemDO> selectRecordPage(ErpStockCheckRecordPageReqVO reqVO) {
LambdaQueryWrapperX<ErpStockCheckItemDO> query = new LambdaQueryWrapperX<ErpStockCheckItemDO>()
.eqIfPresent(ErpStockCheckItemDO::getProductId, reqVO.getProductId())
.eqIfPresent(ErpStockCheckItemDO::getWarehouseId, reqVO.getWarehouseId())
.eqIfPresent(ErpStockCheckItemDO::getAreaId, reqVO.getAreaId())
.orderByDesc(ErpStockCheckItemDO::getId);
query.inSql(ErpStockCheckItemDO::getCheckId, buildCheckFilterSql(reqVO));
if (StringUtils.isNotBlank(reqVO.getIds())) {
List<Long> idList = Arrays.stream(reqVO.getIds().split(","))
.map(String::trim)
.map(Long::valueOf)
.collect(Collectors.toList());
query.in(ErpStockCheckItemDO::getId, idList);
}
return selectPage(reqVO, query);
}
default String buildCheckFilterSql(ErpStockCheckRecordPageReqVO reqVO) {
StringBuilder checkFilterSql = new StringBuilder("select id from erp_stock_check where deleted = 0");
if (StringUtils.isNotBlank(reqVO.getNo())) {
checkFilterSql.append(" and no like '%").append(reqVO.getNo().replace("'", "''")).append("%'");
}
if (reqVO.getCheckTime() != null && reqVO.getCheckTime().length == 2) {
if (reqVO.getCheckTime()[0] != null) {
checkFilterSql.append(" and check_time >= '").append(DATE_TIME_FORMATTER.format(reqVO.getCheckTime()[0])).append("'");
}
if (reqVO.getCheckTime()[1] != null) {
checkFilterSql.append(" and check_time <= '").append(DATE_TIME_FORMATTER.format(reqVO.getCheckTime()[1])).append("'");
}
}
if (reqVO.getSourceType() != null) {
checkFilterSql.append(" and source_type = ").append(reqVO.getSourceType());
}
if (reqVO.getCategoryType() != null) {
checkFilterSql.append(" and category_type = ").append(reqVO.getCategoryType());
}
if (reqVO.getCheckStatus() != null) {
checkFilterSql.append(" and check_status = ").append(reqVO.getCheckStatus());
}
if (reqVO.getStatus() != null) {
checkFilterSql.append(" and status = ").append(reqVO.getStatus());
}
if (StringUtils.isNotBlank(reqVO.getCreator())) {
checkFilterSql.append(" and creator = '").append(reqVO.getCreator().replace("'", "''")).append("'");
}
return checkFilterSql.toString();
}
default List<ErpStockCheckItemDO> selectListByCheckId(Long checkId) {
return selectList(ErpStockCheckItemDO::getCheckId, checkId);
}
@ -27,4 +84,4 @@ public interface ErpStockCheckItemMapper extends BaseMapperX<ErpStockCheckItemDO
return delete(ErpStockCheckItemDO::getCheckId, checkId);
}
}
}

@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheck
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckGenerateByLocationReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckGenerateByProductReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckRecordPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckSubmitReqVO;
@ -15,6 +16,9 @@ import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO;
import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
/**
* ERP Service
@ -65,6 +69,12 @@ public interface ErpStockCheckService {
*/
ErpStockCheckDO getStockCheck(Long id);
default Map<Long, ErpStockCheckDO> getStockCheckMap(Collection<Long> ids) {
return convertMap(getStockCheckList(ids), ErpStockCheckDO::getId);
}
List<ErpStockCheckDO> getStockCheckList(Collection<Long> ids);
/**
*
*
@ -73,6 +83,8 @@ public interface ErpStockCheckService {
*/
PageResult<ErpStockCheckDO> getStockCheckPage(ErpStockCheckPageReqVO pageReqVO);
PageResult<ErpStockCheckItemDO> getStockCheckRecordPage(ErpStockCheckRecordPageReqVO pageReqVO);
// ==================== 盘点项 ====================
/**

@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheck
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckGenerateByLocationReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckGenerateByProductReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckRecordPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckSubmitReqVO;
@ -30,9 +31,7 @@ import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO;
import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus;
import cn.iocoder.yudao.module.erp.enums.stock.ErpStockCheckApproveActionEnum;
import cn.iocoder.yudao.module.erp.enums.stock.ErpStockCheckSourceTypeEnum;
import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO;
import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService;
import cn.iocoder.yudao.module.infra.api.config.ConfigApi;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
@ -83,7 +82,7 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
@Resource
private WarehouseAreaService warehouseAreaService;
@Resource
private ErpStockRecordService stockRecordService;
private ErpStockService stockService;
@Resource
private AdminUserApi adminUserApi;
@Resource
@ -286,11 +285,24 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
return stockCheckMapper.selectById(id);
}
@Override
public List<ErpStockCheckDO> getStockCheckList(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return Collections.emptyList();
}
return stockCheckMapper.selectBatchIds(ids);
}
@Override
public PageResult<ErpStockCheckDO> getStockCheckPage(ErpStockCheckPageReqVO pageReqVO) {
return stockCheckMapper.selectPage(pageReqVO);
}
@Override
public PageResult<ErpStockCheckItemDO> getStockCheckRecordPage(ErpStockCheckRecordPageReqVO pageReqVO) {
return stockCheckItemMapper.selectRecordPage(pageReqVO);
}
@Override
public List<ErpStockCheckItemDO> getStockCheckItemListByCheckId(Long checkId) {
return stockCheckItemMapper.selectListByCheckId(checkId);
@ -404,25 +416,13 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
return;
}
BigDecimal count = approve ? stockCheckItem.getCount() : stockCheckItem.getCount().negate();
Integer bizType;
if (approve) {
bizType = stockCheckItem.getCount().compareTo(BigDecimal.ZERO) > 0
? ErpStockRecordBizTypeEnum.CHECK_MORE_IN.getType()
: ErpStockRecordBizTypeEnum.CHECK_LESS_OUT.getType();
} else {
bizType = stockCheckItem.getCount().compareTo(BigDecimal.ZERO) > 0
? ErpStockRecordBizTypeEnum.CHECK_MORE_IN_CANCEL.getType()
: ErpStockRecordBizTypeEnum.CHECK_LESS_OUT_CANCEL.getType();
}
ErpProductDO productDO = productService.validProductList(Collections.singleton(stockCheckItem.getProductId()))
.stream().findFirst().orElse(null);
if (productDO == null) {
return;
}
stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO(
stockCheckItem.getProductId(), productDO.getCategoryId(), null,
stockCheckItem.getWarehouseId(), stockCheckItem.getAreaId(), stockCheckItem.getAreaName(),
count, bizType, stockCheckItem.getCheckId(), stockCheckItem.getId(), stockCheck.getNo(), stockCheck.getCheckTime()));
stockService.updateStockCountIncrement(productDO.getCategoryId(), stockCheckItem.getProductId(),
stockCheckItem.getWarehouseId(), stockCheckItem.getAreaId(), stockCheckItem.getAreaName(), count);
});
}

@ -100,7 +100,8 @@ public class DeviceLedgerPageReqVO extends PageParam {
private Long productId;
@Schema(description = "出厂日期")
private LocalDateTime outgoingTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDateTime[] outgoingTime;
@Schema(description = "序列号")
private String sn;

@ -56,6 +56,7 @@ public interface DeviceLedgerMapper extends BaseMapperX<DeviceLedgerDO> {
.eqIfPresent(DeviceLedgerDO::getSort, reqVO.getSort())
.eqIfPresent(DeviceLedgerDO::getIsScheduled, reqVO.getIsScheduled())
.betweenIfPresent(DeviceLedgerDO::getCreateTime, reqVO.getCreateTime())
.betweenIfPresent(DeviceLedgerDO::getOutgoingTime, reqVO.getOutgoingTime())
.orderByDesc(DeviceLedgerDO::getCreateTime);
if (reqVO.getDeviceLineIds() != null && !reqVO.getDeviceLineIds().isEmpty()) {

Loading…
Cancel
Save