ck-chenkang 6 days ago
commit 0124acdf5c

@ -101,6 +101,8 @@ public interface ErrorCodeConstants {
ErrorCode WAREHOUSE_LOCATION_CODE_EXISTS = new ErrorCode(1_030_400_005, "库位编码不存在"); ErrorCode WAREHOUSE_LOCATION_CODE_EXISTS = new ErrorCode(1_030_400_005, "库位编码不存在");
ErrorCode WAREHOUSE_LOCATION_NOT_EXISTS = new ErrorCode(1_030_400_006, "库位不存在"); ErrorCode WAREHOUSE_LOCATION_NOT_EXISTS = new ErrorCode(1_030_400_006, "库位不存在");
ErrorCode WAREHOUSE_LOCATION_WAREHOUSE_AREA_NOT_MATCH = new ErrorCode(1_030_400_007, "暂无匹配库位信息"); ErrorCode WAREHOUSE_LOCATION_WAREHOUSE_AREA_NOT_MATCH = new ErrorCode(1_030_400_007, "暂无匹配库位信息");
ErrorCode PALLET_NOT_EXISTS = new ErrorCode(1_030_400_008, "托盘不存在");
ErrorCode PALLET_CODE_EXISTS = new ErrorCode(1_030_400_009, "托盘编码已存在");
// ========== ERP 其它入库单 1-030-401-000 ========== // ========== ERP 其它入库单 1-030-401-000 ==========
ErrorCode STOCK_IN_NOT_EXISTS = new ErrorCode(1_030_401_000, "其它入库单不存在"); ErrorCode STOCK_IN_NOT_EXISTS = new ErrorCode(1_030_401_000, "其它入库单不存在");
@ -160,6 +162,9 @@ public interface ErrorCodeConstants {
ErrorCode STOCK_CHECK_AUDIT_FAIL_STATUS = new ErrorCode(1_030_403_011, "审核失败,只有审核中的盘点单才能审核"); ErrorCode STOCK_CHECK_AUDIT_FAIL_STATUS = new ErrorCode(1_030_403_011, "审核失败,只有审核中的盘点单才能审核");
ErrorCode STOCK_CHECK_AUDIT_FAIL_USER = new ErrorCode(1_030_403_012, "审核失败,当前用户不是指定审核人"); ErrorCode STOCK_CHECK_AUDIT_FAIL_USER = new ErrorCode(1_030_403_012, "审核失败,当前用户不是指定审核人");
ErrorCode STOCK_CHECK_AUDIT_FAIL_RESULT = new ErrorCode(1_030_403_013, "审核失败,审核结果只支持通过或驳回"); ErrorCode STOCK_CHECK_AUDIT_FAIL_RESULT = new ErrorCode(1_030_403_013, "审核失败,审核结果只支持通过或驳回");
ErrorCode STOCK_CHECK_SOURCE_TYPE_NOT_EXISTS = new ErrorCode(1_030_403_014, "盘点单生成来源类型不存在");
ErrorCode STOCK_CODE_EXISTS = new ErrorCode(1_030_403_014, "盘点单编码已存在");
// ========== ERP 产品库存 1-030-404-000 ========== // ========== ERP 产品库存 1-030-404-000 ==========
ErrorCode STOCK_COUNT_NEGATIVE = new ErrorCode(1_030_404_000, "操作失败,产品({})所在仓库({})的库存:{},小于变更数量:{}"); ErrorCode STOCK_COUNT_NEGATIVE = new ErrorCode(1_030_404_000, "操作失败,产品({})所在仓库({})的库存:{},小于变更数量:{}");

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.erp.enums.stock;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
@RequiredArgsConstructor
@Getter
public enum ErpStockCheckSourceTypeEnum implements IntArrayValuable {
BY_LOCATION(1, "按库存"),
BY_PRODUCT(2, "按产品");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpStockCheckSourceTypeEnum::getType).toArray();
private final Integer type;
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}

@ -0,0 +1,82 @@
package cn.iocoder.yudao.module.erp.controller.admin.pallet;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.pallet.ErpPalletDO;
import cn.iocoder.yudao.module.erp.service.pallet.ErpPalletService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@Tag(name = "管理后台 - ERP 托盘")
@RestController
@RequestMapping("/erp/pallet")
@Validated
public class ErpPalletController {
@Resource
private ErpPalletService palletService;
@PostMapping("/create")
@Operation(summary = "创建托盘")
@PreAuthorize("@ss.hasPermission('erp:pallet:create')")
public CommonResult<Long> createPallet(@Valid @RequestBody ErpPalletSaveReqVO createReqVO) {
return success(palletService.createPallet(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新托盘")
@PreAuthorize("@ss.hasPermission('erp:pallet:update')")
public CommonResult<Boolean> updatePallet(@Valid @RequestBody ErpPalletSaveReqVO updateReqVO) {
palletService.updatePallet(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除托盘")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('erp:pallet:delete')")
public CommonResult<Boolean> deletePallet(@RequestParam("id") Long id) {
palletService.deletePallet(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得托盘")
@Parameter(name = "id", description = "编号", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('erp:pallet:query')")
public CommonResult<ErpPalletRespVO> getPallet(@RequestParam("id") Long id) {
ErpPalletDO pallet = palletService.getPallet(id);
return success(BeanUtils.toBean(pallet, ErpPalletRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得托盘分页")
@PreAuthorize("@ss.hasPermission('erp:pallet:query')")
public CommonResult<PageResult<ErpPalletRespVO>> getPalletPage(@Valid ErpPalletPageReqVO pageReqVO) {
PageResult<ErpPalletDO> pageResult = palletService.getPalletPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, ErpPalletRespVO.class));
}
@GetMapping("/simple-list")
@Operation(summary = "获得托盘精简列表")
@Parameter(name = "status", description = "托盘状态", example = "1")
public CommonResult<List<ErpPalletRespVO>> getPalletSimpleList(@RequestParam(value = "status", required = false) Integer status) {
List<ErpPalletDO> list = palletService.getPalletListByStatus(status);
return success(convertList(list, item -> BeanUtils.toBean(item, ErpPalletRespVO.class)));
}
}

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.erp.controller.admin.pallet.enums;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
@Getter
@AllArgsConstructor
public enum ErpPalletStatusEnum implements IntArrayValuable {
IDLE(1, "空闲"),
OCCUPIED(2, "占用"),
SCRAPPED(3, "报废");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpPalletStatusEnum::getStatus).toArray();
private final Integer status;
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.erp.controller.admin.pallet.enums;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
@Getter
@AllArgsConstructor
public enum ErpPalletTypeEnum implements IntArrayValuable {
PLASTIC(1, "塑料"),
STEEL(2, "钢质"),
WOOD(3, "木托盘");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpPalletTypeEnum::getType).toArray();
private final Integer type;
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}

@ -0,0 +1,59 @@
package cn.iocoder.yudao.module.erp.controller.admin.pallet.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.erp.controller.admin.pallet.enums.ErpPalletStatusEnum;
import cn.iocoder.yudao.module.erp.controller.admin.pallet.enums.ErpPalletTypeEnum;
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.LocalDate;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
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 ErpPalletPageReqVO extends PageParam {
@Schema(description = "托盘编码", example = "TP202506100001")
private String code;
@Schema(description = "托盘类型", example = "1")
@InEnum(ErpPalletTypeEnum.class)
private Integer palletType;
@Schema(description = "托盘状态", example = "1")
@InEnum(ErpPalletStatusEnum.class)
private Integer status;
@Schema(description = "仓库编号", example = "1")
private Long warehouseId;
@Schema(description = "库区编号", example = "11")
private Long areaId;
@Schema(description = "生产任务单号", example = "PLAN20250610001")
private String planCode;
@Schema(description = "产品编号", example = "1001")
private Long productId;
@Schema(description = "采购日期")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate[] purchaseDate;
@Schema(description = "投入使用日期")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate[] useDate;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

@ -0,0 +1,84 @@
package cn.iocoder.yudao.module.erp.controller.admin.pallet.vo;
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.LocalDate;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - ERP 托盘 Response VO")
@Data
@ExcelIgnoreUnannotated
public class ErpPalletRespVO {
@Schema(description = "托盘编号", example = "1")
@ExcelProperty("托盘编号")
private Long id;
@Schema(description = "托盘编码", example = "TP202506100001")
@ExcelProperty("托盘编码")
private String code;
@Schema(description = "托盘类型", example = "1")
@ExcelProperty("托盘类型")
private Integer palletType;
@Schema(description = "托盘规格", example = "1200×1000×150")
@ExcelProperty("托盘规格")
private String specification;
@Schema(description = "额定承载重量", example = "1000")
@ExcelProperty("额定承载重量")
private BigDecimal ratedLoadWeight;
@Schema(description = "单位", example = "kg")
@ExcelProperty("单位")
private String unit;
@Schema(description = "托盘状态", example = "1")
@ExcelProperty("托盘状态")
private Integer status;
@Schema(description = "仓库编号", example = "1")
@ExcelProperty("仓库编号")
private Long warehouseId;
@Schema(description = "库区编号", example = "11")
@ExcelProperty("库区编号")
private Long areaId;
@Schema(description = "生产任务单号", example = "PLAN20250610001")
@ExcelProperty("生产任务单号")
private String planCode;
@Schema(description = "产品编号", example = "1001")
@ExcelProperty("产品编号")
private Long productId;
@Schema(description = "产品数量", example = "120")
@ExcelProperty("产品数量")
private BigDecimal productCount;
@Schema(description = "二维码", example = "https://xxx.com/qrcode/pallet/1")
@ExcelProperty("二维码")
private String qrcode;
@Schema(description = "采购日期", example = "2025-06-10")
@ExcelProperty("采购日期")
private LocalDate purchaseDate;
@Schema(description = "投入使用日期", example = "2025-06-11")
@ExcelProperty("投入使用日期")
private LocalDate useDate;
@Schema(description = "备注", example = "用于成品周转")
@ExcelProperty("备注")
private String remark;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

@ -0,0 +1,73 @@
package cn.iocoder.yudao.module.erp.controller.admin.pallet.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.erp.controller.admin.pallet.enums.ErpPalletStatusEnum;
import cn.iocoder.yudao.module.erp.controller.admin.pallet.enums.ErpPalletTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@Schema(description = "管理后台 - ERP 托盘新增/修改 Request VO")
@Data
public class ErpPalletSaveReqVO {
@Schema(description = "托盘编号", example = "1")
private Long id;
@Schema(description = "托盘编码", example = "TP202506100001")
private String code;
@Schema(description = "托盘类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "托盘类型不能为空")
@InEnum(ErpPalletTypeEnum.class)
private Integer palletType;
@Schema(description = "托盘规格(长×宽×高)", example = "1200×1000×150")
private String specification;
@Schema(description = "额定承载重量", example = "1000")
private BigDecimal ratedLoadWeight;
@Schema(description = "单位", example = "kg")
private String unit;
@Schema(description = "托盘状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "托盘状态不能为空")
@InEnum(ErpPalletStatusEnum.class)
private Integer status;
@Schema(description = "仓库编号", example = "1")
private Long warehouseId;
@Schema(description = "库区编号", example = "11")
private Long areaId;
@Schema(description = "生产任务单号", example = "PLAN20250610001")
private String planCode;
@Schema(description = "产品编号", example = "1001")
private Long productId;
@Schema(description = "产品数量", example = "120")
private BigDecimal productCount;
@Schema(description = "二维码", example = "https://xxx.com/qrcode/pallet/1")
private String qrcode;
@Schema(description = "采购日期", example = "2025-06-10")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate purchaseDate;
@Schema(description = "投入使用日期", example = "2025-06-11")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
private LocalDate useDate;
@Schema(description = "备注", example = "用于成品周转")
private String remark;
}

@ -10,7 +10,8 @@ import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; 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.ErpStockCheckApproveRecordRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckAuditReqVO; 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.ErpStockCheckGenerateByLocationReqVO;
@ -25,6 +26,7 @@ import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.warehousearea.WarehouseAreaDO; import cn.iocoder.yudao.module.erp.dal.dataobject.warehousearea.WarehouseAreaDO;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService; import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService;
import cn.iocoder.yudao.module.erp.service.stock.ErpStockCheckService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockCheckService;
import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService;
import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService; import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService;
@ -71,6 +73,8 @@ public class ErpStockCheckController {
@Resource @Resource
private ErpProductService productService; private ErpProductService productService;
@Resource @Resource
private ErpProductUnitService productUnitService;
@Resource
private ErpWarehouseService warehouseService; private ErpWarehouseService warehouseService;
@Resource @Resource
private WarehouseAreaService warehouseAreaService; private WarehouseAreaService warehouseAreaService;
@ -189,10 +193,12 @@ public class ErpStockCheckController {
List<ErpStockCheckItemDO> stockCheckItemList = stockCheckService.getStockCheckItemListByCheckIds( List<ErpStockCheckItemDO> stockCheckItemList = stockCheckService.getStockCheckItemListByCheckIds(
convertSet(pageResult.getList(), ErpStockCheckDO::getId)); convertSet(pageResult.getList(), ErpStockCheckDO::getId));
Map<Long, List<ErpStockCheckItemDO>> stockCheckItemMap = convertMultiMap(stockCheckItemList, ErpStockCheckItemDO::getCheckId); Map<Long, List<ErpStockCheckItemDO>> stockCheckItemMap = convertMultiMap(stockCheckItemList, ErpStockCheckItemDO::getCheckId);
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(pageResult.getList(),
stockCheck -> Stream.of(NumberUtils.parseLong(stockCheck.getCreator()), stockCheck.getAuditUserId())));
return BeanUtils.toBean(pageResult, ErpStockCheckRespVO.class, stockCheck -> { return BeanUtils.toBean(pageResult, ErpStockCheckRespVO.class, stockCheck -> {
stockCheck.setItems(buildItemRespList(stockCheckItemMap.get(stockCheck.getId()))); stockCheck.setItems(buildItemRespList(stockCheckItemMap.get(stockCheck.getId())));
stockCheck.setProductNames(CollUtil.join(stockCheck.getItems(), ",", ErpStockCheckRespVO.Item::getProductName)); stockCheck.setProductNames(CollUtil.join(stockCheck.getItems(), ",", ErpStockCheckRespVO.Item::getProductName));
fillUserInfo(stockCheck); fillUserInfo(stockCheck, userMap);
}); });
} }
@ -210,12 +216,18 @@ public class ErpStockCheckController {
if (CollUtil.isEmpty(itemList)) { if (CollUtil.isEmpty(itemList)) {
return new ArrayList<>(); return new ArrayList<>();
} }
Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(convertSet(itemList, ErpStockCheckItemDO::getProductId)); Map<Long, ErpProductDO> productMap = productService.getProductMap(convertSet(itemList, ErpStockCheckItemDO::getProductId));
Map<Long, ErpProductUnitDO> unitMap = productUnitService.getProductUnitMap(convertSet(itemList, item -> {
ErpProductDO product = productMap.get(item.getProductId());
return product != null ? product.getUnitId() : null;
}));
Map<Long, ErpWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(convertSet(itemList, ErpStockCheckItemDO::getWarehouseId)); Map<Long, ErpWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(convertSet(itemList, ErpStockCheckItemDO::getWarehouseId));
Map<Long, WarehouseAreaDO> areaMap = warehouseAreaService.getWarehouseAreaMap(convertSet(itemList, ErpStockCheckItemDO::getAreaId)); Map<Long, WarehouseAreaDO> areaMap = warehouseAreaService.getWarehouseAreaMap(convertSet(itemList, ErpStockCheckItemDO::getAreaId));
return BeanUtils.toBean(itemList, ErpStockCheckRespVO.Item.class, item -> { return BeanUtils.toBean(itemList, ErpStockCheckRespVO.Item.class, item -> {
MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName())
.setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); .setProductBarCode(product.getBarCode()));
MapUtils.findAndThen(productMap, item.getProductId(), product ->
MapUtils.findAndThen(unitMap, product.getUnitId(), unit -> item.setProductUnitName(unit.getName())));
MapUtils.findAndThen(warehouseMap, item.getWarehouseId(), warehouse -> item.setWarehouseName(warehouse.getName())); MapUtils.findAndThen(warehouseMap, item.getWarehouseId(), warehouse -> item.setWarehouseName(warehouse.getName()));
if (item.getAreaName() == null) { if (item.getAreaName() == null) {
MapUtils.findAndThen(areaMap, item.getAreaId(), area -> item.setAreaName(area.getAreaName())); MapUtils.findAndThen(areaMap, item.getAreaId(), area -> item.setAreaName(area.getAreaName()));
@ -228,6 +240,10 @@ public class ErpStockCheckController {
userIds.add(NumberUtils.parseLong(stockCheck.getCreator())); userIds.add(NumberUtils.parseLong(stockCheck.getCreator()));
userIds.add(stockCheck.getAuditUserId()); userIds.add(stockCheck.getAuditUserId());
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
fillUserInfo(stockCheck, userMap);
}
private void fillUserInfo(ErpStockCheckRespVO stockCheck, Map<Long, AdminUserRespDTO> userMap) {
MapUtils.findAndThen(userMap, NumberUtils.parseLong(stockCheck.getCreator()), user -> stockCheck.setCreatorName(user.getNickname())); MapUtils.findAndThen(userMap, NumberUtils.parseLong(stockCheck.getCreator()), user -> stockCheck.setCreatorName(user.getNickname()));
MapUtils.findAndThen(userMap, stockCheck.getAuditUserId(), user -> stockCheck.setAuditUserName(user.getNickname())); MapUtils.findAndThen(userMap, stockCheck.getAuditUserId(), user -> stockCheck.setAuditUserName(user.getNickname()));
} }

@ -5,13 +5,17 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.erp.controller.admin.stock.enums.ErpWarehouseCategoryEnum;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSummaryRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseRespVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSaveReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSaveReqVO;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO;
import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService;
import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseSummaryService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.Parameters;
@ -38,6 +42,8 @@ public class ErpWarehouseController {
@Resource @Resource
private ErpWarehouseService warehouseService; private ErpWarehouseService warehouseService;
@Resource
private ErpWarehouseSummaryService warehouseSummaryService;
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建仓库") @Operation(summary = "创建仓库")
@ -93,10 +99,21 @@ public class ErpWarehouseController {
@GetMapping("/simple-list") @GetMapping("/simple-list")
@Operation(summary = "获得仓库精简列表", description = "只包含被开启的仓库,主要用于前端的下拉选项") @Operation(summary = "获得仓库精简列表", description = "只包含被开启的仓库,主要用于前端的下拉选项")
public CommonResult<List<ErpWarehouseRespVO>> getWarehouseSimpleList() { @Parameter(name = "categoryType", description = "仓库分类", example = "1")
List<ErpWarehouseDO> list = warehouseService.getWarehouseListByStatus(CommonStatusEnum.ENABLE.getStatus()); public CommonResult<List<ErpWarehouseRespVO>> getWarehouseSimpleList(
@RequestParam(value = "categoryType", required = false) Integer categoryType) {
List<ErpWarehouseDO> list = warehouseService.getWarehouseListByStatus(CommonStatusEnum.ENABLE.getStatus(), categoryType);
return success(convertList(list, warehouse -> new ErpWarehouseRespVO().setId(warehouse.getId()) return success(convertList(list, warehouse -> new ErpWarehouseRespVO().setId(warehouse.getId())
.setName(warehouse.getName()).setDefaultStatus(warehouse.getDefaultStatus()))); .setName(warehouse.getName()).setCategoryType(warehouse.getCategoryType())
.setDefaultStatus(warehouse.getDefaultStatus())));
}
@GetMapping("/summary")
@Operation(summary = "获得仓库总览")
@Parameter(name = "warehouseId", description = "仓库编号", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('erp:warehouse:query')")
public CommonResult<ErpWarehouseSummaryRespVO> getWarehouseSummary(@RequestParam("warehouseId") Long warehouseId) {
return success(warehouseSummaryService.getWarehouseSummary(warehouseId));
} }
@GetMapping("/export-excel") @GetMapping("/export-excel")

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.erp.controller.admin.stock.enums;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
@Getter
@AllArgsConstructor
public enum ErpWarehouseCategoryEnum implements IntArrayValuable {
PRODUCT(1, "产品"),
MATERIAL(2, "物料"),
SPARE_PART(3, "备件"),
OTHER(4, "其他");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpWarehouseCategoryEnum::getCategory).toArray();
private final Integer category;
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}

@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.util.List; import java.util.List;
@Schema(description = "管理后台 - ERP 库存盘点按仓库/库区生成盘点项 Request VO") @Schema(description = "管理后台 - ERP 库存盘点按仓库/库区生成盘点项 Request VO")
@ -16,8 +15,8 @@ public class ErpStockCheckGenerateByLocationReqVO {
@Schema(description = "库区编号列表", example = "[11,12]") @Schema(description = "库区编号列表", example = "[11,12]")
private List<Long> areaIds; private List<Long> areaIds;
@Schema(description = "是否允许为空,默认 false", example = "false") @Schema(description = "是否允许为空库存,默认 true", example = "true")
private Boolean allowEmpty; private Boolean allowEmpty = Boolean.TRUE;
public boolean validSelection() { public boolean validSelection() {
return (warehouseIds != null && !warehouseIds.isEmpty()) || (areaIds != null && !areaIds.isEmpty()); return (warehouseIds != null && !warehouseIds.isEmpty()) || (areaIds != null && !areaIds.isEmpty());

@ -14,4 +14,7 @@ public class ErpStockCheckGenerateByProductReqVO {
@NotEmpty(message = "产品编号列表不能为空") @NotEmpty(message = "产品编号列表不能为空")
private List<Long> productIds; private List<Long> productIds;
@Schema(description = "是否允许为空库存,默认 true", example = "true")
private Boolean allowEmpty = Boolean.TRUE;
} }

@ -2,8 +2,14 @@ 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.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import static cn.iocoder.yudao.module.erp.enums.DictTypeConstants.PRODUCT_CATEGORY_TYPE;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
@ -29,8 +35,16 @@ public class ErpStockCheckRespVO {
@Schema(description = "盘点时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "盘点时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("盘点时间") @ExcelProperty("盘点时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime checkTime; private LocalDateTime checkTime;
@Schema(description = "生成来源类型1-按库存2-按产品", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty(value = "生成来源类型", converter = DictConvert.class)
@DictFormat("erp_stock_check_source_type")
private Integer sourceType;
@Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663")
@ExcelProperty("合计数量") @ExcelProperty("合计数量")
private BigDecimal totalCount; private BigDecimal totalCount;
@ -104,8 +118,7 @@ public class ErpStockCheckRespVO {
@NotNull(message = "账面数量不能为空") @NotNull(message = "账面数量不能为空")
private BigDecimal stockCount; private BigDecimal stockCount;
@Schema(description = "实际数量(实际库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") @Schema(description = "实际数量(实际库存)", example = "100.00")
@NotNull(message = "实际数量不能为空")
private BigDecimal actualCount; private BigDecimal actualCount;
@Schema(description = "盈亏数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") @Schema(description = "盈亏数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")

@ -1,6 +1,13 @@
package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check; package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.erp.enums.stock.ErpStockCheckSourceTypeEnum;
import lombok.Data; import lombok.Data;
import javax.validation.Valid; import javax.validation.Valid;
@ -17,17 +24,28 @@ public class ErpStockCheckSaveReqVO {
@Schema(description = "盘点编号", example = "11756") @Schema(description = "盘点编号", example = "11756")
private Long id; private Long id;
@Schema(description = "盘点编码", example = "11756")
private String code;
@Schema(description = "盘点时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "盘点时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "盘点时间不能为空") @NotNull(message = "盘点时间不能为空")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime checkTime; private LocalDateTime checkTime;
@Schema(description = "生成来源类型1-按库存2-按产品", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "生成来源类型不能为空")
@InEnum(ErpStockCheckSourceTypeEnum.class)
private Integer sourceType;
@Schema(description = "备注", example = "随便") @Schema(description = "备注", example = "随便")
private String remark; private String remark;
@Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc")
private String fileUrl; private String fileUrl;
@Schema(description = "盘点项列表", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "盘点项列表", implementation = Item.class)
@NotEmpty(message = "盘点项列表不能为空") @NotEmpty(message = "盘点项列表不能为空")
@Valid @Valid
private List<Item> items; private List<Item> items;
@ -56,8 +74,7 @@ public class ErpStockCheckSaveReqVO {
@NotNull(message = "账面数量不能为空") @NotNull(message = "账面数量不能为空")
private BigDecimal stockCount; private BigDecimal stockCount;
@Schema(description = "实际数量(实际库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") @Schema(description = "实际数量(实际库存)", example = "100.00")
@NotNull(message = "实际数量不能为空")
private BigDecimal actualCount; private BigDecimal actualCount;
@Schema(description = "盈亏数量,服务端自动按 实际数量 - 账面数量 计算", example = "100.00") @Schema(description = "盈亏数量,服务端自动按 实际数量 - 账面数量 计算", example = "100.00")

@ -31,7 +31,7 @@ public class ErpStockInPageReqVO extends PageParam {
private LocalDateTime[] inTime; private LocalDateTime[] inTime;
@Schema(description = "状态", example = "10") @Schema(description = "状态", example = "10")
@InEnum(ErpStockInStatusEnum.class) // @InEnum(ErpStockInStatusEnum.class)
private List<Integer> statusList; private List<Integer> statusList;
@Schema(description = "入库类型", example = "其它入库") @Schema(description = "入库类型", example = "其它入库")

@ -40,7 +40,7 @@ public class ErpStockOutPageReqVO extends PageParam {
private LocalDateTime[] outTime; private LocalDateTime[] outTime;
@Schema(description = "状态", example = "10") @Schema(description = "状态", example = "10")
@InEnum(ErpStockOutStatusEnum.class) // @InEnum(ErpStockOutStatusEnum.class)
private List<Integer> statusList; private List<Integer> statusList;
@Schema(description = "审核人编号", example = "1") @Schema(description = "审核人编号", example = "1")

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.erp.controller.admin.stock.enums.ErpWarehouseCategoryEnum;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -17,10 +18,14 @@ public class ErpWarehousePageReqVO extends PageParam {
@Schema(description = "仓库名称", example = "李四") @Schema(description = "仓库名称", example = "李四")
private String name; private String name;
@Schema(description = "仓库分类", example = "1")
@InEnum(ErpWarehouseCategoryEnum.class)
private Integer categoryType;
@Schema(description = "开启状态", example = "1") @Schema(description = "开启状态", example = "1")
@InEnum(CommonStatusEnum.class) @InEnum(CommonStatusEnum.class)
private Integer status; private Integer status;
@Schema(description = "id集合导出用") @Schema(description = "id集合导出用")
private String ids; private String ids;
} }

@ -27,6 +27,10 @@ public class ErpWarehouseRespVO {
@ExcelProperty("仓库名称") @ExcelProperty("仓库名称")
private String name; private String name;
@Schema(description = "仓库分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty("仓库分类")
private Integer categoryType;
@Schema(description = "仓库地址", example = "上海陆家嘴") @Schema(description = "仓库地址", example = "上海陆家嘴")
@ExcelProperty("仓库地址") @ExcelProperty("仓库地址")
private String address; private String address;
@ -78,5 +82,4 @@ public class ErpWarehouseRespVO {
@Schema(description = "库位列表") @Schema(description = "库位列表")
private List<WarehouseLocationRespVO> locationList; private List<WarehouseLocationRespVO> locationList;
} }

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.erp.controller.admin.stock.enums.ErpWarehouseCategoryEnum;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@ -20,6 +21,11 @@ public class ErpWarehouseSaveReqVO {
@NotEmpty(message = "仓库名称不能为空") @NotEmpty(message = "仓库名称不能为空")
private String name; private String name;
@Schema(description = "仓库分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "仓库分类不能为空")
@InEnum(ErpWarehouseCategoryEnum.class)
private Integer categoryType;
@Schema(description = "仓库地址", example = "上海陆家嘴") @Schema(description = "仓库地址", example = "上海陆家嘴")
private String address; private String address;

@ -0,0 +1,66 @@
package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - ERP 仓库总览 Response VO")
@Data
public class ErpWarehouseSummaryRespVO {
@Schema(description = "仓库编号", example = "1")
private Long warehouseId;
@Schema(description = "仓库名称", example = "A仓")
private String warehouseName;
@Schema(description = "产品库存量", example = "1000")
private BigDecimal productStockCount;
@Schema(description = "产品库存展示", example = "2托3包4个")
private String productStockDisplay;
@Schema(description = "物料库存量", example = "1000")
private BigDecimal materialStockCount;
@Schema(description = "物料库存展示", example = "10采购单位20库存单位")
private String materialStockDisplay;
@Schema(description = "备件库存量", example = "1000")
private BigDecimal sparePartStockCount;
@Schema(description = "备件库存展示", example = "10采购单位20库存单位")
private String sparePartStockDisplay;
@Schema(description = "今日入库单数量", example = "5")
private Long todayStockInOrderCount;
@Schema(description = "今日入库明细行数量", example = "18")
private Long todayStockInItemCount;
@Schema(description = "今日入库产成品展示", example = "2托3包4个")
private String todayProductStockInDisplay;
@Schema(description = "今日入库物料展示", example = "100个")
private String todayMaterialStockInDisplay;
@Schema(description = "今日入库备件展示", example = "100个")
private String todaySparePartStockInDisplay;
@Schema(description = "今日出库单数量", example = "3")
private Long todayStockOutOrderCount;
@Schema(description = "今日出库明细行数量", example = "10")
private Long todayStockOutItemCount;
@Schema(description = "今日出库产成品展示", example = "2托3包4个")
private String todayProductStockOutDisplay;
@Schema(description = "今日出库物料展示", example = "100个")
private String todayMaterialStockOutDisplay;
@Schema(description = "今日出库备件展示", example = "100个")
private String todaySparePartStockOutDisplay;
}

@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.erp.dal.dataobject.pallet;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.math.BigDecimal;
import java.time.LocalDate;
@TableName("erp_pallet")
@KeySequence("erp_pallet_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ErpPalletDO extends BaseDO {
@TableId
private Long id;
private String code;
private Integer palletType;
private String specification;
private BigDecimal ratedLoadWeight;
private String unit;
private Integer status;
private Long warehouseId;
private Long areaId;
private String planCode;
private Long productId;
private BigDecimal productCount;
private String qrcode;
private LocalDate purchaseDate;
private LocalDate useDate;
private String remark;
}

@ -37,6 +37,10 @@ public class ErpStockCheckDO extends BaseDO {
* *
*/ */
private LocalDateTime checkTime; private LocalDateTime checkTime;
/**
* 1-2-
*/
private Integer sourceType;
/** /**
* *
*/ */

@ -32,6 +32,10 @@ public class ErpWarehouseDO extends BaseDO {
* *
*/ */
private String name; private String name;
/**
*
*/
private Integer categoryType;
/** /**
* *
*/ */
@ -67,4 +71,4 @@ public class ErpWarehouseDO extends BaseDO {
*/ */
private Boolean defaultStatus; private Boolean defaultStatus;
} }

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.erp.dal.mysql.pallet;
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.pallet.vo.ErpPalletPageReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.pallet.ErpPalletDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface ErpPalletMapper extends BaseMapperX<ErpPalletDO> {
default PageResult<ErpPalletDO> selectPage(ErpPalletPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<ErpPalletDO>()
.likeIfPresent(ErpPalletDO::getCode, reqVO.getCode())
.eqIfPresent(ErpPalletDO::getPalletType, reqVO.getPalletType())
.eqIfPresent(ErpPalletDO::getStatus, reqVO.getStatus())
.eqIfPresent(ErpPalletDO::getWarehouseId, reqVO.getWarehouseId())
.eqIfPresent(ErpPalletDO::getAreaId, reqVO.getAreaId())
.likeIfPresent(ErpPalletDO::getPlanCode, reqVO.getPlanCode())
.eqIfPresent(ErpPalletDO::getProductId, reqVO.getProductId())
.betweenIfPresent(ErpPalletDO::getPurchaseDate, reqVO.getPurchaseDate())
.betweenIfPresent(ErpPalletDO::getUseDate, reqVO.getUseDate())
.betweenIfPresent(ErpPalletDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(ErpPalletDO::getId));
}
default ErpPalletDO selectByCode(String code) {
return selectOne(ErpPalletDO::getCode, code);
}
default List<ErpPalletDO> selectListByStatus(Integer status) {
if (status == null) {
return selectList();
}
return selectList(ErpPalletDO::getStatus, status);
}
}

@ -5,8 +5,6 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO;
import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@ -32,10 +30,14 @@ public interface ErpStockCheckMapper extends BaseMapperX<ErpStockCheckDO> {
.eqIfPresent(ErpStockCheckDO::getCreator, reqVO.getCreator()) .eqIfPresent(ErpStockCheckDO::getCreator, reqVO.getCreator())
.orderByDesc(ErpStockCheckDO::getId); .orderByDesc(ErpStockCheckDO::getId);
if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) { if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) {
query.leftJoin(ErpStockCheckItemDO.class, ErpStockCheckItemDO::getCheckId, ErpStockCheckDO::getId) StringBuilder itemFilterSql = new StringBuilder("select distinct check_id from erp_stock_check_item where deleted = 0");
.eq(reqVO.getWarehouseId() != null, ErpStockCheckItemDO::getWarehouseId, reqVO.getWarehouseId()) if (reqVO.getWarehouseId() != null) {
.eq(reqVO.getProductId() != null, ErpStockCheckItemDO::getProductId, reqVO.getProductId()) itemFilterSql.append(" and warehouse_id = ").append(reqVO.getWarehouseId());
.groupBy(ErpStockCheckDO::getId); // 避免 1 对多查询,产生相同的 1 }
if (reqVO.getProductId() != null) {
itemFilterSql.append(" and product_id = ").append(reqVO.getProductId());
}
query.inSql(ErpStockCheckDO::getId, itemFilterSql.toString());
} }
@ -61,4 +63,4 @@ public interface ErpStockCheckMapper extends BaseMapperX<ErpStockCheckDO> {
return selectOne(ErpStockCheckDO::getNo, no); return selectOne(ErpStockCheckDO::getNo, no);
} }
} }

@ -83,11 +83,31 @@ public interface ErpStockMapper extends BaseMapperX<ErpStockDO> {
return selectList(query); return selectList(query);
} }
default List<ErpStockDO> selectListByWarehouseIdsAndAreaIds(List<Long> warehouseIds, List<Long> areaIds,
boolean nonZeroOnly) {
LambdaQueryWrapperX<ErpStockDO> query = new LambdaQueryWrapperX<ErpStockDO>()
.inIfPresent(ErpStockDO::getWarehouseId, warehouseIds)
.inIfPresent(ErpStockDO::getAreaId, areaIds);
if (nonZeroOnly) {
query.ne(ErpStockDO::getCount, BigDecimal.ZERO);
}
return selectList(query);
}
default List<ErpStockDO> selectListByProductIds(List<Long> productIds) { default List<ErpStockDO> selectListByProductIds(List<Long> productIds) {
return selectList(new LambdaQueryWrapperX<ErpStockDO>() return selectList(new LambdaQueryWrapperX<ErpStockDO>()
.inIfPresent(ErpStockDO::getProductId, productIds)); .inIfPresent(ErpStockDO::getProductId, productIds));
} }
default List<ErpStockDO> selectListByProductIds(List<Long> productIds, boolean nonZeroOnly) {
LambdaQueryWrapperX<ErpStockDO> query = new LambdaQueryWrapperX<ErpStockDO>()
.inIfPresent(ErpStockDO::getProductId, productIds);
if (nonZeroOnly) {
query.ne(ErpStockDO::getCount, BigDecimal.ZERO);
}
return selectList(query);
}
default List<ErpStockDO> selectListByProductIdsAndWarehouseIdsAndAreaIds(Collection<Long> productIds, default List<ErpStockDO> selectListByProductIdsAndWarehouseIdsAndAreaIds(Collection<Long> productIds,
Collection<Long> warehouseIds, Collection<Long> warehouseIds,
Collection<Long> areaIds) { Collection<Long> areaIds) {

@ -24,6 +24,7 @@ public interface ErpWarehouseMapper extends BaseMapperX<ErpWarehouseDO> {
LambdaQueryWrapperX<ErpWarehouseDO> erpWarehouseDOLambdaQueryWrapperX = new LambdaQueryWrapperX<ErpWarehouseDO>() LambdaQueryWrapperX<ErpWarehouseDO> erpWarehouseDOLambdaQueryWrapperX = new LambdaQueryWrapperX<ErpWarehouseDO>()
.likeIfPresent(ErpWarehouseDO::getName, reqVO.getName()) .likeIfPresent(ErpWarehouseDO::getName, reqVO.getName())
.eqIfPresent(ErpWarehouseDO::getCategoryType, reqVO.getCategoryType())
.eqIfPresent(ErpWarehouseDO::getStatus, reqVO.getStatus()) .eqIfPresent(ErpWarehouseDO::getStatus, reqVO.getStatus())
.orderByDesc(ErpWarehouseDO::getId); .orderByDesc(ErpWarehouseDO::getId);
@ -43,8 +44,11 @@ public interface ErpWarehouseMapper extends BaseMapperX<ErpWarehouseDO> {
return selectOne(ErpWarehouseDO::getDefaultStatus, true); return selectOne(ErpWarehouseDO::getDefaultStatus, true);
} }
default List<ErpWarehouseDO> selectListByStatus(Integer status) { default List<ErpWarehouseDO> selectListByStatus(Integer status, Integer categoryType) {
return selectList(ErpWarehouseDO::getStatus, status); return selectList(new LambdaQueryWrapperX<ErpWarehouseDO>()
.eqIfPresent(ErpWarehouseDO::getStatus, status)
.eqIfPresent(ErpWarehouseDO::getCategoryType, categoryType)
.orderByDesc(ErpWarehouseDO::getId));
} }
} }

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.erp.service.pallet;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.pallet.ErpPalletDO;
import javax.validation.Valid;
import java.util.List;
public interface ErpPalletService {
Long createPallet(@Valid ErpPalletSaveReqVO createReqVO);
void updatePallet(@Valid ErpPalletSaveReqVO updateReqVO);
void deletePallet(Long id);
ErpPalletDO getPallet(Long id);
PageResult<ErpPalletDO> getPalletPage(ErpPalletPageReqVO pageReqVO);
List<ErpPalletDO> getPalletListByStatus(Integer status);
}

@ -0,0 +1,144 @@
package cn.iocoder.yudao.module.erp.service.pallet;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil;
import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.pallet.ErpPalletDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.warehousearea.WarehouseAreaDO;
import cn.iocoder.yudao.module.erp.dal.mysql.pallet.ErpPalletMapper;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService;
import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PALLET_CODE_EXISTS;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PALLET_NOT_EXISTS;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_AREA_NOT_EXISTS;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_LOCATION_WAREHOUSE_AREA_NOT_MATCH;
@Service
@Validated
public class ErpPalletServiceImpl implements ErpPalletService {
@Resource
private ErpPalletMapper palletMapper;
@Resource
private AutoCodeUtil autoCodeUtil;
@Resource
private ErpWarehouseService warehouseService;
@Resource
private WarehouseAreaService warehouseAreaService;
@Resource
private ErpProductService productService;
@Override
public Long createPallet(ErpPalletSaveReqVO createReqVO) {
validateWarehouseAreaMatch(createReqVO.getWarehouseId(), createReqVO.getAreaId());
validateProductExists(createReqVO.getProductId());
ErpPalletDO pallet = BeanUtils.toBean(createReqVO, ErpPalletDO.class);
if (StringUtils.isBlank(pallet.getCode())) {
pallet.setCode(autoCodeUtil.genSerialCode("PALLET_CODE_GENERATE", null));
} else {
validateCodeUnique(null, pallet.getCode());
}
if (StringUtils.isBlank(pallet.getQrcode())) {
pallet.setQrcode(pallet.getCode());
}
palletMapper.insert(pallet);
return pallet.getId();
}
@Override
public void updatePallet(ErpPalletSaveReqVO updateReqVO) {
ErpPalletDO pallet = validatePalletExists(updateReqVO.getId());
validateWarehouseAreaMatch(updateReqVO.getWarehouseId(), updateReqVO.getAreaId());
validateProductExists(updateReqVO.getProductId());
ErpPalletDO updateObj = BeanUtils.toBean(updateReqVO, ErpPalletDO.class);
if (StringUtils.isBlank(updateObj.getCode())) {
updateObj.setCode(pallet.getCode());
} else {
validateCodeUnique(updateObj.getId(), updateObj.getCode());
}
if (StringUtils.isBlank(updateObj.getQrcode())) {
updateObj.setQrcode(updateObj.getCode());
}
palletMapper.updateById(updateObj);
}
@Override
public void deletePallet(Long id) {
validatePalletExists(id);
palletMapper.deleteById(id);
}
@Override
public ErpPalletDO getPallet(Long id) {
return palletMapper.selectById(id);
}
@Override
public PageResult<ErpPalletDO> getPalletPage(ErpPalletPageReqVO pageReqVO) {
return palletMapper.selectPage(pageReqVO);
}
@Override
public List<ErpPalletDO> getPalletListByStatus(Integer status) {
return palletMapper.selectListByStatus(status);
}
private ErpPalletDO validatePalletExists(Long id) {
ErpPalletDO pallet = palletMapper.selectById(id);
if (pallet == null) {
throw exception(PALLET_NOT_EXISTS);
}
return pallet;
}
private void validateCodeUnique(Long id, String code) {
ErpPalletDO pallet = palletMapper.selectByCode(code);
if (pallet == null) {
return;
}
if (id == null || !pallet.getId().equals(id)) {
throw exception(PALLET_CODE_EXISTS);
}
}
private void validateWarehouseAreaMatch(Long warehouseId, Long areaId) {
if (warehouseId == null && areaId == null) {
return;
}
if (warehouseId != null && warehouseService.validWarehouseList(Collections.singleton(warehouseId)).isEmpty()) {
throw exception(cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_NOT_EXISTS);
}
if (areaId == null) {
return;
}
WarehouseAreaDO area = warehouseAreaService.getWarehouseArea(areaId);
if (area == null) {
throw exception(WAREHOUSE_AREA_NOT_EXISTS);
}
if (warehouseId == null || !warehouseId.equals(area.getWarehouseId())) {
throw exception(WAREHOUSE_LOCATION_WAREHOUSE_AREA_NOT_MATCH);
}
}
private void validateProductExists(Long productId) {
if (productId == null) {
return;
}
if (productService.validProductList(Collections.singleton(productId)).isEmpty()) {
throw exception(PRODUCT_NOT_EXISTS);
}
}
}

@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckAuditReqVO; 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.ErpStockCheckGenerateByLocationReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckGenerateByProductReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckGenerateByProductReqVO;
@ -29,6 +29,7 @@ import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper;
import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; 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.ErpAuditStatus;
import cn.iocoder.yudao.module.erp.enums.stock.ErpStockCheckApproveActionEnum; 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.enums.stock.ErpStockRecordBizTypeEnum;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService; 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.stock.bo.ErpStockRecordCreateReqBO;
@ -36,6 +37,9 @@ import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -55,22 +59,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_APPROVE_FAIL; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_AUDIT_FAIL_RESULT;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_AUDIT_FAIL_STATUS;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_AUDIT_FAIL_USER;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_DELETE_FAIL_APPROVE;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_DELETE_FAIL_PROCESS;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_NOT_EXISTS;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_NO_EXISTS;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_PROCESS_FAIL;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_SUBMIT_FAIL_AUDIT_USER_EMPTY;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_SUBMIT_FAIL_STATUS;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_SUBMIT_FAIL_USER;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_UPDATE_FAIL_APPROVE;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_UPDATE_FAIL_PROCESS;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_AREA_NOT_EXISTS;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_LOCATION_WAREHOUSE_AREA_NOT_MATCH;
@Service @Service
@Validated @Validated
@ -98,18 +87,34 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
private AdminUserApi adminUserApi; private AdminUserApi adminUserApi;
@Resource @Resource
private PermissionApi permissionApi; private PermissionApi permissionApi;
@Autowired
private AutoCodeUtil autoCodeUtil;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Long createStockCheck(ErpStockCheckSaveReqVO createReqVO) { public Long createStockCheck(ErpStockCheckSaveReqVO createReqVO) {
String code = createReqVO.getCode();
validateSourceType(createReqVO.getSourceType());
List<ErpStockCheckItemDO> stockCheckItems = validateStockCheckItems(createReqVO.getItems()); List<ErpStockCheckItemDO> stockCheckItems = validateStockCheckItems(createReqVO.getItems());
String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_CHECK_NO_PREFIX); // String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_CHECK_NO_PREFIX);
if (stockCheckMapper.selectByNo(no) != null) { // if (stockCheckMapper.selectByNo(no) != null) {
throw exception(STOCK_CHECK_NO_EXISTS); // throw exception(STOCK_CHECK_NO_EXISTS);
// }
boolean autoGeneratedCode = StringUtils.isBlank(code);
if (autoGeneratedCode) {
code = autoCodeUtil.genSerialCode("INVENTORY_EXECUTION_CODE", null);
} else {
if (stockCheckMapper.selectOne(Wrappers.<ErpStockCheckDO>lambdaQuery()
.eq(ErpStockCheckDO::getNo, code)) != null) {
throw exception(STOCK_CODE_EXISTS);
}
} }
String finalCode = code;
ErpStockCheckDO stockCheck = BeanUtils.toBean(createReqVO, ErpStockCheckDO.class, in -> in ErpStockCheckDO stockCheck = BeanUtils.toBean(createReqVO, ErpStockCheckDO.class, in -> in
.setNo(no) .setNo(finalCode)
.setStatus(ErpAuditStatus.DRAFT.getStatus()) .setStatus(ErpAuditStatus.DRAFT.getStatus())
.setTotalCount(getSumValue(stockCheckItems, ErpStockCheckItemDO::getCount, BigDecimal::add, BigDecimal.ZERO)) .setTotalCount(getSumValue(stockCheckItems, ErpStockCheckItemDO::getCount, BigDecimal::add, BigDecimal.ZERO))
.setTotalPrice(getSumValue(stockCheckItems, ErpStockCheckItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); .setTotalPrice(getSumValue(stockCheckItems, ErpStockCheckItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)));
@ -130,6 +135,7 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
throw exception(STOCK_CHECK_UPDATE_FAIL_PROCESS, stockCheck.getNo()); throw exception(STOCK_CHECK_UPDATE_FAIL_PROCESS, stockCheck.getNo());
} }
validateSourceType(updateReqVO.getSourceType());
List<ErpStockCheckItemDO> stockCheckItems = validateStockCheckItems(updateReqVO.getItems()); List<ErpStockCheckItemDO> stockCheckItems = validateStockCheckItems(updateReqVO.getItems());
ErpStockCheckDO updateObj = BeanUtils.toBean(updateReqVO, ErpStockCheckDO.class, in -> in ErpStockCheckDO updateObj = BeanUtils.toBean(updateReqVO, ErpStockCheckDO.class, in -> in
.setTotalCount(getSumValue(stockCheckItems, ErpStockCheckItemDO::getCount, BigDecimal::add, BigDecimal.ZERO)) .setTotalCount(getSumValue(stockCheckItems, ErpStockCheckItemDO::getCount, BigDecimal::add, BigDecimal.ZERO))
@ -288,10 +294,9 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
if (reqVO == null || !reqVO.validSelection()) { if (reqVO == null || !reqVO.validSelection()) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<ErpStockDO> stockList = stockMapper.selectListByWarehouseIdsAndAreaIds(reqVO.getWarehouseIds(), reqVO.getAreaIds()); boolean nonZeroOnly = Boolean.FALSE.equals(reqVO.getAllowEmpty());
if (!Boolean.TRUE.equals(reqVO.getAllowEmpty())) { List<ErpStockDO> stockList = stockMapper.selectListByWarehouseIdsAndAreaIds(
stockList = filterNonZeroStocks(stockList); reqVO.getWarehouseIds(), reqVO.getAreaIds(), nonZeroOnly);
}
return buildPreviewItems(stockList); return buildPreviewItems(stockList);
} }
@ -300,7 +305,9 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
if (reqVO == null || CollUtil.isEmpty(reqVO.getProductIds())) { if (reqVO == null || CollUtil.isEmpty(reqVO.getProductIds())) {
return Collections.emptyList(); return Collections.emptyList();
} }
return buildPreviewItems(filterNonZeroStocks(stockMapper.selectListByProductIds(reqVO.getProductIds()))); boolean nonZeroOnly = Boolean.FALSE.equals(reqVO.getAllowEmpty());
List<ErpStockDO> stockList = stockMapper.selectListByProductIds(reqVO.getProductIds(), nonZeroOnly);
return buildPreviewItems(stockList);
} }
private List<ErpStockDO> filterNonZeroStocks(List<ErpStockDO> stockList) { private List<ErpStockDO> filterNonZeroStocks(List<ErpStockDO> stockList) {
@ -320,7 +327,8 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
if (CollUtil.isEmpty(stockList)) { if (CollUtil.isEmpty(stockList)) {
return Collections.emptyList(); return Collections.emptyList();
} }
Map<Long, ErpProductDO> productMap = productService.getProductMap(convertSet(stockList, ErpStockDO::getProductId)); Collection<Long> productIds = convertSet(stockList, ErpStockDO::getProductId);
Map<Long, ErpProductDO> productMap = productService.getProductMap(productIds);
Map<Long, ErpWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(convertSet(stockList, ErpStockDO::getWarehouseId)); Map<Long, ErpWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(convertSet(stockList, ErpStockDO::getWarehouseId));
Map<Long, WarehouseAreaDO> areaMap = warehouseAreaService.getWarehouseAreaMap(convertSet(stockList, ErpStockDO::getAreaId)); Map<Long, WarehouseAreaDO> areaMap = warehouseAreaService.getWarehouseAreaMap(convertSet(stockList, ErpStockDO::getAreaId));
List<ErpStockCheckRespVO.Item> result = new ArrayList<>(); List<ErpStockCheckRespVO.Item> result = new ArrayList<>();
@ -331,7 +339,7 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
item.setAreaName(stock.getAreaName()); item.setAreaName(stock.getAreaName());
item.setProductId(stock.getProductId()); item.setProductId(stock.getProductId());
item.setStockCount(stock.getCount() != null ? stock.getCount() : BigDecimal.ZERO); item.setStockCount(stock.getCount() != null ? stock.getCount() : BigDecimal.ZERO);
item.setActualCount(stock.getCount() != null ? stock.getCount() : BigDecimal.ZERO); item.setActualCount(null);
item.setCount(BigDecimal.ZERO); item.setCount(BigDecimal.ZERO);
MapUtils.findAndThen(warehouseMap, stock.getWarehouseId(), warehouse -> item.setWarehouseName(warehouse.getName())); MapUtils.findAndThen(warehouseMap, stock.getWarehouseId(), warehouse -> item.setWarehouseName(warehouse.getName()));
if (item.getAreaName() == null) { if (item.getAreaName() == null) {
@ -339,13 +347,10 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
} }
ErpProductDO productDO = productMap.get(stock.getProductId()); ErpProductDO productDO = productMap.get(stock.getProductId());
item.setProductPrice(resolveProductPrice(productDO)); item.setProductPrice(resolveProductPrice(productDO));
item.setProductUnitName(stock.getUnitName());
if (productDO != null) { if (productDO != null) {
item.setProductName(productDO.getName()); item.setProductName(productDO.getName());
item.setProductBarCode(productDO.getBarCode()); item.setProductBarCode(productDO.getBarCode());
ErpProductRespVO productVO = productService.getProduct(productDO.getId());
if (productVO != null) {
item.setProductUnitName(productVO.getUnitName());
}
} }
result.add(item); result.add(item);
} }
@ -426,8 +431,8 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
ErpProductDO productDO = productMap.get(item.getProductId()); ErpProductDO productDO = productMap.get(item.getProductId());
WarehouseAreaDO area = item.getAreaId() != null ? areaMap.get(item.getAreaId()) : null; WarehouseAreaDO area = item.getAreaId() != null ? areaMap.get(item.getAreaId()) : null;
BigDecimal stockCount = item.getStockCount() != null ? item.getStockCount() : BigDecimal.ZERO; BigDecimal stockCount = item.getStockCount() != null ? item.getStockCount() : BigDecimal.ZERO;
BigDecimal actualCount = item.getActualCount() != null ? item.getActualCount() : BigDecimal.ZERO; BigDecimal actualCount = item.getActualCount();
BigDecimal count = actualCount.subtract(stockCount); BigDecimal count = actualCount != null ? actualCount.subtract(stockCount) : null;
BigDecimal productPrice = item.getProductPrice() != null ? item.getProductPrice() : resolveProductPrice(productDO); BigDecimal productPrice = item.getProductPrice() != null ? item.getProductPrice() : resolveProductPrice(productDO);
return ErpStockCheckItemDO.builder() return ErpStockCheckItemDO.builder()
.id(item.getId()) .id(item.getId())
@ -440,7 +445,7 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
.stockCount(stockCount) .stockCount(stockCount)
.actualCount(actualCount) .actualCount(actualCount)
.count(count) .count(count)
.totalPrice(MoneyUtils.priceMultiply(productPrice, count)) .totalPrice(count != null ? MoneyUtils.priceMultiply(productPrice, count) : null)
.remark(item.getRemark()) .remark(item.getRemark())
.build(); .build();
}); });
@ -484,4 +489,11 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
return stockCheck; return stockCheck;
} }
private void validateSourceType(Integer sourceType) {
if (!ErpStockCheckSourceTypeEnum.BY_LOCATION.getType().equals(sourceType)
&& !ErpStockCheckSourceTypeEnum.BY_PRODUCT.getType().equals(sourceType)) {
throw exception(STOCK_CHECK_SOURCE_TYPE_NOT_EXISTS);
}
}
} }

@ -75,7 +75,7 @@ public interface ErpWarehouseService {
* @param status * @param status
* @return * @return
*/ */
List<ErpWarehouseDO> getWarehouseListByStatus(Integer status); List<ErpWarehouseDO> getWarehouseListByStatus(Integer status, Integer categoryType);
/** /**
* *

@ -128,8 +128,8 @@ public class ErpWarehouseServiceImpl implements ErpWarehouseService {
} }
@Override @Override
public List<ErpWarehouseDO> getWarehouseListByStatus(Integer status) { public List<ErpWarehouseDO> getWarehouseListByStatus(Integer status, Integer categoryType) {
return warehouseMapper.selectListByStatus(status); return warehouseMapper.selectListByStatus(status, categoryType);
} }
@Override @Override

@ -0,0 +1,9 @@
package cn.iocoder.yudao.module.erp.service.stock;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSummaryRespVO;
public interface ErpWarehouseSummaryService {
ErpWarehouseSummaryRespVO getWarehouseSummary(Long warehouseId);
}

@ -0,0 +1,261 @@
package cn.iocoder.yudao.module.erp.service.stock;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSummaryRespVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInItemMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutItemMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutMapper;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Service
@Validated
public class ErpWarehouseSummaryServiceImpl implements ErpWarehouseSummaryService {
@Resource
private ErpWarehouseService warehouseService;
@Resource
private ErpStockMapper stockMapper;
@Resource
private ErpStockInMapper stockInMapper;
@Resource
private ErpStockInItemMapper stockInItemMapper;
@Resource
private ErpStockOutMapper stockOutMapper;
@Resource
private ErpStockOutItemMapper stockOutItemMapper;
@Resource
private ErpProductService productService;
@Override
public ErpWarehouseSummaryRespVO getWarehouseSummary(Long warehouseId) {
ErpWarehouseDO warehouse = warehouseService.getWarehouse(warehouseId);
ErpWarehouseSummaryRespVO respVO = new ErpWarehouseSummaryRespVO();
respVO.setWarehouseId(warehouseId);
respVO.setWarehouseName(warehouse != null ? warehouse.getName() : null);
List<ErpStockDO> stockList = stockMapper.selectListByWarehouseIdsAndAreaIds(Collections.singletonList(warehouseId), null);
fillStockSummary(respVO, stockList);
LocalDateTime beginTime = LocalDate.now().atStartOfDay();
LocalDateTime endTime = beginTime.plusDays(1);
fillTodayInSummary(respVO, warehouseId, beginTime, endTime);
fillTodayOutSummary(respVO, warehouseId, beginTime, endTime);
return respVO;
}
private void fillStockSummary(ErpWarehouseSummaryRespVO respVO, List<ErpStockDO> stockList) {
if (CollUtil.isEmpty(stockList)) {
respVO.setProductStockCount(BigDecimal.ZERO);
respVO.setMaterialStockCount(BigDecimal.ZERO);
respVO.setSparePartStockCount(BigDecimal.ZERO);
respVO.setProductStockDisplay(formatProductDisplay(BigDecimal.ZERO, null, null, null));
respVO.setMaterialStockDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null));
respVO.setSparePartStockDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null));
return;
}
Map<Integer, List<ErpStockDO>> categoryMap = stockList.stream().collect(Collectors.groupingBy(this::resolveCategoryType));
BigDecimal productCount = sumCount(categoryMap.get(1));
BigDecimal materialCount = sumCount(categoryMap.get(2));
BigDecimal sparePartCount = sumCount(categoryMap.get(3));
respVO.setProductStockCount(productCount);
respVO.setMaterialStockCount(materialCount);
respVO.setSparePartStockCount(sparePartCount);
ErpStockDO productStock = firstStock(categoryMap.get(1));
ErpStockDO materialStock = firstStock(categoryMap.get(2));
ErpStockDO sparePartStock = firstStock(categoryMap.get(3));
respVO.setProductStockDisplay(formatProductDisplay(productCount,
productStock != null ? productStock.getPalletTotalQuantity() : null,
productStock != null ? productStock.getPalletPackageQuantity() : null,
productStock != null ? productStock.getPackageQuantity() : null));
respVO.setMaterialStockDisplay(formatUnitDisplay(materialCount,
materialStock != null ? materialStock.getPurchaseUnitConvertQuantity() : null,
materialStock != null ? materialStock.getPurchaseUnitName() : null,
materialStock != null ? materialStock.getUnitName() : null));
respVO.setSparePartStockDisplay(formatUnitDisplay(sparePartCount,
sparePartStock != null ? sparePartStock.getPurchaseUnitConvertQuantity() : null,
sparePartStock != null ? sparePartStock.getPurchaseUnitName() : null,
sparePartStock != null ? sparePartStock.getUnitName() : null));
}
private void fillTodayInSummary(ErpWarehouseSummaryRespVO respVO, Long warehouseId, LocalDateTime beginTime, LocalDateTime endTime) {
List<ErpStockInDO> stockInList = stockInMapper.selectList(new LambdaQueryWrapper<ErpStockInDO>()
.eq(ErpStockInDO::getStatus, 20)
.between(ErpStockInDO::getInTime, beginTime, endTime));
List<Long> inIds = stockInList.stream()
.filter(stockIn -> hasWarehouseIn(stockIn.getId(), warehouseId))
.map(ErpStockInDO::getId)
.collect(Collectors.toList());
respVO.setTodayStockInOrderCount((long) inIds.size());
List<ErpStockInItemDO> itemList = stockInItemMapper.selectListByInIds(inIds);
respVO.setTodayStockInItemCount((long) itemList.size());
fillInOutDisplay(respVO, true, itemList);
}
private void fillTodayOutSummary(ErpWarehouseSummaryRespVO respVO, Long warehouseId, LocalDateTime beginTime, LocalDateTime endTime) {
List<ErpStockOutDO> stockOutList = stockOutMapper.selectList(new LambdaQueryWrapper<ErpStockOutDO>()
.eq(ErpStockOutDO::getStatus, 20)
.between(ErpStockOutDO::getOutTime, beginTime, endTime));
List<Long> outIds = stockOutList.stream()
.filter(stockOut -> hasWarehouseOut(stockOut.getId(), warehouseId))
.map(ErpStockOutDO::getId)
.collect(Collectors.toList());
respVO.setTodayStockOutOrderCount((long) outIds.size());
List<ErpStockOutItemDO> itemList = stockOutItemMapper.selectListByOutIds(outIds);
respVO.setTodayStockOutItemCount((long) itemList.size());
fillInOutDisplay(respVO, false, itemList);
}
private void fillInOutDisplay(ErpWarehouseSummaryRespVO respVO, boolean inbound, List<?> itemList) {
if (CollUtil.isEmpty(itemList)) {
if (inbound) {
respVO.setTodayProductStockInDisplay(formatProductDisplay(BigDecimal.ZERO, null, null, null));
respVO.setTodayMaterialStockInDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null));
respVO.setTodaySparePartStockInDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null));
} else {
respVO.setTodayProductStockOutDisplay(formatProductDisplay(BigDecimal.ZERO, null, null, null));
respVO.setTodayMaterialStockOutDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null));
respVO.setTodaySparePartStockOutDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null));
}
return;
}
Set<Long> productIds = itemList.stream()
.map(item -> item instanceof ErpStockInItemDO ? ((ErpStockInItemDO) item).getProductId() : ((ErpStockOutItemDO) item).getProductId())
.collect(Collectors.toSet());
Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(productIds);
BigDecimal productCount = BigDecimal.ZERO;
BigDecimal materialCount = BigDecimal.ZERO;
BigDecimal sparePartCount = BigDecimal.ZERO;
for (Object item : itemList) {
Long productId = item instanceof ErpStockInItemDO ? ((ErpStockInItemDO) item).getProductId() : ((ErpStockOutItemDO) item).getProductId();
BigDecimal count = item instanceof ErpStockInItemDO ? ((ErpStockInItemDO) item).getCount() : ((ErpStockOutItemDO) item).getCount();
ErpProductRespVO product = productMap.get(productId);
Integer categoryType = product != null ? product.getCategoryType() : null;
if (Integer.valueOf(1).equals(categoryType)) {
productCount = productCount.add(safeCount(count));
} else if (Integer.valueOf(2).equals(categoryType)) {
materialCount = materialCount.add(safeCount(count));
} else if (Integer.valueOf(3).equals(categoryType)) {
sparePartCount = sparePartCount.add(safeCount(count));
}
}
if (inbound) {
respVO.setTodayProductStockInDisplay(formatProductDisplay(productCount, null, null, null));
respVO.setTodayMaterialStockInDisplay(formatUnitDisplay(materialCount, null, null, null));
respVO.setTodaySparePartStockInDisplay(formatUnitDisplay(sparePartCount, null, null, null));
} else {
respVO.setTodayProductStockOutDisplay(formatProductDisplay(productCount, null, null, null));
respVO.setTodayMaterialStockOutDisplay(formatUnitDisplay(materialCount, null, null, null));
respVO.setTodaySparePartStockOutDisplay(formatUnitDisplay(sparePartCount, null, null, null));
}
}
private boolean hasWarehouseIn(Long inId, Long warehouseId) {
return stockInItemMapper.selectListByInId(inId).stream().anyMatch(item -> warehouseId.equals(item.getWarehouseId()));
}
private boolean hasWarehouseOut(Long outId, Long warehouseId) {
return stockOutItemMapper.selectListByOutId(outId).stream().anyMatch(item -> warehouseId.equals(item.getWarehouseId()));
}
private Integer resolveCategoryType(ErpStockDO stock) {
if (stock.getCategoryType() != null) {
return stock.getCategoryType();
}
ErpProductRespVO product = productService.getProductVOMap(Collections.singleton(stock.getProductId())).get(stock.getProductId());
return product != null ? product.getCategoryType() : null;
}
private ErpStockDO firstStock(List<ErpStockDO> list) {
return CollUtil.isEmpty(list) ? null : list.get(0);
}
private BigDecimal sumCount(List<ErpStockDO> list) {
if (CollUtil.isEmpty(list)) {
return BigDecimal.ZERO;
}
BigDecimal total = BigDecimal.ZERO;
for (ErpStockDO stock : list) {
total = total.add(safeCount(stock.getCount()));
}
return total;
}
private BigDecimal safeCount(BigDecimal count) {
return count == null ? BigDecimal.ZERO : count;
}
private String formatProductDisplay(BigDecimal count, BigDecimal palletTotalQuantity, BigDecimal palletPackageQuantity,
BigDecimal packageQuantity) {
BigDecimal safeCount = safeCount(count);
if (palletTotalQuantity == null || palletTotalQuantity.compareTo(BigDecimal.ZERO) <= 0) {
return formatNumber(safeCount) + "个";
}
BigDecimal palletCount = safeCount.divideToIntegralValue(palletTotalQuantity);
BigDecimal remainAfterPallet = safeCount.remainder(palletTotalQuantity);
if (palletPackageQuantity == null || palletPackageQuantity.compareTo(BigDecimal.ZERO) <= 0) {
return formatNumber(palletCount) + "托" + formatNumber(remainAfterPallet) + "个";
}
BigDecimal packageCount = remainAfterPallet.divideToIntegralValue(palletPackageQuantity);
BigDecimal remainAfterPackage = remainAfterPallet.remainder(palletPackageQuantity);
if (packageQuantity == null || packageQuantity.compareTo(BigDecimal.ZERO) <= 0) {
return formatNumber(palletCount) + "托" + formatNumber(packageCount) + "包" + formatNumber(remainAfterPackage) + "个";
}
BigDecimal unitCount = remainAfterPackage.divideToIntegralValue(packageQuantity);
return formatNumber(palletCount) + "托" + formatNumber(packageCount) + "包" + formatNumber(unitCount) + "个";
}
private String formatUnitDisplay(BigDecimal count, BigDecimal purchaseUnitConvertQuantity, String purchaseUnitName, String unitName) {
BigDecimal safeCount = safeCount(count);
if (purchaseUnitConvertQuantity == null || purchaseUnitConvertQuantity.compareTo(BigDecimal.ZERO) <= 0
|| purchaseUnitName == null || unitName == null) {
return formatNumber(safeCount) + (unitName != null ? unitName : "个");
}
BigDecimal purchaseCount = safeCount.divideToIntegralValue(purchaseUnitConvertQuantity);
BigDecimal unitCount = safeCount.remainder(purchaseUnitConvertQuantity);
StringBuilder display = new StringBuilder();
if (purchaseCount.compareTo(BigDecimal.ZERO) > 0) {
display.append(formatNumber(purchaseCount)).append(purchaseUnitName);
}
if (unitCount.compareTo(BigDecimal.ZERO) > 0 || display.length() == 0) {
display.append(formatNumber(unitCount)).append(unitName);
}
return display.toString();
}
private String formatNumber(BigDecimal value) {
return value == null ? "0" : value.stripTrailingZeros().toPlainString();
}
}
Loading…
Cancel
Save