diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesController.java index 8131fd0..d044e2b 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesController.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesController.java @@ -11,6 +11,7 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesPageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesRespVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesSaveReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesShippingReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.client.MesMdClientDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDO; import cn.iocoder.yudao.module.mes.service.md.client.MesMdClientService; @@ -112,12 +113,28 @@ public class MesWmProductSalesController { return success(true); } - @PutMapping("/pick") + @GetMapping("/check-quantity") + @Operation(summary = "校验销售出库单数量") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:query')") + public CommonResult checkProductSalesQuantity(@RequestParam("id") Long id) { + return success(productSalesService.checkProductSalesQuantity(id)); + } + + @PutMapping("/stock") @Operation(summary = "执行拣货") @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:pick')") - public CommonResult pickProductSales(@RequestParam("id") Long id) { - productSalesService.pickProductSales(id); + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:stock')") + public CommonResult stockProductSales(@RequestParam("id") Long id) { + productSalesService.stockProductSales(id); + return success(true); + } + + @PutMapping("/shipping") + @Operation(summary = "填写运单") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:shipping')") + public CommonResult shippingProductSales(@Valid @RequestBody MesWmProductSalesShippingReqVO reqVO) { + productSalesService.shippingProductSales(reqVO); return success(true); } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesShippingReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesShippingReqVO.java new file mode 100644 index 0000000..c7bcbb4 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesShippingReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - MES 销售出库单填写运单 Request VO") +@Data +public class MesWmProductSalesShippingReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "编号不能为空") + private Long id; + + @Schema(description = "承运商", example = "顺丰快递") + private String carrier; + + @Schema(description = "运输单号", example = "SF1234567890") + private String shippingNumber; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java index 8619c11..b3188f9 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java @@ -433,13 +433,14 @@ public interface ErrorCodeConstants { ErrorCode WM_PRODUCT_SALES_LINES_EMPTY = new ErrorCode(1_040_714_003, "销售出库单行不能为空"); ErrorCode WM_PRODUCT_SALES_CANNOT_SUBMIT = new ErrorCode(1_040_714_004, "当前状态不允许提交"); ErrorCode WM_PRODUCT_SALES_CANNOT_PICK = new ErrorCode(1_040_714_005, "当前状态不允许拣货"); - ErrorCode WM_PRODUCT_SALES_CANNOT_EXECUTE = new ErrorCode(1_040_714_006, "当前状态不允许执行出库"); - ErrorCode WM_PRODUCT_SALES_CANNOT_CANCEL = new ErrorCode(1_040_714_007, "当前状态不允许取消"); - ErrorCode WM_PRODUCT_SALES_DETAILS_EMPTY = new ErrorCode(1_040_714_008, "拣货明细不能为空"); - ErrorCode WM_PRODUCT_SALES_DETAIL_QUANTITY_MISMATCH = new ErrorCode(1_040_714_009, "拣货数量与出库数量不匹配"); - ErrorCode WM_PRODUCT_SALES_LINE_NOT_EXISTS = new ErrorCode(1_040_714_010, "销售出库单行不存在"); - ErrorCode WM_PRODUCT_SALES_DETAIL_NOT_EXISTS = new ErrorCode(1_040_714_011, "销售出库明细不存在"); - ErrorCode WM_PRODUCT_SALES_STOCK_INSUFFICIENT = new ErrorCode(1_040_714_012, "库存不足,无法拣货"); + ErrorCode WM_PRODUCT_SALES_CANNOT_SHIPPING = new ErrorCode(1_040_714_006, "当前状态不允许填写运单"); + ErrorCode WM_PRODUCT_SALES_CANNOT_EXECUTE = new ErrorCode(1_040_714_007, "当前状态不允许执行出库"); + ErrorCode WM_PRODUCT_SALES_CANNOT_CANCEL = new ErrorCode(1_040_714_008, "当前状态不允许取消"); + ErrorCode WM_PRODUCT_SALES_DETAILS_EMPTY = new ErrorCode(1_040_714_009, "拣货明细不能为空"); + ErrorCode WM_PRODUCT_SALES_DETAIL_QUANTITY_MISMATCH = new ErrorCode(1_040_714_010, "拣货数量与出库数量不匹配"); + ErrorCode WM_PRODUCT_SALES_LINE_NOT_EXISTS = new ErrorCode(1_040_714_011, "销售出库单行不存在"); + ErrorCode WM_PRODUCT_SALES_DETAIL_NOT_EXISTS = new ErrorCode(1_040_714_012, "销售出库明细不存在"); + ErrorCode WM_PRODUCT_SALES_STOCK_INSUFFICIENT = new ErrorCode(1_040_714_013, "库存不足,无法拣货"); // ========== MES 仓库管理-发货通知单(1-040-720-000) ========== ErrorCode WM_SALES_NOTICE_NOT_EXISTS = new ErrorCode(1_040_720_000, "发货通知单不存在"); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductSalesStatusEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductSalesStatusEnum.java index 313f99f..d955afc 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductSalesStatusEnum.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductSalesStatusEnum.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.mes.enums.wm; import cn.iocoder.yudao.framework.common.core.ArrayValuable; import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesSaveReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesShippingReqVO; import cn.iocoder.yudao.module.mes.enums.MesOrderStatusConstants; import cn.iocoder.yudao.module.mes.service.wm.productsales.MesWmProductSalesService; import lombok.AllArgsConstructor; @@ -20,8 +21,6 @@ import java.util.Arrays; @AllArgsConstructor public enum MesWmProductSalesStatusEnum implements ArrayValuable { - // (草稿)提交 =》(待拣货)执行拣货 =》(待填写运单)填写运单;=》(待执行出库)执行出库=》(已完成) - /** * 草稿 * @@ -34,12 +33,16 @@ public enum MesWmProductSalesStatusEnum implements ArrayValuable { * 对应方法:{@link MesWmProductSalesService#submitProductSales(Long)} */ APPROVING(MesOrderStatusConstants.APPROVING, "待拣货"), - // TODO @AI:在 APPROVING、APPROVED 之间加一个 10,SHIPPING,待填写运单;执行填写运单方法:{@link MesWmProductSalesService#shippingProductSales(Long)} - // TODO @AI:pick 这个方法要改成 stock; + /** + * 待填写运单 + * + * 对应方法:{@link MesWmProductSalesService#shippingProductSales(MesWmProductSalesShippingReqVO)} + */ + SHIPPING(10, "待填写运单"), // 10 是一个特殊的状态值,不在 MesOrderStatusConstants 中,单独定义 /** * 待执行出库 * - * 对应方法:{@link MesWmProductSalesService#pickProductSales(Long)} + * 对应方法:{@link MesWmProductSalesService#stockProductSales(Long)} */ APPROVED(MesOrderStatusConstants.APPROVED, "待执行出库"), /** diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java index d9be386..96f0792 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.mes.service.wm.productsales; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesPageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesSaveReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesShippingReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDO; import jakarta.validation.Valid; @@ -59,11 +60,26 @@ public interface MesWmProductSalesService { void submitProductSales(Long id); /** - * 执行拣货(待拣货 → 待出库) + * 校验销售出库单数量是否匹配 * * @param id 编号 + * @return 是否匹配 */ - void pickProductSales(Long id); + boolean checkProductSalesQuantity(Long id); + + /** + * 执行拣货(待拣货 → 待填写运单) + * + * @param id 编号 + */ + void stockProductSales(Long id); + + /** + * 填写运单(待填写运单 → 待执行出库) + * + * @param reqVO 运单信息 + */ + void shippingProductSales(@Valid MesWmProductSalesShippingReqVO reqVO); /** * 执行出库(待出库 → 已完成),扣减库存 diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java index dc62515..cc06ed3 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesPageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesSaveReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.MesWmProductSalesShippingReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDetailDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO; @@ -117,33 +118,53 @@ public class MesWmProductSalesServiceImpl implements MesWmProductSalesService { .setId(id).setStatus(MesWmProductSalesStatusEnum.APPROVING.getStatus())); } - // TODO @AI:前后端方法名,都改成 stock;保持整体都是对齐的; @Override - @Transactional(rollbackFor = Exception.class) - public void pickProductSales(Long id) { - // 校验存在 - MesWmProductSalesDO sales = validateProductSalesExists(id); - if (ObjUtil.notEqual(MesWmProductSalesStatusEnum.APPROVING.getStatus(), sales.getStatus())) { - throw exception(WM_PRODUCT_SALES_CANNOT_PICK); - } + public boolean checkProductSalesQuantity(Long id) { // 校验每行明细数量之和是否等于行出库数量 - // TODO @AI:这里挪成独立的 checkQuantiy 接口,不在这个方法里,保持对齐;然后前端调用;类似 /Users/yunai/Java/yudao-all-in-one/yudao-ui-admin-vue3/src/views/mes/wm/returnvendor/ReturnVendorForm.vue 这种; List lines = productSalesLineService.getProductSalesLineListBySalesId(id); for (MesWmProductSalesLineDO line : lines) { List details = productSalesDetailService.getProductSalesDetailListByLineId(line.getId()); if (CollUtil.isEmpty(details)) { - throw exception(WM_PRODUCT_SALES_DETAILS_EMPTY); + return false; } BigDecimal totalDetailQty = CollectionUtils.getSumValue(details, MesWmProductSalesDetailDO::getQuantity, BigDecimal::add, BigDecimal.ZERO); if (line.getQuantity() != null && totalDetailQty.compareTo(line.getQuantity()) != 0) { - throw exception(WM_PRODUCT_SALES_DETAIL_QUANTITY_MISMATCH); + return false; } } + return true; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void stockProductSales(Long id) { + // 校验存在 + MesWmProductSalesDO sales = validateProductSalesExists(id); + if (ObjUtil.notEqual(MesWmProductSalesStatusEnum.APPROVING.getStatus(), sales.getStatus())) { + throw exception(WM_PRODUCT_SALES_CANNOT_PICK); + } + + // 执行拣货(待拣货 → 待填写运单) + productSalesMapper.updateById(new MesWmProductSalesDO() + .setId(id).setStatus(MesWmProductSalesStatusEnum.SHIPPING.getStatus())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void shippingProductSales(MesWmProductSalesShippingReqVO reqVO) { + // 校验存在 + MesWmProductSalesDO sales = validateProductSalesExists(reqVO.getId()); + if (ObjUtil.notEqual(MesWmProductSalesStatusEnum.SHIPPING.getStatus(), sales.getStatus())) { + throw exception(WM_PRODUCT_SALES_CANNOT_SHIPPING); + } - // 执行拣货(待拣货 → 待出库) + // 填写运单(待填写运单 → 待执行出库) productSalesMapper.updateById(new MesWmProductSalesDO() - .setId(id).setStatus(MesWmProductSalesStatusEnum.APPROVED.getStatus())); + .setId(reqVO.getId()) + .setCarrier(reqVO.getCarrier()) + .setShippingNumber(reqVO.getShippingNumber()) + .setStatus(MesWmProductSalesStatusEnum.APPROVED.getStatus())); } @Override