Merge remote-tracking branch 'origin/main'

main
liutao 22 hours ago
commit add1d2e6fa

@ -12,6 +12,7 @@ public enum QrcodeBizTypeEnum {
DEVICE_LINE("DEVICE_LINE", "设备产线"),
KEY_PART("KEY_PART", "关键件"),
MOLD("MOLD", "模具"),
PALLET("PALLET", "托盘"),
SPARE("SPARE", "备件");
private final String code;

@ -101,6 +101,9 @@ public interface ErrorCodeConstants {
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_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, "托盘编码已存在");
ErrorCode PALLET_CODE_EMPTY = new ErrorCode(1_030_400_010, "托盘编码不能为空");
// ========== ERP 其它入库单 1-030-401-000 ==========
ErrorCode STOCK_IN_NOT_EXISTS = new ErrorCode(1_030_401_000, "其它入库单不存在");
@ -160,6 +163,9 @@ public interface ErrorCodeConstants {
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_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 ==========
ErrorCode STOCK_COUNT_NEGATIVE = new ErrorCode(1_030_404_000, "操作失败,产品({})所在仓库({})的库存:{},小于变更数量:{}");

@ -8,6 +8,7 @@ import lombok.RequiredArgsConstructor;
public enum ErpStockCheckApproveActionEnum {
SUBMIT("SUBMIT"),
AUTO_APPROVE("AUTO_APPROVE"),
APPROVE("APPROVE"),
REJECT("REJECT");

@ -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,25 @@
package cn.iocoder.yudao.module.erp.enums.stock;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
@Getter
@AllArgsConstructor
public enum ErpStockOutModeEnum implements IntArrayValuable {
BY_PALLET(1, "按托出库"),
SPLIT_PALLET(2, "拆托出库");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpStockOutModeEnum::getMode).toArray();
private final Integer mode;
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}

@ -0,0 +1,141 @@
package cn.iocoder.yudao.module.erp.controller.admin.pallet;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum;
import cn.iocoder.yudao.module.common.service.qrcordrecord.QrcodeRecordService;
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.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
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;
@Resource
private QrcodeRecordService qrcodeService;
@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(buildPalletRespVO(pallet));
}
@GetMapping("/page")
@Operation(summary = "获得托盘分页")
@PreAuthorize("@ss.hasPermission('erp:pallet:query')")
public CommonResult<PageResult<ErpPalletRespVO>> getPalletPage(@Valid ErpPalletPageReqVO pageReqVO) {
PageResult<ErpPalletDO> pageResult = palletService.getPalletPage(pageReqVO);
Map<Long, String> qrcodeMap = qrcodeService.selectQrcodeUrlMapByBizTypeAndIds(QrcodeBizTypeEnum.PALLET.getCode(),
convertList(pageResult.getList(), ErpPalletDO::getId));
List<ErpPalletRespVO> list = convertList(pageResult.getList(), pallet -> buildPalletRespVO(pallet, qrcodeMap));
return success(new PageResult<>(list, pageResult.getTotal()));
}
@GetMapping("/export-excel")
@Operation(summary = "导出托盘 Excel")
@PreAuthorize("@ss.hasPermission('erp:pallet:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportPalletExcel(@Valid ErpPalletPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
PageResult<ErpPalletDO> pageResult = palletService.getPalletPage(pageReqVO);
Map<Long, String> qrcodeMap = qrcodeService.selectQrcodeUrlMapByBizTypeAndIds(QrcodeBizTypeEnum.PALLET.getCode(),
convertList(pageResult.getList(), ErpPalletDO::getId));
List<ErpPalletRespVO> list = convertList(pageResult.getList(), pallet -> buildPalletRespVO(pallet, qrcodeMap));
ExcelUtils.write(response, "托盘.xls", "数据", ErpPalletRespVO.class, list);
}
@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);
Map<Long, String> qrcodeMap = qrcodeService.selectQrcodeUrlMapByBizTypeAndIds(QrcodeBizTypeEnum.PALLET.getCode(),
convertList(list, ErpPalletDO::getId));
return success(convertList(list, item -> buildPalletRespVO(item, qrcodeMap)));
}
@PostMapping("/regenerate-code")
public CommonResult<Boolean> regenerateCode(@RequestParam("id") Long id,
@RequestParam("code") String code) throws UnsupportedEncodingException {
palletService.regenerateCode(id, code);
return success(true);
}
private ErpPalletRespVO buildPalletRespVO(ErpPalletDO pallet) {
if (pallet == null) {
return null;
}
ErpPalletRespVO respVO = BeanUtils.toBean(pallet, ErpPalletRespVO.class);
String qrcode = qrcodeService.selectQrcodeUrlByIdAndCode(QrcodeBizTypeEnum.PALLET.getCode(), pallet.getId(), pallet.getCode());
if (qrcode != null) {
respVO.setQrcode(qrcode);
}
return respVO;
}
private ErpPalletRespVO buildPalletRespVO(ErpPalletDO pallet, Map<Long, String> qrcodeMap) {
ErpPalletRespVO respVO = BeanUtils.toBean(pallet, ErpPalletRespVO.class);
String qrcode = qrcodeMap.get(pallet.getId());
if (qrcode != null) {
respVO.setQrcode(qrcode);
}
return respVO;
}
}

