From ab7c12d34b2caaeb2487e2e36e149aaca119c7a7 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 2 Mar 2026 10:42:20 +0800 Subject: [PATCH] ✨ feat(mes): 新增销售出库单行及明细相关功能和数据结构 --- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesController.java | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesDetailController.java | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesLineController.java | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesPageReqVO.java | 36 ++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailPageReqVO.java | 21 +++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailRespVO.java | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailSaveReqVO.java | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLinePageReqVO.java | 18 ++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLineRespVO.java | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLineSaveReqVO.java | 34 ++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDetailDO.java | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesDetailMapper.java | 33 +++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java | 32 ++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesMapper.java | 32 ++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductSalesStatusEnum.java | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailService.java | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailServiceImpl.java | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineService.java | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineServiceImpl.java | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 25 files changed, 1882 insertions(+), 0 deletions(-) create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesController.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesDetailController.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesLineController.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesPageReqVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailPageReqVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailRespVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailSaveReqVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLinePageReqVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLineRespVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLineSaveReqVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDetailDO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesDetailMapper.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesMapper.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductSalesStatusEnum.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailService.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailServiceImpl.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineService.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineServiceImpl.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java 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 new file mode 100644 index 0000000..8131fd0 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesController.java @@ -0,0 +1,158 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales; + +import cn.hutool.core.collection.CollUtil; +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.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +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.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; +import cn.iocoder.yudao.module.mes.service.wm.productsales.MesWmProductSalesService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.Collections; +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.convertSet; + +@Tag(name = "管理后台 - MES 销售出库单") +@RestController +@RequestMapping("/mes/wm/product-sales") +@Validated +public class MesWmProductSalesController { + + @Resource + private MesWmProductSalesService productSalesService; + + @Resource + private MesMdClientService clientService; + + @PostMapping("/create") + @Operation(summary = "创建销售出库单") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:create')") + public CommonResult createProductSales(@Valid @RequestBody MesWmProductSalesSaveReqVO createReqVO) { + return success(productSalesService.createProductSales(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "修改销售出库单") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:update')") + public CommonResult updateProductSales(@Valid @RequestBody MesWmProductSalesSaveReqVO updateReqVO) { + productSalesService.updateProductSales(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除销售出库单") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:delete')") + public CommonResult deleteProductSales(@RequestParam("id") Long id) { + productSalesService.deleteProductSales(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得销售出库单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:query')") + public CommonResult getProductSales(@RequestParam("id") Long id) { + MesWmProductSalesDO sales = productSalesService.getProductSales(id); + if (sales == null) { + return success(null); + } + return success(buildRespVOList(Collections.singletonList(sales)).get(0)); + } + + @GetMapping("/page") + @Operation(summary = "获得销售出库单分页") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:query')") + public CommonResult> getProductSalesPage( + @Valid MesWmProductSalesPageReqVO pageReqVO) { + PageResult pageResult = productSalesService.getProductSalesPage(pageReqVO); + return success(new PageResult<>(buildRespVOList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出销售出库单 Excel") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportProductSalesExcel(@Valid MesWmProductSalesPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + PageResult pageResult = productSalesService.getProductSalesPage(pageReqVO); + ExcelUtils.write(response, "销售出库单.xls", "数据", MesWmProductSalesRespVO.class, + buildRespVOList(pageResult.getList())); + } + + @PutMapping("/submit") + @Operation(summary = "提交销售出库单") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:submit')") + public CommonResult submitProductSales(@RequestParam("id") Long id) { + productSalesService.submitProductSales(id); + return success(true); + } + + @PutMapping("/pick") + @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); + return success(true); + } + + @PutMapping("/execute") + @Operation(summary = "执行出库") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:execute')") + public CommonResult executeProductSales(@RequestParam("id") Long id) { + productSalesService.executeProductSales(id); + return success(true); + } + + @PutMapping("/cancel") + @Operation(summary = "取消销售出库单") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:cancel')") + public CommonResult cancelProductSales(@RequestParam("id") Long id) { + productSalesService.cancelProductSales(id); + return success(true); + } + + // ==================== 拼接 VO ==================== + + private List buildRespVOList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + // 1. 获得关联数据 + Map clientMap = clientService.getClientMap( + convertSet(list, MesWmProductSalesDO::getClientId)); + // 2. 构建结果 + return BeanUtils.toBean(list, MesWmProductSalesRespVO.class, vo -> { + MapUtils.findAndThen(clientMap, vo.getClientId(), + client -> vo.setClientName(client.getName())); + }); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesDetailController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesDetailController.java new file mode 100644 index 0000000..4c05d8a --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesDetailController.java @@ -0,0 +1,140 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.detail.MesWmProductSalesDetailRespVO; +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.detail.MesWmProductSalesDetailSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDetailDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; +import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; +import cn.iocoder.yudao.module.mes.service.wm.productsales.MesWmProductSalesDetailService; +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService; +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService; +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - MES 销售出库明细") +@RestController +@RequestMapping("/mes/wm/product-sales-detail") +@Validated +public class MesWmProductSalesDetailController { + + @Resource + private MesWmProductSalesDetailService productSalesDetailService; + + @Resource + private MesMdItemService itemService; + + @Resource + private MesMdUnitMeasureService unitMeasureService; + + @Resource + private MesWmWarehouseService warehouseService; + + @Resource + private MesWmWarehouseLocationService locationService; + + @Resource + private MesWmWarehouseAreaService areaService; + + @PostMapping("/create") + @Operation(summary = "创建销售出库明细") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:create')") + public CommonResult createProductSalesDetail(@Valid @RequestBody MesWmProductSalesDetailSaveReqVO createReqVO) { + return success(productSalesDetailService.createProductSalesDetail(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "修改销售出库明细") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:update')") + public CommonResult updateProductSalesDetail(@Valid @RequestBody MesWmProductSalesDetailSaveReqVO updateReqVO) { + productSalesDetailService.updateProductSalesDetail(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除销售出库明细") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:delete')") + public CommonResult deleteProductSalesDetail(@RequestParam("id") Long id) { + productSalesDetailService.deleteProductSalesDetail(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得销售出库明细") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:query')") + public CommonResult getProductSalesDetail(@RequestParam("id") Long id) { + MesWmProductSalesDetailDO detail = productSalesDetailService.getProductSalesDetail(id); + if (detail == null) { + return success(null); + } + return success(buildRespVOList(Collections.singletonList(detail)).get(0)); + } + + @GetMapping("/list-by-line") + @Operation(summary = "获得销售出库明细列表(按行编号)") + @Parameter(name = "lineId", description = "行编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:query')") + public CommonResult> getProductSalesDetailListByLineId( + @RequestParam("lineId") Long lineId) { + List list = productSalesDetailService.getProductSalesDetailListByLineId(lineId); + return success(buildRespVOList(list)); + } + + // ==================== 拼接 VO ==================== + + private List buildRespVOList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + // 1. 获得关联数据 + Map itemMap = itemService.getItemMap( + convertSet(list, MesWmProductSalesDetailDO::getItemId)); + Map unitMeasureMap = unitMeasureService.getUnitMeasureMap( + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); + Map warehouseMap = warehouseService.getWarehouseMap( + convertSet(list, MesWmProductSalesDetailDO::getWarehouseId)); + Map locationMap = locationService.getWarehouseLocationMap( + convertSet(list, MesWmProductSalesDetailDO::getLocationId)); + Map areaMap = areaService.getWarehouseAreaMap( + convertSet(list, MesWmProductSalesDetailDO::getAreaId)); + // 2. 构建结果 + return BeanUtils.toBean(list, MesWmProductSalesDetailRespVO.class, vo -> { + MapUtils.findAndThen(itemMap, vo.getItemId(), item -> { + vo.setItemCode(item.getCode()).setItemName(item.getName()).setSpecification(item.getSpecification()); + MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), + unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); + }); + MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), + warehouse -> vo.setWarehouseName(warehouse.getName())); + MapUtils.findAndThen(locationMap, vo.getLocationId(), + location -> vo.setLocationName(location.getName())); + MapUtils.findAndThen(areaMap, vo.getAreaId(), + area -> vo.setAreaName(area.getName())); + }); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesLineController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesLineController.java new file mode 100644 index 0000000..d1fe62a --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/MesWmProductSalesLineController.java @@ -0,0 +1,114 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +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.mes.controller.admin.wm.productsales.vo.line.MesWmProductSalesLinePageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line.MesWmProductSalesLineRespVO; +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line.MesWmProductSalesLineSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; +import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; +import cn.iocoder.yudao.module.mes.service.wm.productsales.MesWmProductSalesLineService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - MES 销售出库单行") +@RestController +@RequestMapping("/mes/wm/product-sales-line") +@Validated +public class MesWmProductSalesLineController { + + @Resource + private MesWmProductSalesLineService productSalesLineService; + + @Resource + private MesMdItemService itemService; + + @Resource + private MesMdUnitMeasureService unitMeasureService; + + @PostMapping("/create") + @Operation(summary = "创建销售出库单行") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:create')") + public CommonResult createProductSalesLine(@Valid @RequestBody MesWmProductSalesLineSaveReqVO createReqVO) { + return success(productSalesLineService.createProductSalesLine(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "修改销售出库单行") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:update')") + public CommonResult updateProductSalesLine(@Valid @RequestBody MesWmProductSalesLineSaveReqVO updateReqVO) { + productSalesLineService.updateProductSalesLine(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除销售出库单行") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:delete')") + public CommonResult deleteProductSalesLine(@RequestParam("id") Long id) { + productSalesLineService.deleteProductSalesLine(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得销售出库单行") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:query')") + public CommonResult getProductSalesLine(@RequestParam("id") Long id) { + MesWmProductSalesLineDO line = productSalesLineService.getProductSalesLine(id); + if (line == null) { + return success(null); + } + return success(buildRespVOList(Collections.singletonList(line)).get(0)); + } + + @GetMapping("/page") + @Operation(summary = "获得销售出库单行分页") + @PreAuthorize("@ss.hasPermission('mes:wm-product-sales:query')") + public CommonResult> getProductSalesLinePage( + @Valid MesWmProductSalesLinePageReqVO pageReqVO) { + PageResult pageResult = productSalesLineService.getProductSalesLinePage(pageReqVO); + return success(new PageResult<>(buildRespVOList(pageResult.getList()), pageResult.getTotal())); + } + + // ==================== 拼接 VO ==================== + + private List buildRespVOList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + // 1. 获得关联数据 + Map itemMap = itemService.getItemMap( + convertSet(list, MesWmProductSalesLineDO::getItemId)); + Map unitMeasureMap = unitMeasureService.getUnitMeasureMap( + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); + // 2. 构建结果 + return BeanUtils.toBean(list, MesWmProductSalesLineRespVO.class, vo -> { + MapUtils.findAndThen(itemMap, vo.getItemId(), item -> { + vo.setItemCode(item.getCode()).setItemName(item.getName()).setSpecification(item.getSpecification()); + MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), + unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); + }); + }); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesPageReqVO.java new file mode 100644 index 0000000..3f65810 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesPageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - MES 销售出库单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MesWmProductSalesPageReqVO extends PageParam { + + @Schema(description = "出库单号", example = "PS2026030001") + private String code; + + @Schema(description = "出库单名称", example = "产品出库单") + private String name; + + @Schema(description = "客户编号", example = "1") + private Long clientId; + + @Schema(description = "状态", example = "0") + private Integer status; + + @Schema(description = "计划发货日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] shipmentDate; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java new file mode 100644 index 0000000..af02953 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesRespVO.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo; + +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - MES 销售出库单 Response VO") +@Data +@ExcelIgnoreUnannotated +public class MesWmProductSalesRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "出库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "PS2026030001") + @ExcelProperty("出库单号") + private String code; + + @Schema(description = "出库单名称", example = "产品出库单") + @ExcelProperty("出库单名称") + private String name; + + @Schema(description = "客户ID", example = "1") + private Long clientId; + + @Schema(description = "客户名称", example = "某客户") + @ExcelProperty("客户") + private String clientName; + + @Schema(description = "销售订单号", example = "SO2026030001") + @ExcelProperty("销售订单号") + private String salesOrderCode; + + @Schema(description = "计划发货日期") + @ExcelProperty("计划发货日期") + private LocalDateTime shipmentDate; + + @Schema(description = "联系人", example = "张三") + @ExcelProperty("联系人") + private String contactName; + + @Schema(description = "联系电话", example = "13800138000") + @ExcelProperty("联系电话") + private String contactTelephone; + + @Schema(description = "收货地址", example = "北京市朝阳区xxx") + @ExcelProperty("收货地址") + private String contactAddress; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @ExcelProperty("状态") + private Integer status; + + @Schema(description = "备注", example = "备注") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java new file mode 100644 index 0000000..22bf6ee --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/MesWmProductSalesSaveReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - MES 销售出库单新增/修改 Request VO") +@Data +public class MesWmProductSalesSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "出库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "PS2026030001") + @NotEmpty(message = "出库单号不能为空") + private String code; + + @Schema(description = "出库单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "产品出库单") + @NotEmpty(message = "出库单名称不能为空") + private String name; + + @Schema(description = "客户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "客户不能为空") + private Long clientId; + + @Schema(description = "销售订单号", example = "SO2026030001") + private String salesOrderCode; + + @Schema(description = "计划发货日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "计划发货日期不能为空") + private LocalDateTime shipmentDate; + + @Schema(description = "联系人", example = "张三") + private String contactName; + + @Schema(description = "联系电话", example = "13800138000") + private String contactTelephone; + + @Schema(description = "收货地址", example = "北京市朝阳区xxx") + private String contactAddress; + + @Schema(description = "备注", example = "备注") + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailPageReqVO.java new file mode 100644 index 0000000..ffb52f8 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailPageReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.detail; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - MES 销售出库明细分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MesWmProductSalesDetailPageReqVO extends PageParam { + + @Schema(description = "出库单ID", example = "1") + private Long salesId; + + @Schema(description = "出库单行ID", example = "1") + private Long lineId; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailRespVO.java new file mode 100644 index 0000000..fbecd97 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailRespVO.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.detail; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - MES 销售出库明细 Response VO") +@Data +public class MesWmProductSalesDetailRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "出库单行ID", example = "1") + private Long lineId; + + @Schema(description = "出库单ID", example = "1") + private Long salesId; + + @Schema(description = "物料ID", example = "1") + private Long itemId; + + @Schema(description = "物料编码", example = "M001") + private String itemCode; + + @Schema(description = "物料名称", example = "产品A") + private String itemName; + + @Schema(description = "规格型号", example = "100g") + private String specification; + + @Schema(description = "单位名称", example = "个") + private String unitMeasureName; + + @Schema(description = "拣货数量", example = "50") + private BigDecimal quantity; + + @Schema(description = "批次ID", example = "1") + private Long batchId; + + @Schema(description = "仓库ID", example = "1") + private Long warehouseId; + + @Schema(description = "仓库名称", example = "成品仓") + private String warehouseName; + + @Schema(description = "库区ID", example = "1") + private Long locationId; + + @Schema(description = "库区名称", example = "A区") + private String locationName; + + @Schema(description = "库位ID", example = "1") + private Long areaId; + + @Schema(description = "库位名称", example = "A-01") + private String areaName; + + @Schema(description = "备注", example = "备注") + private String remark; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailSaveReqVO.java new file mode 100644 index 0000000..33983e2 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/detail/MesWmProductSalesDetailSaveReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.detail; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - MES 销售出库明细新增/修改 Request VO") +@Data +public class MesWmProductSalesDetailSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "出库单行ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "出库单行ID不能为空") + private Long lineId; + + @Schema(description = "出库单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "出库单ID不能为空") + private Long salesId; + + @Schema(description = "物料ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "物料不能为空") + private Long itemId; + + @Schema(description = "拣货数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") + @NotNull(message = "拣货数量不能为空") + private BigDecimal quantity; + + @Schema(description = "批次ID", example = "1") + private Long batchId; + + @Schema(description = "仓库ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "仓库不能为空") + private Long warehouseId; + + @Schema(description = "库区ID", example = "1") + private Long locationId; + + @Schema(description = "库位ID", example = "1") + private Long areaId; + + @Schema(description = "备注", example = "备注") + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLinePageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLinePageReqVO.java new file mode 100644 index 0000000..8964ce3 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLinePageReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - MES 销售出库单行分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MesWmProductSalesLinePageReqVO extends PageParam { + + @Schema(description = "出库单ID", example = "1") + private Long salesId; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLineRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLineRespVO.java new file mode 100644 index 0000000..609a78c --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLineRespVO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - MES 销售出库单行 Response VO") +@Data +public class MesWmProductSalesLineRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "出库单ID", example = "1") + private Long salesId; + + @Schema(description = "物料ID", example = "1") + private Long itemId; + + @Schema(description = "物料编码", example = "M001") + private String itemCode; + + @Schema(description = "物料名称", example = "产品A") + private String itemName; + + @Schema(description = "规格型号", example = "100g") + private String specification; + + @Schema(description = "单位名称", example = "个") + private String unitMeasureName; + + @Schema(description = "出库数量", example = "100") + private BigDecimal quantity; + + @Schema(description = "已拣货数量", example = "50") + private BigDecimal pickedQuantity; + + @Schema(description = "批次ID", example = "1") + private Long batchId; + + @Schema(description = "备注", example = "备注") + private String remark; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLineSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLineSaveReqVO.java new file mode 100644 index 0000000..800dce9 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productsales/vo/line/MesWmProductSalesLineSaveReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - MES 销售出库单行新增/修改 Request VO") +@Data +public class MesWmProductSalesLineSaveReqVO { + + @Schema(description = "编号", example = "1024") + private Long id; + + @Schema(description = "出库单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "出库单ID不能为空") + private Long salesId; + + @Schema(description = "物料ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "物料不能为空") + private Long itemId; + + @Schema(description = "出库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @NotNull(message = "出库数量不能为空") + private BigDecimal quantity; + + @Schema(description = "批次ID", example = "1") + private Long batchId; + + @Schema(description = "备注", example = "备注") + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java new file mode 100644 index 0000000..6c489dd --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDO.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.client.MesMdClientDO; +import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * MES 销售出库单 DO + * + * @author 芋道源码 + */ +@TableName("mes_wm_product_sales") +@KeySequence("mes_wm_product_sales_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MesWmProductSalesDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 出库单号 + */ + private String code; + /** + * 出库单名称 + */ + private String name; + /** + * 客户ID + * + * 关联 {@link MesMdClientDO#getId()} + */ + private Long clientId; + /** + * 销售订单号 + */ + private String salesOrderCode; + // TODO @AI:sales_date 改成这个字段。出库日期 + /** + * 计划发货日期 + */ + private LocalDateTime shipmentDate; + + // TODO @AI:收货地址,删除掉;(界面里也删除掉) + /** + * 收货地址 + */ + private String contactAddress; + // TODO @AI:关联下对应的字段 salesnotice; + /** + * 发货通知单ID + */ + private Long noticeId; + // TODO @AI:noticeCode 不存储; + /** + * 发货通知单编号 + */ + private String noticeCode; + + /** + * 联系人 + */ + private String contactName; + /** + * 联系电话 + */ + private String contactTelephone; + + /** + * 承运商 + */ + private String carrier; + /** + * 运输单号 + */ + private String shippingNumber; + + /** + * 状态 + * + * 枚举 {@link MesWmProductSalesStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDetailDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDetailDO.java new file mode 100644 index 0000000..6ecab64 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesDetailDO.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * MES 销售出库明细 DO + * + * @author 芋道源码 + */ +@TableName("mes_wm_product_sales_detail") +@KeySequence("mes_wm_product_sales_detail_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MesWmProductSalesDetailDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 出库单行ID + * + * 关联 {@link MesWmProductSalesLineDO#getId()} + */ + private Long lineId; + /** + * 出库单ID + * + * 关联 {@link MesWmProductSalesDO#getId()} + */ + private Long salesId; + /** + * 物料ID + * + * 关联 {@link MesMdItemDO#getId()} + */ + private Long itemId; + /** + * 拣货数量 + */ + private BigDecimal quantity; + /** + * 批次ID + */ + private Long batchId; + /** + * 仓库ID + * + * 关联 {@link MesWmWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 库区ID + * + * 关联 {@link MesWmWarehouseLocationDO#getId()} + */ + private Long locationId; + /** + * 库位ID + * + * 关联 {@link MesWmWarehouseAreaDO#getId()} + */ + private Long areaId; + /** + * 备注 + */ + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java new file mode 100644 index 0000000..d2bc3c7 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * MES 销售出库单行 DO + * + * @author 芋道源码 + */ +@TableName("mes_wm_product_sales_line") +@KeySequence("mes_wm_product_sales_line_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MesWmProductSalesLineDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 出库单ID + * + * 关联 {@link MesWmProductSalesDO#getId()} + */ + private Long salesId; + /** + * 物料ID + * + * 关联 {@link MesMdItemDO#getId()} + */ + private Long itemId; + /** + * 出库数量 + */ + private BigDecimal quantity; + // TODO @AI:去掉 pickedQuantity 字段;(不存储) + /** + * 已拣货数量 + */ + private BigDecimal pickedQuantity; + /** + * 批次ID + */ + private Long batchId; + /** + * 库存记录ID + */ + private Long materialStockId; + // TODO @AI:换成 Boolean; + /** + * 是否出厂检验(Y/N) + */ + private String oqcCheck; + /** + * 出厂检验单 ID + */ + // TODO @AI:字段关联 + private Long oqcId; + // TODO @AI:不用 oqcCode 字段; + /** + * 出厂检验单编号 + */ + private String oqcCode; + // TODO @AI:关联枚举类; + /** + * 质量状态 + */ + private String qualityStatus; + /** + * 备注 + */ + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesDetailMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesDetailMapper.java new file mode 100644 index 0000000..dc72bcf --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesDetailMapper.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDetailDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * MES 销售出库明细 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MesWmProductSalesDetailMapper extends BaseMapperX { + + default List selectListByLineId(Long lineId) { + return selectList(MesWmProductSalesDetailDO::getLineId, lineId); + } + + default List selectListBySalesId(Long salesId) { + return selectList(MesWmProductSalesDetailDO::getSalesId, salesId); + } + + default void deleteByLineId(Long lineId) { + delete(MesWmProductSalesDetailDO::getLineId, lineId); + } + + default void deleteBySalesId(Long salesId) { + delete(MesWmProductSalesDetailDO::getSalesId, salesId); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java new file mode 100644 index 0000000..e0f29c8 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesLineMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * MES 销售出库单行 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MesWmProductSalesLineMapper extends BaseMapperX { + + default List selectListBySalesId(Long salesId) { + return selectList(MesWmProductSalesLineDO::getSalesId, salesId); + } + + default void deleteBySalesId(Long salesId) { + delete(MesWmProductSalesLineDO::getSalesId, salesId); + } + + default cn.iocoder.yudao.framework.common.pojo.PageResult selectPage( + cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line.MesWmProductSalesLinePageReqVO reqVO) { + return selectPage(reqVO, new cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX() + .eqIfPresent(MesWmProductSalesLineDO::getSalesId, reqVO.getSalesId()) + .orderByDesc(MesWmProductSalesLineDO::getId)); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesMapper.java new file mode 100644 index 0000000..9a2ab4b --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productsales/MesWmProductSalesMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales; + +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.mes.controller.admin.wm.productsales.vo.MesWmProductSalesPageReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * MES 销售出库单 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MesWmProductSalesMapper extends BaseMapperX { + + default PageResult selectPage(MesWmProductSalesPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(MesWmProductSalesDO::getCode, reqVO.getCode()) + .likeIfPresent(MesWmProductSalesDO::getName, reqVO.getName()) + .eqIfPresent(MesWmProductSalesDO::getClientId, reqVO.getClientId()) + .eqIfPresent(MesWmProductSalesDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(MesWmProductSalesDO::getShipmentDate, reqVO.getShipmentDate()) + .orderByDesc(MesWmProductSalesDO::getId)); + } + + default MesWmProductSalesDO selectByCode(String code) { + return selectOne(MesWmProductSalesDO::getCode, code); + } + +} 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 new file mode 100644 index 0000000..0649864 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductSalesStatusEnum.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.mes.enums.wm; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import cn.iocoder.yudao.module.mes.enums.MesOrderStatusConstants; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * MES 销售出库单状态枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum MesWmProductSalesStatusEnum implements ArrayValuable { + + /** + * 草稿 + */ + PREPARE(MesOrderStatusConstants.PREPARE, "草稿"), + /** + * 待拣货 + */ + APPROVING(MesOrderStatusConstants.APPROVING, "待拣货"), + /** + * 待出库 + */ + APPROVED(MesOrderStatusConstants.APPROVED, "待出库"), + /** + * 已完成 + */ + FINISHED(MesOrderStatusConstants.FINISHED, "已完成"), + /** + * 已取消 + */ + CANCELED(MesOrderStatusConstants.CANCELLED, "已取消"); + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesWmProductSalesStatusEnum::getStatus).toArray(Integer[]::new); + + /** + * 状态值 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailService.java new file mode 100644 index 0000000..23d0997 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailService.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.mes.service.wm.productsales; + +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.detail.MesWmProductSalesDetailSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDetailDO; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * MES 销售出库明细 Service 接口 + * + * @author 芋道源码 + */ +public interface MesWmProductSalesDetailService { + + /** + * 创建销售出库明细 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProductSalesDetail(@Valid MesWmProductSalesDetailSaveReqVO createReqVO); + + /** + * 修改销售出库明细 + * + * @param updateReqVO 修改信息 + */ + void updateProductSalesDetail(@Valid MesWmProductSalesDetailSaveReqVO updateReqVO); + + /** + * 删除销售出库明细 + * + * @param id 编号 + */ + void deleteProductSalesDetail(Long id); + + /** + * 获得销售出库明细 + * + * @param id 编号 + * @return 销售出库明细 + */ + MesWmProductSalesDetailDO getProductSalesDetail(Long id); + + /** + * 按出库单编号获得明细列表 + * + * @param salesId 出库单编号 + * @return 明细列表 + */ + List getProductSalesDetailListBySalesId(Long salesId); + + /** + * 按出库单行编号获得明细列表 + * + * @param lineId 行编号 + * @return 明细列表 + */ + List getProductSalesDetailListByLineId(Long lineId); + + /** + * 按出库单行编号批量删除明细 + * + * @param lineId 行编号 + */ + void deleteProductSalesDetailByLineId(Long lineId); + + /** + * 按出库单编号批量删除明细 + * + * @param salesId 出库单编号 + */ + void deleteProductSalesDetailBySalesId(Long salesId); + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailServiceImpl.java new file mode 100644 index 0000000..3f2657b --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailServiceImpl.java @@ -0,0 +1,106 @@ +package cn.iocoder.yudao.module.mes.service.wm.productsales; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.detail.MesWmProductSalesDetailSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDetailDO; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesDetailMapper; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; + +/** + * MES 销售出库明细 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MesWmProductSalesDetailServiceImpl implements MesWmProductSalesDetailService { + + @Resource + private MesWmProductSalesDetailMapper productSalesDetailMapper; + + @Resource + private MesMdItemService itemService; + + @Resource + private MesWmWarehouseAreaService warehouseAreaService; + + @Override + public Long createProductSalesDetail(MesWmProductSalesDetailSaveReqVO createReqVO) { + // 校验物料存在 + itemService.validateItemExists(createReqVO.getItemId()); + // 校验库区关系 + warehouseAreaService.validateWarehouseAreaExists( + createReqVO.getWarehouseId(), createReqVO.getLocationId(), createReqVO.getAreaId()); + + // 插入 + MesWmProductSalesDetailDO detail = BeanUtils.toBean(createReqVO, MesWmProductSalesDetailDO.class); + productSalesDetailMapper.insert(detail); + return detail.getId(); + } + + @Override + public void updateProductSalesDetail(MesWmProductSalesDetailSaveReqVO updateReqVO) { + // 校验存在 + validateProductSalesDetailExists(updateReqVO.getId()); + // 校验物料存在 + itemService.validateItemExists(updateReqVO.getItemId()); + // 校验库区关系 + warehouseAreaService.validateWarehouseAreaExists( + updateReqVO.getWarehouseId(), updateReqVO.getLocationId(), updateReqVO.getAreaId()); + + // 更新 + MesWmProductSalesDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductSalesDetailDO.class); + productSalesDetailMapper.updateById(updateObj); + } + + @Override + public void deleteProductSalesDetail(Long id) { + // 校验存在 + validateProductSalesDetailExists(id); + // 删除 + productSalesDetailMapper.deleteById(id); + } + + @Override + public MesWmProductSalesDetailDO getProductSalesDetail(Long id) { + return productSalesDetailMapper.selectById(id); + } + + @Override + public List getProductSalesDetailListBySalesId(Long salesId) { + return productSalesDetailMapper.selectListBySalesId(salesId); + } + + @Override + public List getProductSalesDetailListByLineId(Long lineId) { + return productSalesDetailMapper.selectListByLineId(lineId); + } + + @Override + public void deleteProductSalesDetailByLineId(Long lineId) { + productSalesDetailMapper.deleteByLineId(lineId); + } + + @Override + public void deleteProductSalesDetailBySalesId(Long salesId) { + productSalesDetailMapper.deleteBySalesId(salesId); + } + + private MesWmProductSalesDetailDO validateProductSalesDetailExists(Long id) { + MesWmProductSalesDetailDO detail = productSalesDetailMapper.selectById(id); + if (detail == null) { + throw exception(WM_PRODUCT_SALES_DETAIL_NOT_EXISTS); + } + return detail; + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineService.java new file mode 100644 index 0000000..f19ebad --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineService.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.mes.service.wm.productsales; + +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line.MesWmProductSalesLinePageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line.MesWmProductSalesLineSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * MES 销售出库单行 Service 接口 + * + * @author 芋道源码 + */ +public interface MesWmProductSalesLineService { + + /** + * 创建销售出库单行 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProductSalesLine(@Valid MesWmProductSalesLineSaveReqVO createReqVO); + + /** + * 修改销售出库单行 + * + * @param updateReqVO 修改信息 + */ + void updateProductSalesLine(@Valid MesWmProductSalesLineSaveReqVO updateReqVO); + + /** + * 删除销售出库单行(级联删除明细) + * + * @param id 编号 + */ + void deleteProductSalesLine(Long id); + + /** + * 获得销售出库单行 + * + * @param id 编号 + * @return 销售出库单行 + */ + MesWmProductSalesLineDO getProductSalesLine(Long id); + + /** + * 按出库单编号获得行列表 + * + * @param salesId 出库单编号 + * @return 行列表 + */ + List getProductSalesLineListBySalesId(Long salesId); + + /** + * 按出库单编号批量删除行 + * + * @param salesId 出库单编号 + */ + void deleteProductSalesLineBySalesId(Long salesId); + + /** + * 获得销售出库单行分页 + * + * @param pageReqVO 分页查询 + * @return 销售出库单行分页 + */ + cn.iocoder.yudao.framework.common.pojo.PageResult getProductSalesLinePage( + MesWmProductSalesLinePageReqVO pageReqVO); + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineServiceImpl.java new file mode 100644 index 0000000..f7ae041 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineServiceImpl.java @@ -0,0 +1,108 @@ +package cn.iocoder.yudao.module.mes.service.wm.productsales; + +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line.MesWmProductSalesLinePageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line.MesWmProductSalesLineSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesLineMapper; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCT_SALES_LINE_NOT_EXISTS; + +/** + * MES 销售出库单行 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MesWmProductSalesLineServiceImpl implements MesWmProductSalesLineService { + + @Resource + private MesWmProductSalesLineMapper productSalesLineMapper; + + @Resource + @Lazy + private MesWmProductSalesService productSalesService; + + @Resource + private MesWmProductSalesDetailService productSalesDetailService; + + @Resource + private MesMdItemService itemService; + + @Override + public Long createProductSalesLine(MesWmProductSalesLineSaveReqVO createReqVO) { + // 校验物料存在 + itemService.validateItemExists(createReqVO.getItemId()); + + // 新增 + MesWmProductSalesLineDO line = BeanUtils.toBean(createReqVO, MesWmProductSalesLineDO.class); + line.setPickedQuantity(BigDecimal.ZERO); + productSalesLineMapper.insert(line); + return line.getId(); + } + + @Override + public void updateProductSalesLine(MesWmProductSalesLineSaveReqVO updateReqVO) { + // 校验存在 + validateProductSalesLineExists(updateReqVO.getId()); + // 校验物料存在 + itemService.validateItemExists(updateReqVO.getItemId()); + + // 更新 + MesWmProductSalesLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductSalesLineDO.class); + productSalesLineMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteProductSalesLine(Long id) { + // 校验存在 + validateProductSalesLineExists(id); + + // 级联删除明细 + productSalesDetailService.deleteProductSalesDetailByLineId(id); + // 删除 + productSalesLineMapper.deleteById(id); + } + + @Override + public MesWmProductSalesLineDO getProductSalesLine(Long id) { + return productSalesLineMapper.selectById(id); + } + + @Override + public List getProductSalesLineListBySalesId(Long salesId) { + return productSalesLineMapper.selectListBySalesId(salesId); + } + + @Override + public void deleteProductSalesLineBySalesId(Long salesId) { + productSalesLineMapper.deleteBySalesId(salesId); + } + + @Override + public cn.iocoder.yudao.framework.common.pojo.PageResult getProductSalesLinePage( + MesWmProductSalesLinePageReqVO pageReqVO) { + return productSalesLineMapper.selectPage(pageReqVO); + } + + private MesWmProductSalesLineDO validateProductSalesLineExists(Long id) { + MesWmProductSalesLineDO line = productSalesLineMapper.selectById(id); + if (line == null) { + throw exception(WM_PRODUCT_SALES_LINE_NOT_EXISTS); + } + return line; + } + +} 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 new file mode 100644 index 0000000..d9be386 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java @@ -0,0 +1,82 @@ +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.dal.dataobject.wm.productsales.MesWmProductSalesDO; +import jakarta.validation.Valid; + +/** + * MES 销售出库单 Service 接口 + * + * @author 芋道源码 + */ +public interface MesWmProductSalesService { + + /** + * 创建销售出库单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProductSales(@Valid MesWmProductSalesSaveReqVO createReqVO); + + /** + * 修改销售出库单 + * + * @param updateReqVO 修改信息 + */ + void updateProductSales(@Valid MesWmProductSalesSaveReqVO updateReqVO); + + /** + * 删除销售出库单(级联删除行+明细) + * + * @param id 编号 + */ + void deleteProductSales(Long id); + + /** + * 获得销售出库单 + * + * @param id 编号 + * @return 销售出库单 + */ + MesWmProductSalesDO getProductSales(Long id); + + /** + * 获得销售出库单分页 + * + * @param pageReqVO 分页参数 + * @return 销售出库单分页 + */ + PageResult getProductSalesPage(MesWmProductSalesPageReqVO pageReqVO); + + /** + * 提交销售出库单(草稿 → 待拣货) + * + * @param id 编号 + */ + void submitProductSales(Long id); + + /** + * 执行拣货(待拣货 → 待出库) + * + * @param id 编号 + */ + void pickProductSales(Long id); + + /** + * 执行出库(待出库 → 已完成),扣减库存 + * + * @param id 编号 + */ + void executeProductSales(Long id); + + /** + * 取消销售出库单(任意非已完成/已取消状态 → 已取消) + * + * @param id 编号 + */ + void cancelProductSales(Long id); + +} 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 new file mode 100644 index 0000000..f22e510 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java @@ -0,0 +1,215 @@ +package cn.iocoder.yudao.module.mes.service.wm.productsales; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +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.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; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesMapper; +import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum; +import cn.iocoder.yudao.module.mes.service.md.client.MesMdClientService; +import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; + +/** + * MES 销售出库单 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MesWmProductSalesServiceImpl implements MesWmProductSalesService { + + @Resource + private MesWmProductSalesMapper productSalesMapper; + + @Resource + private MesWmProductSalesLineService productSalesLineService; + + @Resource + private MesWmProductSalesDetailService productSalesDetailService; + + @Resource + private MesMdClientService clientService; + + @Resource + private MesWmMaterialStockService materialStockService; + + @Override + public Long createProductSales(MesWmProductSalesSaveReqVO createReqVO) { + // 校验编码唯一 + validateCodeUnique(null, createReqVO.getCode()); + // 校验客户存在 + clientService.validateClientExists(createReqVO.getClientId()); + + // 插入 + MesWmProductSalesDO sales = BeanUtils.toBean(createReqVO, MesWmProductSalesDO.class); + sales.setStatus(MesWmProductSalesStatusEnum.PREPARE.getStatus()); + productSalesMapper.insert(sales); + return sales.getId(); + } + + @Override + public void updateProductSales(MesWmProductSalesSaveReqVO updateReqVO) { + // 校验存在 + 草稿状态 + validateProductSalesExistsAndDraft(updateReqVO.getId()); + // 校验编码唯一 + validateCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); + // 校验客户存在 + clientService.validateClientExists(updateReqVO.getClientId()); + + // 更新 + MesWmProductSalesDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductSalesDO.class); + productSalesMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteProductSales(Long id) { + // 校验存在 + 草稿状态 + validateProductSalesExistsAndDraft(id); + + // 级联删除明细和行 + productSalesDetailService.deleteProductSalesDetailBySalesId(id); + productSalesLineService.deleteProductSalesLineBySalesId(id); + // 删除 + productSalesMapper.deleteById(id); + } + + @Override + public MesWmProductSalesDO getProductSales(Long id) { + return productSalesMapper.selectById(id); + } + + @Override + public PageResult getProductSalesPage(MesWmProductSalesPageReqVO pageReqVO) { + return productSalesMapper.selectPage(pageReqVO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void submitProductSales(Long id) { + // 校验存在 + 草稿状态 + validateProductSalesExistsAndDraft(id); + // 校验至少有一条行 + List lines = productSalesLineService.getProductSalesLineListBySalesId(id); + if (CollUtil.isEmpty(lines)) { + throw exception(WM_PRODUCT_SALES_LINES_EMPTY); + } + + // 提交(草稿 → 待拣货) + productSalesMapper.updateById(new MesWmProductSalesDO() + .setId(id).setStatus(MesWmProductSalesStatusEnum.APPROVING.getStatus())); + } + + @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); + } + // 校验每行明细数量之和是否等于行出库数量 + 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); + } + 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); + } + } + + // 执行拣货(待拣货 → 待出库) + productSalesMapper.updateById(new MesWmProductSalesDO() + .setId(id).setStatus(MesWmProductSalesStatusEnum.APPROVED.getStatus())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void executeProductSales(Long id) { + // 校验存在 + MesWmProductSalesDO sales = validateProductSalesExists(id); + if (ObjUtil.notEqual(MesWmProductSalesStatusEnum.APPROVED.getStatus(), sales.getStatus())) { + throw exception(WM_PRODUCT_SALES_CANNOT_EXECUTE); + } + + // 遍历所有明细,扣减库存 + // TODO @AI:需要实现 decreaseStock 方法 + List details = productSalesDetailService.getProductSalesDetailListBySalesId(id); + for (MesWmProductSalesDetailDO detail : details) { + // materialStockService.decreaseStock( + // detail.getItemId(), detail.getWarehouseId(), detail.getLocationId(), detail.getAreaId(), + // detail.getBatchId(), detail.getQuantity(), sales.getClientId(), null, null); + } + + // 更新出库单状态 + productSalesMapper.updateById(new MesWmProductSalesDO() + .setId(id).setStatus(MesWmProductSalesStatusEnum.FINISHED.getStatus())); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void cancelProductSales(Long id) { + // 校验存在 + MesWmProductSalesDO sales = validateProductSalesExists(id); + // 已完成和已取消不允许取消 + if (ObjectUtils.equalsAny(sales.getStatus(), + MesWmProductSalesStatusEnum.FINISHED.getStatus(), + MesWmProductSalesStatusEnum.CANCELED.getStatus())) { + throw exception(WM_PRODUCT_SALES_CANNOT_CANCEL); + } + // 取消 + productSalesMapper.updateById(new MesWmProductSalesDO() + .setId(id).setStatus(MesWmProductSalesStatusEnum.CANCELED.getStatus())); + } + + private MesWmProductSalesDO validateProductSalesExists(Long id) { + MesWmProductSalesDO sales = productSalesMapper.selectById(id); + if (sales == null) { + throw exception(WM_PRODUCT_SALES_NOT_EXISTS); + } + return sales; + } + + /** + * 校验销售出库单存在且为草稿状态 + */ + private MesWmProductSalesDO validateProductSalesExistsAndDraft(Long id) { + MesWmProductSalesDO sales = validateProductSalesExists(id); + if (ObjUtil.notEqual(MesWmProductSalesStatusEnum.PREPARE.getStatus(), sales.getStatus())) { + throw exception(WM_PRODUCT_SALES_NOT_PREPARE); + } + return sales; + } + + private void validateCodeUnique(Long id, String code) { + MesWmProductSalesDO sales = productSalesMapper.selectByCode(code); + if (sales == null) { + return; + } + if (ObjUtil.notEqual(id, sales.getId())) { + throw exception(WM_PRODUCT_SALES_CODE_DUPLICATE); + } + } + +} -- libgit2 0.21.4