@ -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.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;
@ -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.warehousearea.WarehouseAreaDO;
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.ErpWarehouseService;
import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService;
@ -71,6 +73,8 @@ public class ErpStockCheckController {
@Resource
private ErpProductService productService;
@Resource
private ErpProductUnitService productUnitService;
@Resource
private ErpWarehouseService warehouseService;
@Resource
private WarehouseAreaService warehouseAreaService;
@ -94,7 +98,7 @@ public class ErpStockCheckController {
@PutMapping("/update-status")
@Operation(summary = "更新库存盘点单状态")
@PreAuthorize("@ss.hasPermission('erp:stock-check:update-status')")
@PreAuthorize("@ss.hasPermission('erp:stock-check:update')")
@RateLimiter(count = 1, timeUnit = TimeUnit.SECONDS)
public CommonResult<Boolean> updateStockCheckStatus(@RequestParam("id") Long id,
@RequestParam("status") Integer status) {
@ -104,7 +108,7 @@ public class ErpStockCheckController {
@PutMapping("/submit")
@Operation(summary = "提交库存盘点单审核")
@PreAuthorize("@ss.hasPermission('erp:stock-check:update')")
@PreAuthorize("@ss.hasPermission('erp:stock-check:submit')")
@RateLimiter(count = 1, timeUnit = TimeUnit.SECONDS)
public CommonResult<Boolean> submitStockCheckAudit(@Valid @RequestBody ErpStockCheckSubmitReqVO submitReqVO) {
stockCheckService.submitStockCheckAudit(submitReqVO);
@ -113,7 +117,7 @@ public class ErpStockCheckController {
@PutMapping("/audit")
@Operation(summary = "审核库存盘点单")
@PreAuthorize("@ss.hasPermission('erp:stock-check:update-status')")
@PreAuthorize("@ss.hasPermission('erp:stock-check:audit')")
@RateLimiter(count = 1, timeUnit = TimeUnit.SECONDS)
public CommonResult<Boolean> auditStockCheck(@Valid @RequestBody ErpStockCheckAuditReqVO auditReqVO) {
stockCheckService.auditStockCheck(auditReqVO);
@ -189,10 +193,12 @@ public class ErpStockCheckController {
List<ErpStockCheckItemDO> stockCheckItemList = stockCheckService.getStockCheckItemListByCheckIds(
convertSet(pageResult.getList(), ErpStockCheckDO::getId));
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 -> {
stockCheck.setItems(buildItemRespList(stockCheckItemMap.get(stockCheck.getId())));
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)) {
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, WarehouseAreaDO> areaMap = warehouseAreaService.getWarehouseAreaMap(convertSet(itemList, ErpStockCheckItemDO::getAreaId));
return BeanUtils.toBean(itemList, ErpStockCheckRespVO.Item.class, item -> {
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()));
if (item.getAreaName() == null) {
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(stockCheck.getAuditUserId());
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, stockCheck.getAuditUserId(), user -> stockCheck.setAuditUserName(user.getNickname()));
}

@ -12,9 +12,11 @@ import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProduc
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductPackagingSchemeRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockRespVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.pallet.ErpPalletDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO;
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.service.pallet.ErpPalletService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.stock.ErpStockRecordService;
import cn.iocoder.yudao.module.erp.service.stock.ErpStockService;
@ -36,8 +38,12 @@ import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -59,6 +65,8 @@ public class ErpStockController {
private WarehouseAreaService warehouseAreaService;
@Resource
private ErpStockRecordService stockRecordService;
@Resource
private ErpPalletService palletService;
@GetMapping("/get")
@Operation(summary = "获得产品库存")
@ -112,6 +120,7 @@ public class ErpStockController {
convertSet(pageResult.getList(), ErpStockDO::getWarehouseId));
Map<Long, WarehouseAreaDO> areaMap = warehouseAreaService.getWarehouseAreaMap(
convertSet(pageResult.getList(), ErpStockDO::getAreaId));
Map<String, Long> palletCountMap = buildPalletCountMap(pageResult.getList());
return BeanUtils.toBean(pageResult, ErpStockRespVO.class, stock -> {
MapUtils.findAndThen(productMap, stock.getProductId(), product -> {
stock.setProductName(product.getName()).setBarCode(product.getBarCode())
@ -120,6 +129,7 @@ public class ErpStockController {
fillProductExtraInfo(stock, product);
fillPackagingSnapshot(stock, product);
});
stock.setPalletCount(palletCountMap.getOrDefault(buildStockKey(stock.getProductId(), stock.getWarehouseId(), stock.getAreaId()), 0L));
stock.setPackagingRule(buildPackagingRule(stock));
stock.setStockDisplay(buildStockDisplay(stock));
MapUtils.findAndThen(warehouseMap, stock.getWarehouseId(), warehouse -> stock.setWarehouseName(warehouse.getName()));
@ -150,6 +160,7 @@ public class ErpStockController {
fillPackagingSnapshot(respVO, product);
}
fillDerivedFields(respVO);
respVO.setPalletCount(getPalletCount(respVO));
respVO.setPackagingRule(buildPackagingRule(respVO));
respVO.setStockDisplay(buildStockDisplay(respVO));
ErpWarehouseDO warehouse = warehouseService.getWarehouse(stock.getWarehouseId());
@ -259,11 +270,12 @@ public class ErpStockController {
return null;
}
if (isProductType(stock.getCategoryType())) {
if (stock.getPalletTotalQuantity() == null || stock.getPalletTotalQuantity().compareTo(BigDecimal.ZERO) <= 0) {
if (stock.getPackageQuantity() == null || stock.getPackageQuantity().compareTo(BigDecimal.ZERO) <= 0) {
return formatNumber(stock.getCount()) + stock.getUnitName();
}
BigDecimal palletCount = stock.getCount().divideToIntegralValue(stock.getPalletTotalQuantity());
return formatNumber(palletCount) + "托,0包,0个";
BigDecimal packageCount = stock.getCount().divide(stock.getPackageQuantity(), 0, RoundingMode.CEILING);
return formatNumber(BigDecimal.valueOf(stock.getPalletCount() != null ? stock.getPalletCount() : 0L)) + "\u6258"
+ formatNumber(packageCount) + "\u5305" + formatNumber(stock.getCount()) + stock.getUnitName();
}
if (stock.getPurchaseUnitConvertQuantity() == null || stock.getPurchaseUnitConvertQuantity().compareTo(BigDecimal.ZERO) <= 0
|| stock.getPurchaseUnitName() == null || stock.getUnitName() == null) {
@ -298,6 +310,28 @@ public class ErpStockController {
return Integer.valueOf(1).equals(categoryType);
}
private Map<String, Long> buildPalletCountMap(List<ErpStockDO> stockList) {
if (CollUtil.isEmpty(stockList)) {
return new HashMap<>();
}
return palletService.getOccupiedPalletList(convertSet(stockList, ErpStockDO::getProductId),
convertSet(stockList, ErpStockDO::getWarehouseId), convertSet(stockList, ErpStockDO::getAreaId)).stream()
.collect(Collectors.groupingBy(pallet -> buildStockKey(pallet.getProductId(), pallet.getWarehouseId(), pallet.getAreaId()),
Collectors.counting()));
}
private Long getPalletCount(ErpStockRespVO stock) {
return palletService.getOccupiedPalletList(Collections.singleton(stock.getProductId()),
Collections.singleton(stock.getWarehouseId()), Collections.singleton(stock.getAreaId())).stream()
.filter(pallet -> buildStockKey(stock.getProductId(), stock.getWarehouseId(), stock.getAreaId())
.equals(buildStockKey(pallet.getProductId(), pallet.getWarehouseId(), pallet.getAreaId())))
.count();
}
private String buildStockKey(Long productId, Long warehouseId, Long areaId) {
return String.valueOf(productId) + "_" + String.valueOf(warehouseId) + "_" + String.valueOf(areaId);
}
private String formatNumber(BigDecimal value) {
return value == null ? "0" : value.stripTrailingZeros().toPlainString();
}

@ -19,16 +19,19 @@ import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInRespVO
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSubmitReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.StockInTypeEnum;
import cn.iocoder.yudao.module.erp.dal.dataobject.pallet.ErpPalletDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInApproveRecordDO;
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.ErpStockInItemPalletDO;
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.enums.ErpStockInStatusEnum;
import cn.iocoder.yudao.module.erp.service.mold.MoldBrandService;
import cn.iocoder.yudao.module.erp.service.mold.MoldService;
import cn.iocoder.yudao.module.erp.service.pallet.ErpPalletService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService;
import cn.iocoder.yudao.module.erp.service.stock.ErpStockInService;
@ -92,6 +95,8 @@ public class ErpStockInController {
@Resource
private MoldService moldService;
@Resource
private ErpPalletService palletService;
@Resource
private AdminUserApi adminUserApi;
@PostMapping("/create")
@ -121,8 +126,8 @@ public class ErpStockInController {
}
@PutMapping("/submit")
@Operation(summary = "提交其它入库单审核")
@PreAuthorize("@ss.hasPermission('erp:stock-in:update')")
@Operation(summary = "提交入库单审核")
@PreAuthorize("@ss.hasPermission('erp:stock-in:submit')")
@RateLimiter(count = 1, timeUnit = TimeUnit.SECONDS)
public CommonResult<Boolean> submitStockInAudit(@Valid @RequestBody ErpStockInSubmitReqVO submitReqVO) {
stockInService.submitStockInAudit(submitReqVO);
@ -130,8 +135,8 @@ public class ErpStockInController {
}
@PutMapping("/audit")
@Operation(summary = "审核其它入库单")
@PreAuthorize("@ss.hasPermission('erp:stock-in:update-status')")
@Operation(summary = "审核入库单")
@PreAuthorize("@ss.hasPermission('erp:stock-in:audit')")
@RateLimiter(count = 1, timeUnit = TimeUnit.SECONDS)
public CommonResult<Boolean> auditStockIn(@Valid @RequestBody ErpStockInAuditReqVO auditReqVO) {
stockInService.auditStockIn(auditReqVO);
@ -246,17 +251,23 @@ public class ErpStockInController {
convertSet(allItems, ErpStockInItemDO::getMoldSetId));
Map<Long, List<cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO>> moldListMap = moldService.getMoldListMapByBrandIds(
convertSet(allItems, ErpStockInItemDO::getMoldSetId));
Map<Long, List<ErpStockInItemPalletDO>> itemPalletMap = stockInService.getStockInItemPalletListByInIds(
convertSet(stockIns, ErpStockInDO::getId)).stream()
.collect(Collectors.groupingBy(ErpStockInItemPalletDO::getInItemId));
Map<Long, ErpPalletDO> palletMap = palletService.getPalletMap(
convertSet(convertListByFlatMap(itemPalletMap.values(), Collection::stream), ErpStockInItemPalletDO::getPalletId));
Map<String, ErpStockDO> stockMap = buildStockMap(allItems);
List<ErpStockInRespVO> list = convertList(stockIns, stockIn -> buildStockInRespVO(
stockIn, itemMap.getOrDefault(stockIn.getId(), Collections.emptyList()), Collections.emptyList(),
userMap, supplierMap, stockMap, warehouseMap, areaMap, productMap, moldMap, moldListMap));
userMap, supplierMap, stockMap, warehouseMap, areaMap, productMap, moldMap, moldListMap,
itemPalletMap, palletMap));
return new PageResult<>(list, pageResult.getTotal());
}
private ErpStockInRespVO buildStockInRespVO(ErpStockInDO stockIn, List<ErpStockInItemDO> stockInItemList,
List<ErpStockInApproveRecordDO> approveRecords) {
return buildStockInRespVO(stockIn, stockInItemList, approveRecords,
null, null, null, null, null, null, null, null);
null, null, null, null, null, null, null, null, null, null);
}
private ErpStockInRespVO buildStockInRespVO(ErpStockInDO stockIn, List<ErpStockInItemDO> stockInItemList,
@ -268,7 +279,9 @@ public class ErpStockInController {
Map<Long, WarehouseAreaDO> pageAreaMap,
Map<Long, ErpProductRespVO> pageProductMap,
Map<Long, MoldBrandDO> pageMoldMap,
Map<Long, List<cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO>> pageMoldListMap) {
Map<Long, List<cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO>> pageMoldListMap,
Map<Long, List<ErpStockInItemPalletDO>> pageItemPalletMap,
Map<Long, ErpPalletDO> pagePalletMap) {
ErpStockInRespVO stockInVO = BeanUtils.toBean(stockIn, ErpStockInRespVO.class);
stockInVO.setStatusName(getStockInStatusName(stockIn.getStatus()));
Map<Long, ErpWarehouseDO> warehouseMap = pageWarehouseMap != null ? pageWarehouseMap : warehouseService.getWarehouseMap(
@ -278,6 +291,11 @@ public class ErpStockInController {
Map<Long, AdminUserRespDTO> userMap = pageUserMap != null ? pageUserMap : adminUserApi.getUserMap(convertListByFlatMap(
Collections.singletonList(stockIn), item -> Stream.of(NumberUtils.parseLong(item.getCreator()),
item.getStockUserId(), item.getAuditUserId())));
Map<Long, List<ErpStockInItemPalletDO>> itemPalletMap = pageItemPalletMap != null ? pageItemPalletMap
: stockInService.getStockInItemPalletListByInId(stockIn.getId()).stream()
.collect(Collectors.groupingBy(ErpStockInItemPalletDO::getInItemId));
Map<Long, ErpPalletDO> palletMap = pagePalletMap != null ? pagePalletMap : palletService.getPalletMap(
convertSet(convertListByFlatMap(itemPalletMap.values(), Collection::stream), ErpStockInItemPalletDO::getPalletId));
MapUtils.findAndThen(userMap, NumberUtils.parseLong(stockIn.getCreator()), user -> stockInVO.setCreatorName(user.getNickname()));
MapUtils.findAndThen(userMap, stockIn.getStockUserId(), user -> stockInVO.setStockUserName(user.getNickname()));
MapUtils.findAndThen(userMap, stockIn.getAuditUserId(), user -> stockInVO.setAuditUserName(user.getNickname()));
@ -294,6 +312,7 @@ public class ErpStockInController {
item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO);
item.setMoldList(moldListMap.getOrDefault(source.getMoldSetId(), new ArrayList<>()));
fillWarehouseInfo(item, source, warehouseMap, areaMap);
item.setPallets(buildStockInPalletRespList(itemPalletMap.get(source.getId()), palletMap));
MapUtils.findAndThen(moldMap, source.getMoldSetId(), mold -> {
item.setMoldSetName(mold.getName());
item.setProductName(mold.getName());
@ -316,6 +335,7 @@ public class ErpStockInController {
if (StringUtils.isBlank(item.getAreaName())) {
MapUtils.findAndThen(areaMap, item.getAreaId(), area -> item.setAreaName(area.getAreaName()));
}
item.setPallets(buildStockInPalletRespList(itemPalletMap.get(item.getId()), palletMap));
MapUtils.findAndThen(productMap, item.getProductId(), product -> {
item.setProductName(product.getName());
item.setProductBarCode(product.getBarCode());
@ -359,6 +379,20 @@ public class ErpStockInController {
return String.valueOf(productId) + "_" + String.valueOf(warehouseId) + "_" + String.valueOf(areaId);
}
private List<ErpStockInRespVO.Item.PalletItem> buildStockInPalletRespList(List<ErpStockInItemPalletDO> itemPallets,
Map<Long, ErpPalletDO> palletMap) {
if (CollUtil.isEmpty(itemPallets)) {
return Collections.emptyList();
}
return convertList(itemPallets, itemPallet -> {
ErpStockInRespVO.Item.PalletItem palletItem = new ErpStockInRespVO.Item.PalletItem();
palletItem.setPalletId(itemPallet.getPalletId());
palletItem.setPackageCount(itemPallet.getPackageCount());
MapUtils.findAndThen(palletMap, itemPallet.getPalletId(), pallet -> palletItem.setPalletCode(pallet.getCode()));
return palletItem;
});
}
private List<ErpStockInApproveRecordRespVO> buildApproveRecordRespList(List<ErpStockInApproveRecordDO> records) {
if (CollUtil.isEmpty(records)) {
return new ArrayList<>();

@ -19,14 +19,17 @@ import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutResp
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSubmitReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.StockOutTypeEnum;
import cn.iocoder.yudao.module.erp.dal.dataobject.pallet.ErpPalletDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutApproveRecordDO;
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.ErpStockOutItemPalletDO;
import cn.iocoder.yudao.module.erp.enums.ErpStockOutStatusEnum;
import cn.iocoder.yudao.module.erp.service.mold.MoldBrandService;
import cn.iocoder.yudao.module.erp.service.mold.MoldService;
import cn.iocoder.yudao.module.erp.service.pallet.ErpPalletService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService;
import cn.iocoder.yudao.module.erp.service.stock.ErpStockOutService;
@ -90,6 +93,8 @@ public class ErpStockOutController {
@Resource
private MoldService moldService;
@Resource
private ErpPalletService palletService;
@Resource
private AdminUserApi adminUserApi;
@PostMapping("/create")
@ -119,8 +124,8 @@ public class ErpStockOutController {
}
@PutMapping("/submit")
@Operation(summary = "提交其它出库单审核")
@PreAuthorize("@ss.hasPermission('erp:stock-out:update')")
@Operation(summary = "提交出库单审核")
@PreAuthorize("@ss.hasPermission('erp:stock-out:submit')")
@RateLimiter(count = 1, timeUnit = TimeUnit.SECONDS)
public CommonResult<Boolean> submitStockOutAudit(@Valid @RequestBody ErpStockOutSubmitReqVO submitReqVO) {
stockOutService.submitStockOutAudit(submitReqVO);
@ -128,8 +133,8 @@ public class ErpStockOutController {
}
@PutMapping("/audit")
@Operation(summary = "审核其它出库单")
@PreAuthorize("@ss.hasPermission('erp:stock-out:update-status')")
@Operation(summary = "审核出库单")
@PreAuthorize("@ss.hasPermission('erp:stock-out:audit')")
@RateLimiter(count = 1, timeUnit = TimeUnit.SECONDS)
public CommonResult<Boolean> auditStockOut(@Valid @RequestBody ErpStockOutAuditReqVO auditReqVO) {
stockOutService.auditStockOut(auditReqVO);
@ -250,17 +255,22 @@ public class ErpStockOutController {
convertSet(allItems, ErpStockOutItemDO::getMoldSetId));
Map<Long, List<cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO>> moldListMap = moldService.getMoldListMapByBrandIds(
convertSet(allItems, ErpStockOutItemDO::getMoldSetId));
Map<Long, List<ErpStockOutItemPalletDO>> itemPalletMap = stockOutService.getStockOutItemPalletListByOutIds(
convertSet(stockOuts, ErpStockOutDO::getId)).stream()
.collect(Collectors.groupingBy(ErpStockOutItemPalletDO::getOutItemId));
Map<Long, ErpPalletDO> palletMap = palletService.getPalletMap(
convertSet(convertListByFlatMap(itemPalletMap.values(), Collection::stream), ErpStockOutItemPalletDO::getPalletId));
Map<String, ErpStockDO> stockMap = buildStockMap(allItems);
List<ErpStockOutRespVO> list = convertList(stockOuts, stockOut -> buildStockOutRespVO(
stockOut, itemMap.getOrDefault(stockOut.getId(), Collections.emptyList()), Collections.emptyList(),
userMap, customerMap, stockMap, productMap, moldMap, moldListMap));
userMap, customerMap, stockMap, productMap, moldMap, moldListMap, itemPalletMap, palletMap));
return new PageResult<>(list, pageResult.getTotal());
}
private ErpStockOutRespVO buildStockOutRespVO(ErpStockOutDO stockOut, List<ErpStockOutItemDO> stockOutItemList,
List<ErpStockOutApproveRecordDO> approveRecords) {
return buildStockOutRespVO(stockOut, stockOutItemList, approveRecords,
null, null, null, null, null, null);
null, null, null, null, null, null, null, null);
}
private ErpStockOutRespVO buildStockOutRespVO(ErpStockOutDO stockOut, List<ErpStockOutItemDO> stockOutItemList,
@ -270,12 +280,19 @@ public class ErpStockOutController {
Map<String, ErpStockDO> pageStockMap,
Map<Long, ErpProductRespVO> pageProductMap,
Map<Long, MoldBrandDO> pageMoldMap,
Map<Long, List<cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO>> pageMoldListMap) {
Map<Long, List<cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO>> pageMoldListMap,
Map<Long, List<ErpStockOutItemPalletDO>> pageItemPalletMap,
Map<Long, ErpPalletDO> pagePalletMap) {
ErpStockOutRespVO stockOutVO = BeanUtils.toBean(stockOut, ErpStockOutRespVO.class);
stockOutVO.setStatusName(getStockOutStatusName(stockOut.getStatus()));
Map<Long, AdminUserRespDTO> userMap = pageUserMap != null ? pageUserMap : adminUserApi.getUserMap(convertListByFlatMap(
Collections.singletonList(stockOut), item -> Stream.of(NumberUtils.parseLong(item.getCreator()),
item.getResponserId(), item.getAuditUserId())));
Map<Long, List<ErpStockOutItemPalletDO>> itemPalletMap = pageItemPalletMap != null ? pageItemPalletMap
: stockOutService.getStockOutItemPalletListByOutId(stockOut.getId()).stream()
.collect(Collectors.groupingBy(ErpStockOutItemPalletDO::getOutItemId));
Map<Long, ErpPalletDO> palletMap = pagePalletMap != null ? pagePalletMap : palletService.getPalletMap(
convertSet(convertListByFlatMap(itemPalletMap.values(), Collection::stream), ErpStockOutItemPalletDO::getPalletId));
MapUtils.findAndThen(userMap, NumberUtils.parseLong(stockOut.getCreator()), user -> stockOutVO.setCreatorName(user.getNickname()));
MapUtils.findAndThen(userMap, stockOut.getResponserId(), user -> stockOutVO.setResponserName(user.getNickname()));
MapUtils.findAndThen(userMap, stockOut.getAuditUserId(), user -> stockOutVO.setAuditUserName(user.getNickname()));
@ -291,6 +308,7 @@ public class ErpStockOutController {
: stockService.getStock(source.getMoldSetId(), source.getWarehouseId(), source.getAreaId());
item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO);
item.setMoldList(moldListMap.getOrDefault(source.getMoldSetId(), new ArrayList<>()));
item.setPallets(buildStockOutPalletRespList(itemPalletMap.get(source.getId()), palletMap));
MapUtils.findAndThen(moldMap, source.getMoldSetId(), mold -> {
item.setMoldSetName(mold.getName());
item.setProductName(mold.getName());
@ -307,6 +325,7 @@ public class ErpStockOutController {
ErpStockDO stock = pageStockMap != null ? pageStockMap.get(buildStockKey(item.getProductId(), item.getWarehouseId(), item.getAreaId()))
: stockService.getStock(item.getProductId(), item.getWarehouseId(), item.getAreaId());
item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO);
item.setPallets(buildStockOutPalletRespList(itemPalletMap.get(item.getId()), palletMap));
MapUtils.findAndThen(productMap, item.getProductId(), product -> {
item.setProductName(product.getName());
item.setProductBarCode(product.getBarCode());
@ -369,6 +388,20 @@ public class ErpStockOutController {
return String.valueOf(productId) + "_" + String.valueOf(warehouseId) + "_" + String.valueOf(areaId);
}
private List<ErpStockOutRespVO.Item.PalletItem> buildStockOutPalletRespList(List<ErpStockOutItemPalletDO> itemPallets,
Map<Long, ErpPalletDO> palletMap) {
if (CollUtil.isEmpty(itemPallets)) {
return Collections.emptyList();
}
return convertList(itemPallets, itemPallet -> {
ErpStockOutRespVO.Item.PalletItem palletItem = new ErpStockOutRespVO.Item.PalletItem();
palletItem.setPalletId(itemPallet.getPalletId());
palletItem.setPackageCount(itemPallet.getPackageCount());
MapUtils.findAndThen(palletMap, itemPallet.getPalletId(), pallet -> palletItem.setPalletCode(pallet.getCode()));
return palletItem;
});
}
private List<ErpStockOutApproveRecordRespVO> buildApproveRecordRespList(List<ErpStockOutApproveRecordDO> records) {
if (CollUtil.isEmpty(records)) {
return new ArrayList<>();

@ -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.PageParam;
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.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.ErpWarehouseSummaryRespVO;
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.framework.common.util.object.BeanUtils;
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.ErpWarehouseSummaryService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
@ -38,6 +42,8 @@ public class ErpWarehouseController {
@Resource
private ErpWarehouseService warehouseService;
@Resource
private ErpWarehouseSummaryService warehouseSummaryService;
@PostMapping("/create")
@Operation(summary = "创建仓库")
@ -93,10 +99,21 @@ public class ErpWarehouseController {
@GetMapping("/simple-list")
@Operation(summary = "获得仓库精简列表", description = "只包含被开启的仓库,主要用于前端的下拉选项")
public CommonResult<List<ErpWarehouseRespVO>> getWarehouseSimpleList() {
List<ErpWarehouseDO> list = warehouseService.getWarehouseListByStatus(CommonStatusEnum.ENABLE.getStatus());
@Parameter(name = "categoryType", description = "仓库分类", example = "1")
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())
.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")

@ -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 lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.util.List;
@Schema(description = "管理后台 - ERP 库存盘点按仓库/库区生成盘点项 Request VO")
@ -16,8 +15,11 @@ public class ErpStockCheckGenerateByLocationReqVO {
@Schema(description = "库区编号列表", example = "[11,12]")
private List<Long> areaIds;
@Schema(description = "是否允许为空,默认 false", example = "false")
private Boolean allowEmpty;
@Schema(description = "是否允许为空库存,默认 true", example = "true")
private Boolean allowEmpty = Boolean.TRUE;
@Schema(description = "选择分类", example = "1")
private Integer categoryType;
public boolean validSelection() {
return (warehouseIds != null && !warehouseIds.isEmpty()) || (areaIds != null && !areaIds.isEmpty());

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

@ -42,6 +42,12 @@ public class ErpStockCheckPageReqVO extends PageParam {
@Schema(description = "产品编号", example = "1")
private Long productId;
@Schema(description = "选择分类", example = "1")
private Integer categoryType;
@Schema(description = "盘点状态0-未盘点1-已盘点", example = "1")
private Integer checkStatus;
@Schema(description = "id集合导出用")
private String ids;
}
}

@ -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.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.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 javax.validation.constraints.NotNull;
import lombok.Data;
@ -29,8 +35,28 @@ public class ErpStockCheckRespVO {
@Schema(description = "盘点时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("盘点时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
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 = "选择分类", 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 = "true")
private Boolean needAudit;
@Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663")
@ExcelProperty("合计数量")
private BigDecimal totalCount;
@ -104,8 +130,7 @@ public class ErpStockCheckRespVO {
@NotNull(message = "账面数量不能为空")
private BigDecimal stockCount;
@Schema(description = "实际数量(实际库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
@NotNull(message = "实际数量不能为空")
@Schema(description = "实际数量(实际库存)", example = "100.00")
private BigDecimal actualCount;
@Schema(description = "盈亏数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")

@ -1,6 +1,13 @@
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 cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.erp.enums.stock.ErpStockCheckSourceTypeEnum;
import lombok.Data;
import javax.validation.Valid;
@ -17,17 +24,34 @@ public class ErpStockCheckSaveReqVO {
@Schema(description = "盘点编号", example = "11756")
private Long id;
@Schema(description = "盘点编码", example = "11756")
private String code;
@Schema(description = "盘点时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "盘点时间不能为空")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime checkTime;
@Schema(description = "生成来源类型1-按库存2-按产品", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "生成来源类型不能为空")
@InEnum(ErpStockCheckSourceTypeEnum.class)
private Integer sourceType;
@Schema(description = "选择分类", example = "1")
private Integer categoryType;
@Schema(description = "盘点状态0-未盘点1-已盘点", example = "1")
private Integer checkStatus;
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc")
private String fileUrl;
@Schema(description = "盘点项列表", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "盘点项列表", implementation = Item.class)
@NotEmpty(message = "盘点项列表不能为空")
@Valid
private List<Item> items;
@ -56,8 +80,7 @@ public class ErpStockCheckSaveReqVO {
@NotNull(message = "账面数量不能为空")
private BigDecimal stockCount;
@Schema(description = "实际数量(实际库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
@NotNull(message = "实际数量不能为空")
@Schema(description = "实际数量(实际库存)", example = "100.00")
private BigDecimal actualCount;
@Schema(description = "盈亏数量,服务端自动按 实际数量 - 账面数量 计算", example = "100.00")

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

@ -141,9 +141,36 @@ public class ErpStockInRespVO {
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
private BigDecimal count;
@Schema(description = "是否关联任务单", example = "true")
private Boolean relateTask;
@Schema(description = "任务单 ID", example = "10001")
private Long taskId;
@Schema(description = "包装方案 ID", example = "1")
private Long packagingSchemeId;
@Schema(description = "包装方案名称", example = "标准包装")
private String packagingSchemeName;
@Schema(description = "每包数量", example = "10.00")
private BigDecimal packageQuantity;
@Schema(description = "每托包数", example = "20.00")
private BigDecimal palletPackageQuantity;
@Schema(description = "每托总数量", example = "200.00")
private BigDecimal palletTotalQuantity;
@Schema(description = "托数", example = "2.00")
private BigDecimal palletCount;
@Schema(description = "包数", example = "40.00")
private BigDecimal packageCount;
@Schema(description = "个数", example = "400.00")
private BigDecimal pieceCount;
@Schema(description = "单位输入方式", example = "包")
private String inputUnitType;
@ -177,7 +204,23 @@ public class ErpStockInRespVO {
@Schema(description = "库存数量", example = "100.00")
private BigDecimal stockCount;
@Schema(description = "托盘列表")
private List<PalletItem> pallets;
@Schema(description = "子模具详情")
private List<MoldDO> moldList;
@Data
public static class PalletItem {
@Schema(description = "托盘 ID", example = "1")
private Long palletId;
@Schema(description = "托盘编码", example = "TP20240601001")
private String palletCode;
@Schema(description = "包数", example = "10")
private BigDecimal packageCount;
}
}
}

@ -76,16 +76,58 @@ public class ErpStockInSaveReqVO {
@Schema(description = "包装方案 ID", example = "1")
private Long packagingSchemeId;
@Schema(description = "包装方案名称", example = "标准包装")
private String packagingSchemeName;
@Schema(description = "每包数量", example = "10")
private BigDecimal packageQuantity;
@Schema(description = "每托包数", example = "20")
private BigDecimal palletPackageQuantity;
@Schema(description = "每托总数量", example = "200")
private BigDecimal palletTotalQuantity;
@Schema(description = "托数", example = "1")
private BigDecimal palletCount;
@Schema(description = "包数", example = "10")
private BigDecimal packageCount;
@Schema(description = "个数", example = "100")
private BigDecimal pieceCount;
@Schema(description = "单位输入方式", example = "包")
private String inputUnitType;
@Schema(description = "录入数量", example = "10.00")
private BigDecimal inputCount;
@Schema(description = "是否关联任务单", example = "true")
private Boolean relateTask;
@Schema(description = "任务单ID", example = "10001")
private Long taskId;
@Schema(description = "托盘列表")
@Valid
private List<PalletItem> pallets;
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "设备 id", example = "100")
private Long deviceId;
@Data
public static class PalletItem {
@Schema(description = "托盘ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "托盘ID不能为空")
private Long palletId;
@Schema(description = "包数", example = "10")
private BigDecimal packageCount;
}
}
}

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

@ -181,6 +181,39 @@ public class ErpStockOutRespVO {
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
private BigDecimal count;
@Schema(description = "包装方案 ID", example = "1")
private Long packagingSchemeId;
@Schema(description = "包装方案名称", example = "标准包装")
private String packagingSchemeName;
@Schema(description = "每包数量", example = "10.00")
private BigDecimal packageQuantity;
@Schema(description = "每托包数", example = "20.00")
private BigDecimal palletPackageQuantity;
@Schema(description = "每托总数量", example = "200.00")
private BigDecimal palletTotalQuantity;
@Schema(description = "托数", example = "2.00")
private BigDecimal palletCount;
@Schema(description = "包数", example = "40.00")
private BigDecimal packageCount;
@Schema(description = "个数", example = "400.00")
private BigDecimal pieceCount;
@Schema(description = "单位输入方式", example = "包")
private String inputUnitType;
@Schema(description = "录入数量", example = "10.00")
private BigDecimal inputCount;
@Schema(description = "出库方式1-按托出库 2-拆托出库", example = "1")
private Integer outMode;
@Schema(description = "出库用途", example = "1")
private Integer outUsageType;
@ -226,8 +259,24 @@ public class ErpStockOutRespVO {
@Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
private BigDecimal stockCount;
@Schema(description = "托盘列表")
private List<PalletItem> pallets;
@Schema(description = "子模具列表")
private List<MoldDO> moldList;
@Data
public static class PalletItem {
@Schema(description = "托盘 ID", example = "1")
private Long palletId;
@Schema(description = "托盘编码", example = "TP20240601001")
private String palletCode;
@Schema(description = "包数", example = "10")
private BigDecimal packageCount;
}
}
}

@ -5,8 +5,12 @@ import cn.iocoder.yudao.module.erp.enums.ErpStockOutUsageTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.List;
import cn.iocoder.yudao.module.erp.enums.stock.ErpStockOutModeEnum;
@Schema(description = "ERP 其它出库单明细项")
@Data
@ -33,9 +37,43 @@ public class ErpStockOutSaveReqVOItem {
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
private BigDecimal count;
@Schema(description = "包装方案 ID", example = "1")
private Long packagingSchemeId;
@Schema(description = "包装方案名称", example = "标准包装")
private String packagingSchemeName;
@Schema(description = "每包数量", example = "10.00")
private BigDecimal packageQuantity;
@Schema(description = "每托包数", example = "20.00")
private BigDecimal palletPackageQuantity;
@Schema(description = "每托总数量", example = "200.00")
private BigDecimal palletTotalQuantity;
@Schema(description = "托数", example = "2.00")
private BigDecimal palletCount;
@Schema(description = "包数", example = "40.00")
private BigDecimal packageCount;
@Schema(description = "个数", example = "400.00")
private BigDecimal pieceCount;
@Schema(description = "单位输入方式", example = "包")
private String inputUnitType;
@Schema(description = "录入数量", example = "10.00")
private BigDecimal inputCount;
@Schema(description = "出库方式1-按托出库 2-拆托出库", example = "1")
@InEnum(ErpStockOutModeEnum.class)
private Integer outMode;
@Schema(description = "出库用途", example = "1")
@InEnum(ErpStockOutUsageTypeEnum.class)
@NotNull(message = "出库用途不能为空")
// @NotNull(message = "出库用途不能为空")
private Integer outUsageType;
@Schema(description = "维修单编号", example = "1001")
@ -49,4 +87,19 @@ public class ErpStockOutSaveReqVOItem {
@Schema(description = "备注", example = "备注信息")
private String remark;
@Schema(description = "托盘列表")
@Valid
private List<PalletItem> pallets;
@Data
public static class PalletItem {
@Schema(description = "托盘ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "托盘ID不能为空")
private Long palletId;
@Schema(description = "包数", example = "10")
private BigDecimal packageCount;
}
}

@ -95,6 +95,9 @@ public class ErpStockRespVO {
@ExcelProperty("库存展示")
private String stockDisplay;
@Schema(description = "托盘数量", example = "2")
private Long palletCount;
// ========== 仓库信息 ==========
@Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")

@ -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.pojo.PageParam;
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 lombok.Data;
import lombok.EqualsAndHashCode;
@ -17,10 +18,14 @@ public class ErpWarehousePageReqVO extends PageParam {
@Schema(description = "仓库名称", example = "李四")
private String name;
@Schema(description = "仓库分类", example = "1")
@InEnum(ErpWarehouseCategoryEnum.class)
private Integer categoryType;
@Schema(description = "开启状态", example = "1")
@InEnum(CommonStatusEnum.class)
private Integer status;
@Schema(description = "id集合导出用")
private String ids;
}
}

@ -27,6 +27,10 @@ public class ErpWarehouseRespVO {
@ExcelProperty("仓库名称")
private String name;
@Schema(description = "仓库分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty("仓库分类")
private Integer categoryType;
@Schema(description = "仓库地址", example = "上海陆家嘴")
@ExcelProperty("仓库地址")
private String address;
@ -78,5 +82,4 @@ public class ErpWarehouseRespVO {
@Schema(description = "库位列表")
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.validation.InEnum;
import cn.iocoder.yudao.module.erp.controller.admin.stock.enums.ErpWarehouseCategoryEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -20,6 +21,11 @@ public class ErpWarehouseSaveReqVO {
@NotEmpty(message = "仓库名称不能为空")
private String name;
@Schema(description = "仓库分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "仓库分类不能为空")
@InEnum(ErpWarehouseCategoryEnum.class)
private Integer categoryType;
@Schema(description = "仓库地址", example = "上海陆家嘴")
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,22 @@ public class ErpStockCheckDO extends BaseDO {
*
*/
private LocalDateTime checkTime;
/**
* 1-2-
*/
private Integer sourceType;
/**
*
*/
private Integer categoryType;
/**
* 0-1-
*/
private Integer checkStatus;
/**
*
*/
private Boolean needAudit;
/**
*
*/

@ -70,6 +70,34 @@ public class ErpStockInItemDO extends BaseDO {
* ID
*/
private Long packagingSchemeId;
/**
*
*/
private String packagingSchemeName;
/**
*
*/
private BigDecimal packageQuantity;
/**
*
*/
private BigDecimal palletPackageQuantity;
/**
*
*/
private BigDecimal palletTotalQuantity;
/**
*
*/
private BigDecimal palletCount;
/**
*
*/
private BigDecimal packageCount;
/**
*
*/
private BigDecimal pieceCount;
/**
* //
*/
@ -78,6 +106,8 @@ public class ErpStockInItemDO extends BaseDO {
*
*/
private BigDecimal inputCount;
private Boolean relateTask;
private Long taskId;
/**
*
*/

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.erp.dal.dataobject.stock;
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;
@TableName("erp_stock_in_item_pallet")
@KeySequence("erp_stock_in_item_pallet_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ErpStockInItemPalletDO extends BaseDO {
@TableId
private Long id;
private Long inId;
private Long inItemId;
private Long palletId;
private BigDecimal packageCount;
}

@ -105,6 +105,47 @@ public class ErpStockOutItemDO extends BaseDO {
*
*/
private BigDecimal count;
/**
* ID
*/
private Long packagingSchemeId;
/**
*
*/
private String packagingSchemeName;
/**
*
*/
private BigDecimal packageQuantity;
/**
*
*/
private BigDecimal palletPackageQuantity;
/**
*
*/
private BigDecimal palletTotalQuantity;
/**
*
*/
private BigDecimal palletCount;
/**
*
*/
private BigDecimal packageCount;
/**
*
*/
private BigDecimal pieceCount;
/**
* //
*/
private String inputUnitType;
/**
*
*/
private BigDecimal inputCount;
private Integer outMode;
/**
*
*/

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.erp.dal.dataobject.stock;
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;
@TableName("erp_stock_out_item_pallet")
@KeySequence("erp_stock_out_item_pallet_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ErpStockOutItemPalletDO extends BaseDO {
@TableId
private Long id;
private Long outId;
private Long outItemId;
private Long palletId;
private BigDecimal packageCount;
}

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

@ -0,0 +1,52 @@
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.math.BigDecimal;
import java.util.Collection;
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);
}
default List<ErpPalletDO> selectOccupiedList(Collection<Long> productIds, Collection<Long> warehouseIds,
Collection<Long> areaIds) {
boolean containsNullArea = areaIds != null && areaIds.stream().anyMatch(java.util.Objects::isNull);
return selectList(new LambdaQueryWrapperX<ErpPalletDO>()
.inIfPresent(ErpPalletDO::getProductId, productIds)
.inIfPresent(ErpPalletDO::getWarehouseId, warehouseIds)
.inIfPresent(ErpPalletDO::getAreaId, containsNullArea ? null : areaIds)
.gt(ErpPalletDO::getProductCount, BigDecimal.ZERO));
}
}

@ -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.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.ErpStockCheckItemDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO;
import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
@ -27,15 +25,21 @@ public interface ErpStockCheckMapper extends BaseMapperX<ErpStockCheckDO> {
MPJLambdaWrapperX<ErpStockCheckDO> query = new MPJLambdaWrapperX<ErpStockCheckDO>()
.likeIfPresent(ErpStockCheckDO::getNo, reqVO.getNo())
.betweenIfPresent(ErpStockCheckDO::getCheckTime, reqVO.getCheckTime())
.eqIfPresent(ErpStockCheckDO::getCategoryType, reqVO.getCategoryType())
.eqIfPresent(ErpStockCheckDO::getCheckStatus, reqVO.getCheckStatus())
.eqIfPresent(ErpStockCheckDO::getStatus, reqVO.getStatus())
.likeIfPresent(ErpStockCheckDO::getRemark, reqVO.getRemark())
.eqIfPresent(ErpStockCheckDO::getCreator, reqVO.getCreator())
.orderByDesc(ErpStockCheckDO::getId);
if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) {
query.leftJoin(ErpStockCheckItemDO.class, ErpStockCheckItemDO::getCheckId, ErpStockCheckDO::getId)
.eq(reqVO.getWarehouseId() != null, ErpStockCheckItemDO::getWarehouseId, reqVO.getWarehouseId())
.eq(reqVO.getProductId() != null, ErpStockCheckItemDO::getProductId, reqVO.getProductId())
.groupBy(ErpStockCheckDO::getId); // 避免 1 对多查询,产生相同的 1
StringBuilder itemFilterSql = new StringBuilder("select distinct check_id from erp_stock_check_item where deleted = 0");
if (reqVO.getWarehouseId() != null) {
itemFilterSql.append(" and warehouse_id = ").append(reqVO.getWarehouseId());
}
if (reqVO.getProductId() != null) {
itemFilterSql.append(" and product_id = ").append(reqVO.getProductId());
}
query.inSql(ErpStockCheckDO::getId, itemFilterSql.toString());
}
@ -61,4 +65,4 @@ public interface ErpStockCheckMapper extends BaseMapperX<ErpStockCheckDO> {
return selectOne(ErpStockCheckDO::getNo, no);
}
}
}

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.erp.dal.mysql.stock;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemPalletDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
@Mapper
public interface ErpStockInItemPalletMapper extends BaseMapperX<ErpStockInItemPalletDO> {
default List<ErpStockInItemPalletDO> selectListByInId(Long inId) {
return selectList(ErpStockInItemPalletDO::getInId, inId);
}
default List<ErpStockInItemPalletDO> selectListByInIds(Collection<Long> inIds) {
return selectList(ErpStockInItemPalletDO::getInId, inIds);
}
default int deleteByInId(Long inId) {
return delete(ErpStockInItemPalletDO::getInId, inId);
}
}

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

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.erp.dal.mysql.stock;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemPalletDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
@Mapper
public interface ErpStockOutItemPalletMapper extends BaseMapperX<ErpStockOutItemPalletDO> {
default List<ErpStockOutItemPalletDO> selectListByOutId(Long outId) {
return selectList(ErpStockOutItemPalletDO::getOutId, outId);
}
default List<ErpStockOutItemPalletDO> selectListByOutIds(Collection<Long> outIds) {
return selectList(ErpStockOutItemPalletDO::getOutId, outIds);
}
default int deleteByOutId(Long outId) {
return delete(ErpStockOutItemPalletDO::getOutId, outId);
}
}

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

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.erp.handler;
import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum;
import cn.iocoder.yudao.module.common.handler.QrcodeBizHandler;
import cn.iocoder.yudao.module.erp.dal.mysql.pallet.ErpPalletMapper;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class PalletQrcodeBizHandler implements QrcodeBizHandler {
@Resource
private ErpPalletMapper palletMapper;
@Override
public String getBizType() {
return QrcodeBizTypeEnum.PALLET.getCode();
}
@Override
public boolean exists(Long id) {
return palletMapper.selectById(id) != null;
}
@Override
public String buildDeepLink(Long id) {
return "https://www.baidu.com";
}
@Override
public String buildH5Path(Long id) {
return "https://baike.baidu.com/item/%E6%98%9F%E5%BA%A7/8072715?fr=aladdin";
}
}

@ -0,0 +1,35 @@
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.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public interface ErpPalletService {
Long createPallet(@Valid ErpPalletSaveReqVO createReqVO);
void updatePallet(@Valid ErpPalletSaveReqVO updateReqVO);
void deletePallet(Long id);
ErpPalletDO getPallet(Long id);
List<ErpPalletDO> getPalletList(Collection<Long> ids);
Map<Long, ErpPalletDO> getPalletMap(Collection<Long> ids);
PageResult<ErpPalletDO> getPalletPage(ErpPalletPageReqVO pageReqVO);
List<ErpPalletDO> getPalletListByStatus(Integer status);
List<ErpPalletDO> getOccupiedPalletList(Collection<Long> productIds, Collection<Long> warehouseIds, Collection<Long> areaIds);
void regenerateCode(Long id, String code) throws UnsupportedEncodingException;
}

@ -0,0 +1,205 @@
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.common.enums.CodeTypeEnum;
import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum;
import cn.iocoder.yudao.module.common.service.qrcordrecord.QrcodeRecordService;
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.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PALLET_CODE_EMPTY;
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;
@Resource
private QrcodeRecordService qrcodeService;
@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);
generatePalletQrcode(pallet.getId(), pallet.getCode());
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 List<ErpPalletDO> getPalletList(Collection<Long> ids) {
return ids == null || ids.isEmpty() ? Collections.emptyList() : palletMapper.selectBatchIds(ids);
}
@Override
public Map<Long, ErpPalletDO> getPalletMap(Collection<Long> ids) {
return convertMap(getPalletList(ids), ErpPalletDO::getId);
}
@Override
public PageResult<ErpPalletDO> getPalletPage(ErpPalletPageReqVO pageReqVO) {
return palletMapper.selectPage(pageReqVO);
}
@Override
public List<ErpPalletDO> getPalletListByStatus(Integer status) {
return palletMapper.selectListByStatus(status);
}
@Override
public List<ErpPalletDO> getOccupiedPalletList(Collection<Long> productIds, Collection<Long> warehouseIds,
Collection<Long> areaIds) {
return palletMapper.selectOccupiedList(productIds, warehouseIds, areaIds);
}
@Override
public void regenerateCode(Long id, String code) throws UnsupportedEncodingException {
validatePalletExists(id);
if (StringUtils.isBlank(code)) {
throw exception(PALLET_CODE_EMPTY);
}
CodeTypeEnum codeType = autoCodeUtil.queryCodeType("PALLET_CODE_GENERATE");
qrcodeService.regenerateByCodeType(
QrcodeBizTypeEnum.PALLET,
id,
code,
"DETAIL",
codeType.getCode()
);
}
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);
}
}
private void generatePalletQrcode(Long id, String code) {
CodeTypeEnum codeType = autoCodeUtil.queryCodeType("PALLET_CODE_GENERATE");
if (codeType == null) {
return;
}
try {
qrcodeService.generateOrRefresh(
QrcodeBizTypeEnum.PALLET,
id,
code,
"DETAIL",
codeType
);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}

@ -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.object.BeanUtils;
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.ErpStockCheckGenerateByLocationReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckGenerateByProductReqVO;
@ -29,13 +29,18 @@ 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.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;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
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.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@ -55,22 +60,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.diffList;
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.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;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
@Service
@Validated
@ -98,18 +88,37 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
private AdminUserApi adminUserApi;
@Resource
private PermissionApi permissionApi;
@Autowired
private AutoCodeUtil autoCodeUtil;
@Resource
private ConfigApi configApi;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createStockCheck(ErpStockCheckSaveReqVO createReqVO) {
String code = createReqVO.getCode();
validateSourceType(createReqVO.getSourceType());
List<ErpStockCheckItemDO> stockCheckItems = validateStockCheckItems(createReqVO.getItems());
String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_CHECK_NO_PREFIX);
if (stockCheckMapper.selectByNo(no) != null) {
throw exception(STOCK_CHECK_NO_EXISTS);
// String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_CHECK_NO_PREFIX);
// if (stockCheckMapper.selectByNo(no) != null) {
// 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
.setNo(no)
.setNo(finalCode)
.setNeedAudit(needAudit())
.setStatus(ErpAuditStatus.DRAFT.getStatus())
.setTotalCount(getSumValue(stockCheckItems, ErpStockCheckItemDO::getCount, BigDecimal::add, BigDecimal.ZERO))
.setTotalPrice(getSumValue(stockCheckItems, ErpStockCheckItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)));
@ -130,8 +139,10 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
throw exception(STOCK_CHECK_UPDATE_FAIL_PROCESS, stockCheck.getNo());
}
validateSourceType(updateReqVO.getSourceType());
List<ErpStockCheckItemDO> stockCheckItems = validateStockCheckItems(updateReqVO.getItems());
ErpStockCheckDO updateObj = BeanUtils.toBean(updateReqVO, ErpStockCheckDO.class, in -> in
.setNeedAudit(needAudit())
.setTotalCount(getSumValue(stockCheckItems, ErpStockCheckItemDO::getCount, BigDecimal::add, BigDecimal.ZERO))
.setTotalPrice(getSumValue(stockCheckItems, ErpStockCheckItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)));
stockCheckMapper.updateById(updateObj);
@ -179,15 +190,16 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
throw exception(STOCK_CHECK_SUBMIT_FAIL_STATUS);
}
Integer fromStatus = stockCheck.getStatus();
Long auditUserId = submitReqVO.getAuditUserId() != null ? submitReqVO.getAuditUserId() : stockCheck.getAuditUserId();
if (auditUserId == null) {
throw exception(STOCK_CHECK_SUBMIT_FAIL_AUDIT_USER_EMPTY);
if (auditUserId != null) {
adminUserApi.validateUser(auditUserId);
}
adminUserApi.validateUser(auditUserId);
Integer fromStatus = stockCheck.getStatus();
int updateCount = stockCheckMapper.updateByIdAndStatus(stockCheck.getId(), fromStatus,
new ErpStockCheckDO().setAuditUserId(auditUserId).setStatus(ErpAuditStatus.PROCESS.getStatus()));
ErpStockCheckDO updateObj = new ErpStockCheckDO()
.setAuditUserId(auditUserId)
.setStatus(ErpAuditStatus.PROCESS.getStatus());
int updateCount = stockCheckMapper.updateByIdAndStatus(stockCheck.getId(), fromStatus, updateObj);
if (updateCount == 0) {
throw exception(STOCK_CHECK_SUBMIT_FAIL_STATUS);
}
@ -200,8 +212,23 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
@Transactional(rollbackFor = Exception.class)
public void auditStockCheck(ErpStockCheckAuditReqVO auditReqVO) {
ErpStockCheckDO stockCheck = validateStockCheckExists(auditReqVO.getId());
if (!ErpAuditStatus.PROCESS.getStatus().equals(stockCheck.getStatus())) {
throw exception(STOCK_CHECK_AUDIT_FAIL_STATUS);
// if (!ErpAuditStatus.PROCESS.getStatus().equals(stockCheck.getStatus())) {
// throw exception(STOCK_CHECK_AUDIT_FAIL_STATUS);
// }
Integer fromStatus = stockCheck.getStatus();
if (!needAudit()) {
int updateCount = stockCheckMapper.updateByIdAndStatus(stockCheck.getId(), fromStatus,
new ErpStockCheckDO().setNeedAudit(false).setStatus(ErpAuditStatus.APPROVE.getStatus()));
if (updateCount == 0) {
throw exception(STOCK_CHECK_AUDIT_FAIL_STATUS);
}
List<ErpStockCheckItemDO> stockCheckItems = stockCheckItemMapper.selectListByCheckId(stockCheck.getId());
applyStockCheckEffect(stockCheck, stockCheckItems);
createApproveRecord(stockCheck.getId(), ErpStockCheckApproveActionEnum.AUTO_APPROVE,
fromStatus, ErpAuditStatus.APPROVE.getStatus(), NumberUtils.parseLong(stockCheck.getCreator()),
auditReqVO.getRemark() != null ? auditReqVO.getRemark() : "无需审核,审核时自动盘点");
return;
}
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
@ -214,9 +241,8 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
throw exception(STOCK_CHECK_AUDIT_FAIL_RESULT);
}
Integer fromStatus = stockCheck.getStatus();
int updateCount = stockCheckMapper.updateByIdAndStatus(stockCheck.getId(), fromStatus,
new ErpStockCheckDO().setStatus(auditReqVO.getStatus()));
new ErpStockCheckDO().setNeedAudit(true).setStatus(auditReqVO.getStatus()));
if (updateCount == 0) {
throw exception(STOCK_CHECK_AUDIT_FAIL_STATUS);
}
@ -288,10 +314,9 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
if (reqVO == null || !reqVO.validSelection()) {
return Collections.emptyList();
}
List<ErpStockDO> stockList = stockMapper.selectListByWarehouseIdsAndAreaIds(reqVO.getWarehouseIds(), reqVO.getAreaIds());
if (!Boolean.TRUE.equals(reqVO.getAllowEmpty())) {
stockList = filterNonZeroStocks(stockList);
}
boolean nonZeroOnly = Boolean.FALSE.equals(reqVO.getAllowEmpty());
List<ErpStockDO> stockList = stockMapper.selectListByWarehouseIdsAndAreaIds(
reqVO.getWarehouseIds(), reqVO.getAreaIds(), nonZeroOnly, reqVO.getCategoryType());
return buildPreviewItems(stockList);
}
@ -300,7 +325,9 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
if (reqVO == null || CollUtil.isEmpty(reqVO.getProductIds())) {
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, reqVO.getCategoryType());
return buildPreviewItems(stockList);
}
private List<ErpStockDO> filterNonZeroStocks(List<ErpStockDO> stockList) {
@ -320,7 +347,8 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
if (CollUtil.isEmpty(stockList)) {
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, WarehouseAreaDO> areaMap = warehouseAreaService.getWarehouseAreaMap(convertSet(stockList, ErpStockDO::getAreaId));
List<ErpStockCheckRespVO.Item> result = new ArrayList<>();
@ -331,7 +359,7 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
item.setAreaName(stock.getAreaName());
item.setProductId(stock.getProductId());
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);
MapUtils.findAndThen(warehouseMap, stock.getWarehouseId(), warehouse -> item.setWarehouseName(warehouse.getName()));
if (item.getAreaName() == null) {
@ -339,13 +367,10 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
}
ErpProductDO productDO = productMap.get(stock.getProductId());
item.setProductPrice(resolveProductPrice(productDO));
item.setProductUnitName(stock.getUnitName());
if (productDO != null) {
item.setProductName(productDO.getName());
item.setProductBarCode(productDO.getBarCode());
ErpProductRespVO productVO = productService.getProduct(productDO.getId());
if (productVO != null) {
item.setProductUnitName(productVO.getUnitName());
}
}
result.add(item);
}
@ -426,8 +451,8 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
ErpProductDO productDO = productMap.get(item.getProductId());
WarehouseAreaDO area = item.getAreaId() != null ? areaMap.get(item.getAreaId()) : null;
BigDecimal stockCount = item.getStockCount() != null ? item.getStockCount() : BigDecimal.ZERO;
BigDecimal actualCount = item.getActualCount() != null ? item.getActualCount() : BigDecimal.ZERO;
BigDecimal count = actualCount.subtract(stockCount);
BigDecimal actualCount = item.getActualCount();
BigDecimal count = actualCount != null ? actualCount.subtract(stockCount) : null;
BigDecimal productPrice = item.getProductPrice() != null ? item.getProductPrice() : resolveProductPrice(productDO);
return ErpStockCheckItemDO.builder()
.id(item.getId())
@ -440,7 +465,7 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
.stockCount(stockCount)
.actualCount(actualCount)
.count(count)
.totalPrice(MoneyUtils.priceMultiply(productPrice, count))
.totalPrice(count != null ? MoneyUtils.priceMultiply(productPrice, count) : null)
.remark(item.getRemark())
.build();
});
@ -476,6 +501,10 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
.build());
}
private boolean needAudit() {
return !"0".equals(configApi.getConfigValueByCategoryAndKey("biz", "inventoryAudit"));
}
private ErpStockCheckDO validateStockCheckExists(Long id) {
ErpStockCheckDO stockCheck = stockCheckMapper.selectById(id);
if (stockCheck == null) {
@ -484,4 +513,11 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService {
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);
}
}
}

@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSubmit
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInApproveRecordDO;
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.ErpStockInItemPalletDO;
import javax.validation.Valid;
import java.util.Collection;
@ -37,6 +38,10 @@ public interface ErpStockInService {
List<ErpStockInItemDO> getStockInItemListByInIds(Collection<Long> inIds);
List<ErpStockInItemPalletDO> getStockInItemPalletListByInId(Long inId);
List<ErpStockInItemPalletDO> getStockInItemPalletListByInIds(Collection<Long> inIds);
List<ErpStockInApproveRecordDO> getStockInApproveRecordList(Long stockInId);
void updateMoldStatus(Long id, Integer status);

@ -10,19 +10,24 @@ import cn.iocoder.yudao.module.common.controller.admin.mold.vo.MoldBrandSaveReqV
import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldBrandDO;
import cn.iocoder.yudao.module.common.dal.mysql.mold.MoldBrandMapper;
import cn.iocoder.yudao.module.common.enums.MoldBrandStatusEnum;
import cn.iocoder.yudao.module.erp.controller.admin.pallet.enums.ErpPalletStatusEnum;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInAuditReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSubmitReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.pallet.ErpPalletDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInApproveRecordDO;
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.ErpStockInItemPalletDO;
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.mysql.pallet.ErpPalletMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInApproveRecordMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInItemMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInItemPalletMapper;
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.redis.no.ErpNoRedisDAO;
@ -49,9 +54,11 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
@ -71,6 +78,7 @@ import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_IN_SUBM
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_IN_SUBMIT_FAIL_USER;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_IN_UPDATE_FAIL_APPROVE;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_IN_UPDATE_FAIL_PROCESS;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PALLET_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;
@ -85,10 +93,14 @@ public class ErpStockInServiceImpl implements ErpStockInService {
@Resource
private ErpStockInItemMapper stockInItemMapper;
@Resource
private ErpStockInItemPalletMapper stockInItemPalletMapper;
@Resource
private ErpStockInApproveRecordMapper stockInApproveRecordMapper;
@Resource
private ErpStockMapper erpStockMapper;
@Resource
private ErpPalletMapper palletMapper;
@Resource
private ErpNoRedisDAO noRedisDAO;
@Resource
private ErpProductService productService;
@ -135,6 +147,7 @@ public class ErpStockInServiceImpl implements ErpStockInService {
stockInMapper.insert(stockIn);
stockInItems.forEach(item -> item.setInId(stockIn.getId()));
stockInItemMapper.insertBatch(stockInItems);
saveStockInItemPallets(stockIn.getId(), stockInItems, createReqVO.getItems());
if (createReqVO.getInType().equals("模具入库")){
//修改模具组状态
@ -174,6 +187,7 @@ public class ErpStockInServiceImpl implements ErpStockInService {
.setTotalPrice(getSumValue(stockInItems, ErpStockInItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)));
stockInMapper.updateById(updateObj);
updateStockInItemList(updateReqVO.getId(), stockInItems);
saveStockInItemPallets(updateReqVO.getId(), stockInItems, updateReqVO.getItems());
}
@Override
@ -215,27 +229,12 @@ public class ErpStockInServiceImpl implements ErpStockInService {
throw exception(STOCK_IN_SUBMIT_FAIL_STATUS);
}
Integer fromStatus = stockIn.getStatus();
if (!Boolean.TRUE.equals(stockIn.getNeedAudit())) {
int updateCount = stockInMapper.updateByIdAndStatus(stockIn.getId(), fromStatus,
new ErpStockInDO().setStatus(ErpAuditStatus.APPROVE.getStatus()));
if (updateCount == 0) {
throw exception(STOCK_IN_SUBMIT_FAIL_STATUS);
}
List<ErpStockInItemDO> stockInItems = stockInItemMapper.selectListByInId(stockIn.getId());
applyStockInEffect(stockIn, stockInItems, null);
createApproveRecord(stockIn.getId(), ErpStockInApproveActionEnum.AUTO_APPROVE, fromStatus,
ErpAuditStatus.APPROVE.getStatus(), null,
submitReqVO.getRemark() != null ? submitReqVO.getRemark() : "无需审核,提交后自动入库");
return;
}
Long auditUserId = submitReqVO.getAuditUserId() != null ? submitReqVO.getAuditUserId() : stockIn.getAuditUserId();
if (auditUserId == null) {
throw exception(STOCK_IN_SUBMIT_FAIL_AUDIT_USER_EMPTY);
if (auditUserId != null) {
adminUserApi.validateUser(auditUserId);
}
adminUserApi.validateUser(auditUserId);
ErpStockInDO updateObj = new ErpStockInDO()
.setAuditUserId(auditUserId)
.setNeedAudit(true)
.setStatus(ErpAuditStatus.PROCESS.getStatus());
int updateCount = stockInMapper.updateByIdAndStatus(stockIn.getId(), fromStatus, updateObj);
if (updateCount == 0) {
@ -249,8 +248,23 @@ public class ErpStockInServiceImpl implements ErpStockInService {
@Transactional(rollbackFor = Exception.class)
public void auditStockIn(ErpStockInAuditReqVO auditReqVO) {
ErpStockInDO stockIn = validateStockInExists(auditReqVO.getId());
if (!ErpAuditStatus.PROCESS.getStatus().equals(stockIn.getStatus())) {
throw exception(STOCK_IN_AUDIT_FAIL_STATUS);
// if (!ErpAuditStatus.PROCESS.getStatus().equals(stockIn.getStatus())) {
// throw exception(STOCK_IN_AUDIT_FAIL_STATUS);
// }
Integer fromStatus = stockIn.getStatus();
if (!needAudit()) {
int updateCount = stockInMapper.updateByIdAndStatus(stockIn.getId(), fromStatus,
new ErpStockInDO().setNeedAudit(false).setStatus(ErpAuditStatus.APPROVE.getStatus()));
if (updateCount == 0) {
throw exception(STOCK_IN_AUDIT_FAIL_STATUS);
}
List<ErpStockInItemDO> stockInItems = stockInItemMapper.selectListByInId(stockIn.getId());
applyStockInEffect(stockIn, stockInItems, null);
createApproveRecord(stockIn.getId(), ErpStockInApproveActionEnum.AUTO_APPROVE, fromStatus,
ErpAuditStatus.APPROVE.getStatus(), NumberUtils.parseLong(stockIn.getCreator()),
auditReqVO.getRemark() != null ? auditReqVO.getRemark() : "无需审核,审核时自动入库");
return;
}
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
boolean adminCanAudit = permissionApi.hasAnyRoles(loginUserId, RoleCodeEnum.SUPER_ADMIN.getCode());
@ -262,9 +276,8 @@ public class ErpStockInServiceImpl implements ErpStockInService {
throw exception(STOCK_IN_AUDIT_FAIL_RESULT);
}
Integer fromStatus = stockIn.getStatus();
int updateCount = stockInMapper.updateByIdAndStatus(stockIn.getId(), fromStatus,
new ErpStockInDO().setStatus(auditReqVO.getStatus()));
new ErpStockInDO().setNeedAudit(true).setStatus(auditReqVO.getStatus()));
if (updateCount == 0) {
throw exception(STOCK_IN_AUDIT_FAIL_STATUS);
}
@ -297,6 +310,7 @@ public class ErpStockInServiceImpl implements ErpStockInService {
stockIns.forEach(stockIn -> {
stockInMapper.deleteById(stockIn.getId());
stockInItemMapper.deleteByInId(stockIn.getId());
stockInItemPalletMapper.deleteByInId(stockIn.getId());
stockInApproveRecordMapper.deleteByStockInId(stockIn.getId());
});
}
@ -340,6 +354,19 @@ public class ErpStockInServiceImpl implements ErpStockInService {
return stockInItemMapper.selectListByInIds(inIds);
}
@Override
public List<ErpStockInItemPalletDO> getStockInItemPalletListByInId(Long inId) {
return stockInItemPalletMapper.selectListByInId(inId);
}
@Override
public List<ErpStockInItemPalletDO> getStockInItemPalletListByInIds(Collection<Long> inIds) {
if (CollUtil.isEmpty(inIds)) {
return Collections.emptyList();
}
return stockInItemPalletMapper.selectListByInIds(inIds);
}
@Override
public List<ErpStockInApproveRecordDO> getStockInApproveRecordList(Long stockInId) {
return stockInApproveRecordMapper.selectListByStockInId(stockInId);
@ -386,6 +413,7 @@ public class ErpStockInServiceImpl implements ErpStockInService {
recordBizType, stockInItem.getInId(), stockInItem.getId(), stockIn.getNo(), stockIn.getInTime()));
}
});
operateStockInPalletEffect(stockIn.getId(), stockInItems, approve);
}
private Integer resolveRecordBizType(String inType, boolean approve, Integer bizType) {
@ -445,6 +473,8 @@ public class ErpStockInServiceImpl implements ErpStockInService {
.packagingSchemeId(item.getPackagingSchemeId())
.inputUnitType(item.getInputUnitType())
.inputCount(item.getInputCount())
.relateTask(item.getRelateTask())
.taskId(item.getTaskId())
.totalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount()))
.remark(item.getRemark())
.deviceId(item.getDeviceId())
@ -452,6 +482,7 @@ public class ErpStockInServiceImpl implements ErpStockInService {
});
}
validateWarehouseAreas(list);
validatePallets(list);
List<ErpProductDO> productList = productService.validProductList(convertSet(list, ErpStockInSaveReqVO.Item::getProductId));
@ -468,6 +499,20 @@ public class ErpStockInServiceImpl implements ErpStockInService {
.setTotalPrice(MoneyUtils.priceMultiply(target.getProductPrice(), target.getCount()))));
}
private void validatePallets(List<ErpStockInSaveReqVO.Item> list) {
List<Long> palletIds = convertListByFlatMap(list, item -> item.getPallets() == null ? java.util.stream.Stream.empty()
: item.getPallets().stream().map(ErpStockInSaveReqVO.Item.PalletItem::getPalletId));
if (CollUtil.isEmpty(palletIds)) {
return;
}
Map<Long, ErpPalletDO> palletMap = convertMap(palletMapper.selectBatchIds(palletIds), ErpPalletDO::getId);
palletIds.forEach(palletId -> {
if (!palletMap.containsKey(palletId)) {
throw exception(PALLET_NOT_EXISTS);
}
});
}
private void validateWarehouseAreas(List<ErpStockInSaveReqVO.Item> list) {
Map<Long, ErpWarehouseDO> warehouseMap = convertMap(
warehouseService.validWarehouseList(convertSet(list, ErpStockInSaveReqVO.Item::getWarehouseId)),
@ -513,4 +558,72 @@ public class ErpStockInServiceImpl implements ErpStockInService {
stockInItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpStockInItemDO::getId));
}
}
private void saveStockInItemPallets(Long inId, List<ErpStockInItemDO> stockInItems,
List<ErpStockInSaveReqVO.Item> reqItems) {
stockInItemPalletMapper.deleteByInId(inId);
if (CollUtil.isEmpty(stockInItems) || CollUtil.isEmpty(reqItems)) {
return;
}
List<ErpStockInItemPalletDO> palletRelations = CollUtil.newArrayList();
for (int i = 0; i < Math.min(stockInItems.size(), reqItems.size()); i++) {
ErpStockInItemDO stockInItem = stockInItems.get(i);
ErpStockInSaveReqVO.Item reqItem = reqItems.get(i);
if (stockInItem.getId() == null || CollUtil.isEmpty(reqItem.getPallets())) {
continue;
}
reqItem.getPallets().forEach(pallet -> palletRelations.add(ErpStockInItemPalletDO.builder()
.inId(inId)
.inItemId(stockInItem.getId())
.palletId(pallet.getPalletId())
.packageCount(defaultPackageCount(pallet.getPackageCount(), stockInItem.getCount()))
.build()));
}
if (CollUtil.isNotEmpty(palletRelations)) {
stockInItemPalletMapper.insertBatch(palletRelations);
}
}
private void operateStockInPalletEffect(Long inId, List<ErpStockInItemDO> stockInItems, boolean approve) {
List<ErpStockInItemPalletDO> palletRelations = stockInItemPalletMapper.selectListByInId(inId);
if (CollUtil.isEmpty(palletRelations)) {
return;
}
Map<Long, ErpStockInItemDO> itemMap = convertMap(stockInItems, ErpStockInItemDO::getId);
Map<Long, ErpPalletDO> palletMap = convertMap(palletMapper.selectBatchIds(
convertSet(palletRelations, ErpStockInItemPalletDO::getPalletId)), ErpPalletDO::getId);
palletRelations.forEach(relation -> {
ErpStockInItemDO item = itemMap.get(relation.getInItemId());
ErpPalletDO pallet = palletMap.get(relation.getPalletId());
if (item == null || pallet == null) {
return;
}
BigDecimal packageCount = defaultZero(relation.getPackageCount());
if (approve) {
pallet.setStatus(ErpPalletStatusEnum.OCCUPIED.getStatus());
pallet.setProductId(item.getProductId());
pallet.setProductCount(defaultZero(pallet.getProductCount()).add(packageCount));
pallet.setWarehouseId(item.getWarehouseId());
pallet.setAreaId(item.getAreaId());
} else {
BigDecimal remainCount = defaultZero(pallet.getProductCount()).subtract(packageCount);
if (remainCount.compareTo(BigDecimal.ZERO) <= 0) {
pallet.setStatus(ErpPalletStatusEnum.IDLE.getStatus());
pallet.setProductId(null);
pallet.setProductCount(BigDecimal.ZERO);
} else {
pallet.setProductCount(remainCount);
}
}
palletMapper.updateById(pallet);
});
}
private BigDecimal defaultPackageCount(BigDecimal packageCount, BigDecimal itemCount) {
return packageCount != null ? packageCount : defaultZero(itemCount);
}
private BigDecimal defaultZero(BigDecimal value) {
return value != null ? value : BigDecimal.ZERO;
}
}

@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSave
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutApproveRecordDO;
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.ErpStockOutItemPalletDO;
import javax.validation.Valid;
import java.util.Collection;
@ -90,6 +91,10 @@ public interface ErpStockOutService {
*/
List<ErpStockOutItemDO> getStockOutItemListByOutIds(Collection<Long> outIds);
List<ErpStockOutItemPalletDO> getStockOutItemPalletListByOutId(Long outId);
List<ErpStockOutItemPalletDO> getStockOutItemPalletListByOutIds(Collection<Long> outIds);
List<ErpStockOutApproveRecordDO> getStockOutApproveRecordList(Long stockOutId);
List<ErpStockOutDO> selectByOutType(List<String> outTypes);

@ -10,20 +10,25 @@ import cn.iocoder.yudao.module.common.controller.admin.mold.vo.MoldBrandSaveReqV
import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldBrandDO;
import cn.iocoder.yudao.module.common.dal.mysql.mold.MoldBrandMapper;
import cn.iocoder.yudao.module.common.enums.MoldBrandStatusEnum;
import cn.iocoder.yudao.module.erp.controller.admin.pallet.enums.ErpPalletStatusEnum;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutAuditReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVOItem;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSubmitReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.pallet.ErpPalletDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutApproveRecordDO;
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.ErpStockOutItemPalletDO;
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.mysql.pallet.ErpPalletMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutApproveRecordMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutItemMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutItemPalletMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutMapper;
import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO;
import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus;
@ -58,6 +63,7 @@ import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
@ -79,8 +85,12 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
@Resource
private ErpStockOutItemMapper stockOutItemMapper;
@Resource
private ErpStockOutItemPalletMapper stockOutItemPalletMapper;
@Resource
private ErpStockOutApproveRecordMapper stockOutApproveRecordMapper;
@Resource
private ErpPalletMapper palletMapper;
@Resource
private ErpNoRedisDAO noRedisDAO;
@Resource
private ErpProductService productService;
@ -137,6 +147,7 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
stockOutMapper.insert(stockOut);
stockOutItems.forEach(item -> item.setOutId(stockOut.getId()));
stockOutItemMapper.insertBatch(stockOutItems);
saveStockOutItemPallets(stockOut.getId(), stockOutItems, createReqVO.getItems());
if (createReqVO.getOutType().equals("模具出库")) {
//修改模具组状态
@ -179,6 +190,7 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
fillUsageSnapshot(stockOutItems, updateReqVO.getItems());
stockOutMapper.updateById(updateObj);
updateStockOutItemList(updateReqVO.getId(), stockOutItems);
saveStockOutItemPallets(updateReqVO.getId(), stockOutItems, updateReqVO.getItems());
}
@Override
@ -220,27 +232,12 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
throw exception(STOCK_OUT_SUBMIT_FAIL_STATUS);
}
Integer fromStatus = stockOut.getStatus();
if (!Boolean.TRUE.equals(stockOut.getNeedAudit())) {
int updateCount = stockOutMapper.updateByIdAndStatus(stockOut.getId(), fromStatus,
new ErpStockOutDO().setStatus(ErpAuditStatus.APPROVE.getStatus()));
if (updateCount == 0) {
throw exception(STOCK_OUT_SUBMIT_FAIL_STATUS);
}
List<ErpStockOutItemDO> stockOutItems = stockOutItemMapper.selectListByOutId(stockOut.getId());
applyStockOutEffect(stockOut, stockOutItems, null);
createApproveRecord(stockOut.getId(), ErpStockOutApproveActionEnum.AUTO_APPROVE, fromStatus,
ErpAuditStatus.APPROVE.getStatus(), null,
submitReqVO.getRemark() != null ? submitReqVO.getRemark() : "无需审核,提交后自动出库");
return;
}
Long auditUserId = submitReqVO.getAuditUserId() != null ? submitReqVO.getAuditUserId() : stockOut.getAuditUserId();
if (auditUserId == null) {
throw exception(STOCK_OUT_SUBMIT_FAIL_AUDIT_USER_EMPTY);
if (auditUserId != null) {
adminUserApi.validateUser(auditUserId);
}
adminUserApi.validateUser(auditUserId);
ErpStockOutDO updateObj = new ErpStockOutDO()
.setAuditUserId(auditUserId)
.setNeedAudit(true)
.setStatus(ErpAuditStatus.PROCESS.getStatus());
int updateCount = stockOutMapper.updateByIdAndStatus(stockOut.getId(), fromStatus, updateObj);
if (updateCount == 0) {
@ -254,8 +251,23 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
@Transactional(rollbackFor = Exception.class)
public void auditStockOut(ErpStockOutAuditReqVO auditReqVO) {
ErpStockOutDO stockOut = validateStockOutExists(auditReqVO.getId());
if (!ErpAuditStatus.PROCESS.getStatus().equals(stockOut.getStatus())) {
throw exception(STOCK_OUT_AUDIT_FAIL_STATUS);
// if (!ErpAuditStatus.PROCESS.getStatus().equals(stockOut.getStatus())) {
// throw exception(STOCK_OUT_AUDIT_FAIL_STATUS);
// }
Integer fromStatus = stockOut.getStatus();
if (!needAudit()) {
int updateCount = stockOutMapper.updateByIdAndStatus(stockOut.getId(), fromStatus,
new ErpStockOutDO().setNeedAudit(false).setStatus(ErpAuditStatus.APPROVE.getStatus()));
if (updateCount == 0) {
throw exception(STOCK_OUT_AUDIT_FAIL_STATUS);
}
List<ErpStockOutItemDO> stockOutItems = stockOutItemMapper.selectListByOutId(stockOut.getId());
applyStockOutEffect(stockOut, stockOutItems, null);
createApproveRecord(stockOut.getId(), ErpStockOutApproveActionEnum.AUTO_APPROVE, fromStatus,
ErpAuditStatus.APPROVE.getStatus(), NumberUtils.parseLong(stockOut.getCreator()),
auditReqVO.getRemark() != null ? auditReqVO.getRemark() : "无需审核,审核时自动出库");
return;
}
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
@ -270,9 +282,8 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
throw exception(STOCK_OUT_AUDIT_FAIL_RESULT);
}
Integer fromStatus = stockOut.getStatus();
int updateCount = stockOutMapper.updateByIdAndStatus(stockOut.getId(), fromStatus,
new ErpStockOutDO().setStatus(auditReqVO.getStatus()));
new ErpStockOutDO().setNeedAudit(true).setStatus(auditReqVO.getStatus()));
if (updateCount == 0) {
throw exception(STOCK_OUT_AUDIT_FAIL_STATUS);
}
@ -305,6 +316,7 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
stockOuts.forEach(stockOut -> {
stockOutMapper.deleteById(stockOut.getId());
stockOutItemMapper.deleteByOutId(stockOut.getId());
stockOutItemPalletMapper.deleteByOutId(stockOut.getId());
stockOutApproveRecordMapper.deleteByStockOutId(stockOut.getId());
});
}
@ -340,6 +352,19 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
return stockOutItemMapper.selectListByOutIds(outIds);
}
@Override
public List<ErpStockOutItemPalletDO> getStockOutItemPalletListByOutId(Long outId) {
return stockOutItemPalletMapper.selectListByOutId(outId);
}
@Override
public List<ErpStockOutItemPalletDO> getStockOutItemPalletListByOutIds(Collection<Long> outIds) {
if (CollUtil.isEmpty(outIds)) {
return Collections.emptyList();
}
return stockOutItemPalletMapper.selectListByOutIds(outIds);
}
@Override
public List<ErpStockOutApproveRecordDO> getStockOutApproveRecordList(Long stockOutId) {
return stockOutApproveRecordMapper.selectListByStockOutId(stockOutId);
@ -401,6 +426,7 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
recordBizType, stockOutItem.getOutId(), stockOutItem.getId(), stockOut.getNo(), stockOut.getOutTime()));
}
});
operateStockOutPalletEffect(stockOut.getId(), stockOutItems, approve);
}
private boolean itemNeedUpdateMoldStatus(MoldBrandDO moldDO) {
@ -477,6 +503,7 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
.productUnitId(null)
.productPrice(item.getProductPrice())
.count(item.getCount())
.outMode(item.getOutMode())
.totalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount()))
.outUsageType(item.getOutUsageType())
.outUsageTypeName(ErpStockOutUsageTypeEnum.getNameByType(item.getOutUsageType()))
@ -487,6 +514,7 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
.build();
});
}
validatePallets(list);
List<ErpProductDO> productList = productService.validProductList(convertSet(list, ErpStockOutSaveReqVOItem::getProductId));
Map<Long, ErpProductDO> productMap = convertMap(productList, ErpProductDO::getId);
Map<Long, WarehouseAreaDO> areaMap = warehouseAreaService.getWarehouseAreaMap(
@ -505,6 +533,20 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
.setMaintenanceName(null)));
}
private void validatePallets(List<ErpStockOutSaveReqVOItem> list) {
List<Long> palletIds = convertListByFlatMap(list, item -> item.getPallets() == null ? java.util.stream.Stream.empty()
: item.getPallets().stream().map(ErpStockOutSaveReqVOItem.PalletItem::getPalletId));
if (CollUtil.isEmpty(palletIds)) {
return;
}
Map<Long, ErpPalletDO> palletMap = convertMap(palletMapper.selectBatchIds(palletIds), ErpPalletDO::getId);
palletIds.forEach(palletId -> {
if (!palletMap.containsKey(palletId)) {
throw exception(PALLET_NOT_EXISTS);
}
});
}
private void validateWarehouseAreas(List<ErpStockOutSaveReqVOItem> list) {
Map<Long, ErpWarehouseDO> warehouseMap = convertMap(
warehouseService.validWarehouseList(convertSet(list, ErpStockOutSaveReqVOItem::getWarehouseId)),
@ -553,4 +595,72 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
}
}
private void saveStockOutItemPallets(Long outId, List<ErpStockOutItemDO> stockOutItems,
List<ErpStockOutSaveReqVOItem> reqItems) {
stockOutItemPalletMapper.deleteByOutId(outId);
if (CollUtil.isEmpty(stockOutItems) || CollUtil.isEmpty(reqItems)) {
return;
}
List<ErpStockOutItemPalletDO> palletRelations = CollUtil.newArrayList();
for (int i = 0; i < Math.min(stockOutItems.size(), reqItems.size()); i++) {
ErpStockOutItemDO stockOutItem = stockOutItems.get(i);
ErpStockOutSaveReqVOItem reqItem = reqItems.get(i);
if (stockOutItem.getId() == null || CollUtil.isEmpty(reqItem.getPallets())) {
continue;
}
reqItem.getPallets().forEach(pallet -> palletRelations.add(ErpStockOutItemPalletDO.builder()
.outId(outId)
.outItemId(stockOutItem.getId())
.palletId(pallet.getPalletId())
.packageCount(defaultPackageCount(pallet.getPackageCount(), stockOutItem.getCount()))
.build()));
}
if (CollUtil.isNotEmpty(palletRelations)) {
stockOutItemPalletMapper.insertBatch(palletRelations);
}
}
private void operateStockOutPalletEffect(Long outId, List<ErpStockOutItemDO> stockOutItems, boolean approve) {
List<ErpStockOutItemPalletDO> palletRelations = stockOutItemPalletMapper.selectListByOutId(outId);
if (CollUtil.isEmpty(palletRelations)) {
return;
}
Map<Long, ErpStockOutItemDO> itemMap = convertMap(stockOutItems, ErpStockOutItemDO::getId);
Map<Long, ErpPalletDO> palletMap = convertMap(palletMapper.selectBatchIds(
convertSet(palletRelations, ErpStockOutItemPalletDO::getPalletId)), ErpPalletDO::getId);
palletRelations.forEach(relation -> {
ErpStockOutItemDO item = itemMap.get(relation.getOutItemId());
ErpPalletDO pallet = palletMap.get(relation.getPalletId());
if (item == null || pallet == null) {
return;
}
BigDecimal packageCount = defaultZero(relation.getPackageCount());
if (approve) {
BigDecimal remainCount = defaultZero(pallet.getProductCount()).subtract(packageCount);
if (remainCount.compareTo(BigDecimal.ZERO) <= 0) {
pallet.setStatus(ErpPalletStatusEnum.IDLE.getStatus());
pallet.setProductId(null);
pallet.setProductCount(BigDecimal.ZERO);
} else {
pallet.setProductCount(remainCount);
}
} else {
pallet.setStatus(ErpPalletStatusEnum.OCCUPIED.getStatus());
pallet.setProductId(item.getProductId());
pallet.setProductCount(defaultZero(pallet.getProductCount()).add(packageCount));
pallet.setWarehouseId(item.getWarehouseId());
pallet.setAreaId(item.getAreaId());
}
palletMapper.updateById(pallet);
});
}
private BigDecimal defaultPackageCount(BigDecimal packageCount, BigDecimal itemCount) {
return packageCount != null ? packageCount : defaultZero(itemCount);
}
private BigDecimal defaultZero(BigDecimal value) {
return value != null ? value : BigDecimal.ZERO;
}
}

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

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

@ -216,6 +216,16 @@ public class TaskController {
public CommonResult<List<TaskDetailRespVO>> getTaskDetailListByTaskId(@RequestParam("taskId") Long taskId) {
return success(taskService.buildDetailVOList(taskService.getTaskDetailListByTaskId(taskId)));
}
@GetMapping("/task-detail/default-packaging-schemes")
@Operation(summary = "获得生产任务单明细产品默认包装方案列表")
@Parameter(name = "taskId", description = "task ID", required = true)
@PreAuthorize("@ss.hasPermission('mes:task:query')")
public CommonResult<TaskPackagingSchemeRespVO> getTaskProductDefaultPackagingSchemes(
@RequestParam("taskId") Long taskId) {
return success(taskService.getTaskProductDefaultPackagingSchemes(taskId));
}
// ==================== 子表(生产任务单明细) ====================
@GetMapping("/task-detail/page")
@ -266,4 +276,4 @@ public class TaskController {
public CommonResult<List<ViewTaskProductSummary>> getTaskDetailSummary(@RequestParam("taskId") Long taskId) {
return success(taskService.getTaskProductSummaryList(taskId));
}
}
}

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.mes.controller.admin.task.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 生产任务单默认包装方案 Response VO")
@Data
public class TaskPackagingSchemeRespVO {
@Schema(description = "任务单 ID", example = "1")
private Long taskId;
@Schema(description = "任务单名称", example = "RW20240618001")
private String taskName;
@Schema(description = "产品默认包装方案列表")
private List<TaskProductPackagingSchemeRespVO> products;
}

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.mes.controller.admin.task.vo;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductPackagingSchemeRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 生产任务单产品默认包装方案 Response VO")
@Data
public class TaskProductPackagingSchemeRespVO {
@Schema(description = "产品 ID", example = "1")
private Long productId;
@Schema(description = "产品编码", example = "CP001")
private String productCode;
@Schema(description = "产品名称", example = "产品A")
private String productName;
@Schema(description = "任务明细 ID 列表")
private List<Long> taskDetailIds;
@Schema(description = "默认包装方案列表")
private List<ProductPackagingSchemeRespVO> packagingSchemes;
}

@ -65,6 +65,9 @@ public class TicketManagementPageReqVO extends PageParam {
@Schema(description = "设备集合", example = "6979")
private List<String> machineryNames;
@Schema(description = "设备 ID", example = "6979")
private Long deviceId;
@Schema(description = "产线")
private String deviceLineId;
}
}

@ -96,6 +96,7 @@ public interface TaskService {
*/
List<TaskDetailDO> getTaskDetailListByTaskId(Long taskId);
List<TaskDetailRespVO> buildDetailVOList(List<TaskDetailDO> list);
TaskPackagingSchemeRespVO getTaskProductDefaultPackagingSchemes(Long taskId);
/**
*
*

@ -6,12 +6,15 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
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.product.vo.product.ProductPackagingSchemeRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductRelationRespVO;
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.dal.dataobject.productdevicerel.ProductDeviceRelDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.productpackagingschemerel.ProductPackagingSchemeRelDO;
import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.productdevicerel.ProductDeviceRelMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.productpackagingschemerel.ProductPackagingSchemeRelMapper;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO;
@ -97,6 +100,8 @@ public class TaskServiceImpl implements TaskService {
@Resource
private ProductDeviceRelMapper productDeviceRelMapper;
@Resource
private ProductPackagingSchemeRelMapper productPackagingSchemeRelMapper;
@Resource
private DeviceLedgerService deviceLedgerService;
@ -258,6 +263,42 @@ public class TaskServiceImpl implements TaskService {
return taskDetailMapper.selectListByTaskId(taskId);
}
@Override
public TaskPackagingSchemeRespVO getTaskProductDefaultPackagingSchemes(Long taskId) {
TaskDO task = getTask(taskId);
TaskPackagingSchemeRespVO result = new TaskPackagingSchemeRespVO();
result.setTaskId(taskId);
result.setTaskName(task == null ? null : task.getCode());
List<TaskDetailDO> details = getTaskDetailListByTaskId(taskId);
if (CollUtil.isEmpty(details)) {
result.setProducts(Collections.emptyList());
return result;
}
Set<Long> productIds = convertSet(details, TaskDetailDO::getProductId);
Map<Long, ErpProductDO> productMap = productService.getProductMap(productIds);
Map<Long, List<Long>> taskDetailIdMap = details.stream()
.filter(item -> item.getProductId() != null)
.collect(Collectors.groupingBy(TaskDetailDO::getProductId,
Collectors.mapping(TaskDetailDO::getId, Collectors.toList())));
Map<Long, List<ProductPackagingSchemeRespVO>> packagingSchemeMap = productPackagingSchemeRelMapper
.selectListByProductIds(productIds).stream()
.filter(item -> Integer.valueOf(1).equals(item.getDefaultStatus()))
.collect(Collectors.groupingBy(ProductPackagingSchemeRelDO::getProductId,
Collectors.mapping(item -> BeanUtils.toBean(item, ProductPackagingSchemeRespVO.class),
Collectors.toList())));
result.setProducts(productIds.stream().map(productId -> {
ErpProductDO product = productMap.get(productId);
TaskProductPackagingSchemeRespVO respVO = new TaskProductPackagingSchemeRespVO();
respVO.setProductId(productId);
respVO.setProductCode(product == null ? null : product.getBarCode());
respVO.setProductName(product == null ? null : product.getName());
respVO.setTaskDetailIds(taskDetailIdMap.getOrDefault(productId, Collections.emptyList()));
respVO.setPackagingSchemes(packagingSchemeMap.getOrDefault(productId, Collections.emptyList()));
return respVO;
}).collect(Collectors.toList()));
return result;
}
private void createTaskDetailList(Long taskId, List<TaskDetailDO> list) {
list.forEach(o -> o.setTaskId(taskId));
taskDetailMapper.insertBatch(list);

@ -93,7 +93,17 @@ public class TicketManagementServiceImpl implements TicketManagementService {
@Override
public PageResult<TicketManagementDO> getTicketManagementPage(TicketManagementPageReqVO pageReqVO) {
if(StringUtils.isNotBlank(pageReqVO.getDeviceLineId())||StringUtils.isNotBlank(pageReqVO.getPlanNo())) {
if (pageReqVO.getDeviceId() != null) {
pageReqVO.setPlanNo(null);
DeviceLedgerDO deviceLedgerDO = deviceLedgerMapper.selectById(pageReqVO.getDeviceId());
if (deviceLedgerDO != null
&& StringUtils.isNotBlank(deviceLedgerDO.getDeviceName())
&& matchesDeviceLine(deviceLedgerDO, pageReqVO.getDeviceLineId())) {
pageReqVO.setMachineryNames(Collections.singletonList(deviceLedgerDO.getDeviceName()));
} else {
pageReqVO.setMachineryNames(emptyResultMachineryNames());
}
} else if(StringUtils.isNotBlank(pageReqVO.getDeviceLineId())||StringUtils.isNotBlank(pageReqVO.getPlanNo())) {
LambdaQueryWrapperX<DeviceLedgerDO> deviceLedgerDOLambdaQueryWrapperX = new LambdaQueryWrapperX<>();
if(StringUtils.isNotBlank(pageReqVO.getDeviceLineId()))
deviceLedgerDOLambdaQueryWrapperX.eqIfPresent(DeviceLedgerDO::getDeviceLine, pageReqVO.getDeviceLineId());
@ -109,15 +119,23 @@ public class TicketManagementServiceImpl implements TicketManagementService {
if(CollUtil.isNotEmpty(machineryNames)){
pageReqVO.setMachineryNames(machineryNames);
}else {
List<String> objects = new ArrayList<>();
objects.add("adsaf");
pageReqVO.setMachineryNames(objects);
pageReqVO.setMachineryNames(emptyResultMachineryNames());
}
}
return ticketManagementMapper.selectPage(pageReqVO);
}
private boolean matchesDeviceLine(DeviceLedgerDO deviceLedgerDO, String deviceLineId) {
return StringUtils.isBlank(deviceLineId)
|| (deviceLedgerDO.getDeviceLine() != null
&& Objects.equals(String.valueOf(deviceLedgerDO.getDeviceLine()), deviceLineId));
}
private List<String> emptyResultMachineryNames() {
return Collections.singletonList("adsaf");
}
@Override
@Transactional(rollbackFor = Exception.class)
public void batchUpdateJobStatus(TicketManagementBatchUpdateReqVO reqVO) {

Loading…
Cancel
Save