Commit c96487f59482bee4c0dcad578ca09d69b3940f5f

Authored by YunaiV
1 parent 9bebb4ce

feat(wms):新增移库、盘库管理

Showing 30 changed files with 2823 additions and 0 deletions
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/WmsCheckOrderController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.check;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.NumberUtil;
  5 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  6 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  9 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  10 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  11 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  12 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  13 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  14 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.detail.WmsCheckOrderDetailRespVO;
  15 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order.WmsCheckOrderPageReqVO;
  16 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order.WmsCheckOrderRespVO;
  17 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order.WmsCheckOrderSaveReqVO;
  18 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
  19 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
  20 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO;
  21 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
  22 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.check.WmsCheckOrderDO;
  23 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.check.WmsCheckOrderDetailDO;
  24 +import cn.iocoder.yudao.module.wms.framework.config.WmsProperties;
  25 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
  26 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
  27 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseAreaService;
  28 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
  29 +import cn.iocoder.yudao.module.wms.service.order.check.WmsCheckOrderDetailService;
  30 +import cn.iocoder.yudao.module.wms.service.order.check.WmsCheckOrderService;
  31 +import io.swagger.v3.oas.annotations.Operation;
  32 +import io.swagger.v3.oas.annotations.Parameter;
  33 +import io.swagger.v3.oas.annotations.tags.Tag;
  34 +import jakarta.annotation.Resource;
  35 +import jakarta.servlet.http.HttpServletResponse;
  36 +import jakarta.validation.Valid;
  37 +import org.springframework.security.access.prepost.PreAuthorize;
  38 +import org.springframework.validation.annotation.Validated;
  39 +import org.springframework.web.bind.annotation.*;
  40 +
  41 +import java.io.IOException;
  42 +import java.math.BigDecimal;
  43 +import java.util.Collections;
  44 +import java.util.List;
  45 +import java.util.Map;
  46 +import java.util.stream.Stream;
  47 +
  48 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
  49 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  50 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  51 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
  52 +
  53 +@Tag(name = "管理后台 - WMS 盘库单")
  54 +@RestController
  55 +@RequestMapping("/wms/check-order")
  56 +@Validated
  57 +public class WmsCheckOrderController {
  58 +
  59 + @Resource
  60 + private WmsCheckOrderService checkOrderService;
  61 + @Resource
  62 + private WmsCheckOrderDetailService checkOrderDetailService;
  63 + @Resource
  64 + private WmsWarehouseService warehouseService;
  65 + @Resource
  66 + private WmsWarehouseAreaService warehouseAreaService;
  67 + @Resource
  68 + private WmsItemService itemService;
  69 + @Resource
  70 + private WmsItemSkuService itemSkuService;
  71 +
  72 + @Resource
  73 + private WmsProperties wmsProperties;
  74 +
  75 + @Resource
  76 + private AdminUserApi adminUserApi;
  77 +
  78 + @PostMapping("/create")
  79 + @Operation(summary = "创建盘库单")
  80 + @PreAuthorize("@ss.hasPermission('wms:check-order:create')")
  81 + public CommonResult<Long> createCheckOrder(@Valid @RequestBody WmsCheckOrderSaveReqVO createReqVO) {
  82 + return success(checkOrderService.createCheckOrder(createReqVO));
  83 + }
  84 +
  85 + @PutMapping("/update")
  86 + @Operation(summary = "更新盘库单")
  87 + @PreAuthorize("@ss.hasPermission('wms:check-order:update')")
  88 + public CommonResult<Boolean> updateCheckOrder(@Valid @RequestBody WmsCheckOrderSaveReqVO updateReqVO) {
  89 + checkOrderService.updateCheckOrder(updateReqVO);
  90 + return success(true);
  91 + }
  92 +
  93 + @DeleteMapping("/delete")
  94 + @Operation(summary = "删除盘库单")
  95 + @Parameter(name = "id", description = "编号", required = true)
  96 + @PreAuthorize("@ss.hasPermission('wms:check-order:delete')")
  97 + public CommonResult<Boolean> deleteCheckOrder(@RequestParam("id") Long id) {
  98 + checkOrderService.deleteCheckOrder(id);
  99 + return success(true);
  100 + }
  101 +
  102 + @PutMapping("/complete")
  103 + @Operation(summary = "完成盘库")
  104 + @Parameter(name = "id", description = "编号", required = true)
  105 + @PreAuthorize("@ss.hasPermission('wms:check-order:complete')")
  106 + public CommonResult<Boolean> completeCheckOrder(@RequestParam("id") Long id) {
  107 + checkOrderService.completeCheckOrder(id);
  108 + return success(true);
  109 + }
  110 +
  111 + @PutMapping("/cancel")
  112 + @Operation(summary = "作废盘库单")
  113 + @Parameter(name = "id", description = "编号", required = true)
  114 + @PreAuthorize("@ss.hasPermission('wms:check-order:cancel')")
  115 + public CommonResult<Boolean> cancelCheckOrder(@RequestParam("id") Long id) {
  116 + checkOrderService.cancelCheckOrder(id);
  117 + return success(true);
  118 + }
  119 +
  120 + @GetMapping("/get")
  121 + @Operation(summary = "获得盘库单")
  122 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  123 + @PreAuthorize("@ss.hasPermission('wms:check-order:query')")
  124 + public CommonResult<WmsCheckOrderRespVO> getCheckOrder(@RequestParam("id") Long id) {
  125 + WmsCheckOrderDO order = checkOrderService.getCheckOrder(id);
  126 + if (order == null) {
  127 + return success(null);
  128 + }
  129 + // 获得盘库单的明细列表
  130 + List<WmsCheckOrderDetailDO> detailList = checkOrderDetailService.getCheckOrderDetailList(id);
  131 + // 拼接结果返回
  132 + WmsCheckOrderRespVO respVO = buildCheckOrderRespVO(order)
  133 + .setDetails(buildCheckOrderDetailRespVOList(detailList));
  134 + return success(respVO);
  135 + }
  136 +
  137 + @GetMapping("/page")
  138 + @Operation(summary = "获得盘库单分页")
  139 + @PreAuthorize("@ss.hasPermission('wms:check-order:query')")
  140 + public CommonResult<PageResult<WmsCheckOrderRespVO>> getCheckOrderPage(@Valid WmsCheckOrderPageReqVO pageReqVO) {
  141 + PageResult<WmsCheckOrderDO> pageResult = checkOrderService.getCheckOrderPage(pageReqVO);
  142 + return success(new PageResult<>(buildCheckOrderRespVOList(pageResult.getList()), pageResult.getTotal()));
  143 + }
  144 +
  145 + @GetMapping("/export-excel")
  146 + @Operation(summary = "导出盘库单 Excel")
  147 + @PreAuthorize("@ss.hasPermission('wms:check-order:export')")
  148 + @ApiAccessLog(operateType = EXPORT)
  149 + public void exportCheckOrderExcel(@Valid WmsCheckOrderPageReqVO pageReqVO,
  150 + HttpServletResponse response) throws IOException {
  151 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  152 + List<WmsCheckOrderDO> list = checkOrderService.getCheckOrderPage(pageReqVO).getList();
  153 + ExcelUtils.write(response, "盘库单.xls", "数据", WmsCheckOrderRespVO.class,
  154 + buildCheckOrderRespVOList(list));
  155 + }
  156 +
  157 + // ==================== 拼接 VO ====================
  158 +
  159 + private WmsCheckOrderRespVO buildCheckOrderRespVO(WmsCheckOrderDO order) {
  160 + if (order == null) {
  161 + return null;
  162 + }
  163 + List<WmsCheckOrderRespVO> list = buildCheckOrderRespVOList(List.of(order));
  164 + return CollUtil.getFirst(list);
  165 + }
  166 +
  167 + private List<WmsCheckOrderRespVO> buildCheckOrderRespVOList(List<WmsCheckOrderDO> list) {
  168 + if (CollUtil.isEmpty(list)) {
  169 + return Collections.emptyList();
  170 + }
  171 + // 获取相关的仓库、库区、用户等数据
  172 + Map<Long, WmsWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(convertSet(list, WmsCheckOrderDO::getWarehouseId));
  173 + Map<Long, WmsWarehouseAreaDO> areaMap = wmsProperties.isAreaEnabled()
  174 + ? warehouseAreaService.getWarehouseAreaMap(convertSet(list, WmsCheckOrderDO::getAreaId))
  175 + : Collections.emptyMap();
  176 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSetByFlatMap(list,
  177 + order -> Stream.of(parseUserId(order.getCreator()), parseUserId(order.getUpdater()))));
  178 + // 拼接数据
  179 + return BeanUtils.toBean(list, WmsCheckOrderRespVO.class, vo -> {
  180 + MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
  181 + MapUtils.findAndThen(areaMap, vo.getAreaId(), area -> vo.setAreaName(area.getName()));
  182 + MapUtils.findAndThen(userMap, parseUserId(vo.getCreator()), user -> vo.setCreatorName(user.getNickname()));
  183 + MapUtils.findAndThen(userMap, parseUserId(vo.getUpdater()), user -> vo.setUpdaterName(user.getNickname()));
  184 + });
  185 + }
  186 +
  187 + private Long parseUserId(String userId) {
  188 + return NumberUtil.parseLong(userId, null);
  189 + }
  190 +
  191 + private List<WmsCheckOrderDetailRespVO> buildCheckOrderDetailRespVOList(List<WmsCheckOrderDetailDO> list) {
  192 + if (CollUtil.isEmpty(list)) {
  193 + return Collections.emptyList();
  194 + }
  195 + // 获取相关的商品、SKU、仓库、库区等数据
  196 + Map<Long, WmsItemSkuDO> skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsCheckOrderDetailDO::getSkuId));
  197 + Map<Long, WmsItemDO> itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
  198 + Map<Long, WmsWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(
  199 + convertSet(list, WmsCheckOrderDetailDO::getWarehouseId));
  200 + Map<Long, WmsWarehouseAreaDO> areaMap = wmsProperties.isAreaEnabled()
  201 + ? warehouseAreaService.getWarehouseAreaMap(convertSet(list, WmsCheckOrderDetailDO::getAreaId))
  202 + : Collections.emptyMap();
  203 + // 拼接数据
  204 + return BeanUtils.toBean(list, WmsCheckOrderDetailRespVO.class, vo -> {
  205 + MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
  206 + vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
  207 + MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
  208 + .setItemName(item.getName()).setUnit(item.getUnit()));
  209 + });
  210 + MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
  211 + MapUtils.findAndThen(areaMap, vo.getAreaId(), area -> vo.setAreaName(area.getName()));
  212 + if (vo.getQuantity() != null && vo.getCheckQuantity() != null) {
  213 + vo.setDifferenceQuantity(vo.getCheckQuantity().subtract(vo.getQuantity()));
  214 + } else {
  215 + vo.setDifferenceQuantity(BigDecimal.ZERO);
  216 + }
  217 + });
  218 + }
  219 +
  220 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/WmsCheckOrderDetailController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.check;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.detail.WmsCheckOrderDetailRespVO;
  8 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
  9 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
  10 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO;
  11 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
  12 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.check.WmsCheckOrderDetailDO;
  13 +import cn.iocoder.yudao.module.wms.framework.config.WmsProperties;
  14 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
  15 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
  16 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseAreaService;
  17 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
  18 +import cn.iocoder.yudao.module.wms.service.order.check.WmsCheckOrderDetailService;
  19 +import io.swagger.v3.oas.annotations.Operation;
  20 +import io.swagger.v3.oas.annotations.Parameter;
  21 +import io.swagger.v3.oas.annotations.tags.Tag;
  22 +import jakarta.annotation.Resource;
  23 +import org.springframework.security.access.prepost.PreAuthorize;
  24 +import org.springframework.validation.annotation.Validated;
  25 +import org.springframework.web.bind.annotation.GetMapping;
  26 +import org.springframework.web.bind.annotation.RequestMapping;
  27 +import org.springframework.web.bind.annotation.RequestParam;
  28 +import org.springframework.web.bind.annotation.RestController;
  29 +
  30 +import java.math.BigDecimal;
  31 +import java.util.Collections;
  32 +import java.util.List;
  33 +import java.util.Map;
  34 +
  35 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  36 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  37 +
  38 +@Tag(name = "管理后台 - WMS 盘库单明细")
  39 +@RestController
  40 +@RequestMapping("/wms/check-order-detail")
  41 +@Validated
  42 +public class WmsCheckOrderDetailController {
  43 +
  44 + @Resource
  45 + private WmsCheckOrderDetailService checkOrderDetailService;
  46 + @Resource
  47 + private WmsItemService itemService;
  48 + @Resource
  49 + private WmsItemSkuService itemSkuService;
  50 + @Resource
  51 + private WmsWarehouseService warehouseService;
  52 + @Resource
  53 + private WmsWarehouseAreaService warehouseAreaService;
  54 +
  55 + @Resource
  56 + private WmsProperties wmsProperties;
  57 +
  58 + @GetMapping("/list-by-order-id")
  59 + @Operation(summary = "获得盘库单明细列表")
  60 + @Parameter(name = "orderId", description = "盘库单编号", required = true, example = "1024")
  61 + @PreAuthorize("@ss.hasPermission('wms:check-order:query')")
  62 + public CommonResult<List<WmsCheckOrderDetailRespVO>> getCheckOrderDetailListByOrderId(
  63 + @RequestParam("orderId") Long orderId) {
  64 + List<WmsCheckOrderDetailDO> list = checkOrderDetailService.getCheckOrderDetailList(orderId);
  65 + return success(buildCheckOrderDetailRespVOList(list));
  66 + }
  67 +
  68 + // ==================== 拼接 VO ====================
  69 +
  70 + private List<WmsCheckOrderDetailRespVO> buildCheckOrderDetailRespVOList(List<WmsCheckOrderDetailDO> list) {
  71 + if (CollUtil.isEmpty(list)) {
  72 + return Collections.emptyList();
  73 + }
  74 + // 查询关联数据
  75 + Map<Long, WmsItemSkuDO> skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsCheckOrderDetailDO::getSkuId));
  76 + Map<Long, WmsItemDO> itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
  77 + Map<Long, WmsWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(
  78 + convertSet(list, WmsCheckOrderDetailDO::getWarehouseId));
  79 + Map<Long, WmsWarehouseAreaDO> areaMap = wmsProperties.isAreaEnabled()
  80 + ? warehouseAreaService.getWarehouseAreaMap(convertSet(list, WmsCheckOrderDetailDO::getAreaId))
  81 + : Collections.emptyMap();
  82 + // 拼接数据
  83 + return BeanUtils.toBean(list, WmsCheckOrderDetailRespVO.class, vo -> {
  84 + MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
  85 + vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
  86 + MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
  87 + .setItemName(item.getName()).setUnit(item.getUnit()));
  88 + });
  89 + MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
  90 + MapUtils.findAndThen(areaMap, vo.getAreaId(), area -> vo.setAreaName(area.getName()));
  91 + if (vo.getQuantity() != null && vo.getCheckQuantity() != null) {
  92 + vo.setDifferenceQuantity(vo.getCheckQuantity().subtract(vo.getQuantity()));
  93 + } else {
  94 + vo.setDifferenceQuantity(BigDecimal.ZERO);
  95 + }
  96 + });
  97 + }
  98 +
  99 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/detail/WmsCheckOrderDetailRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.detail;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.math.BigDecimal;
  7 +import java.time.LocalDateTime;
  8 +
  9 +@Schema(description = "管理后台 - WMS 盘库单明细 Response VO")
  10 +@Data
  11 +public class WmsCheckOrderDetailRespVO {
  12 +
  13 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  14 + private Long id;
  15 +
  16 + @Schema(description = "盘库单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  17 + private Long orderId;
  18 +
  19 + @Schema(description = "商品编号", example = "2048")
  20 + private Long itemId;
  21 +
  22 + @Schema(description = "商品编号", example = "SPU-APPLE")
  23 + private String itemCode;
  24 +
  25 + @Schema(description = "商品名称", example = "红富士苹果")
  26 + private String itemName;
  27 +
  28 + @Schema(description = "商品单位", example = "箱")
  29 + private String unit;
  30 +
  31 + @Schema(description = "SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
  32 + private Long skuId;
  33 +
  34 + @Schema(description = "规格编号", example = "SKU-APPLE-10KG")
  35 + private String skuCode;
  36 +
  37 + @Schema(description = "规格名称", example = "10kg 箱装")
  38 + private String skuName;
  39 +
  40 + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  41 + private Long warehouseId;
  42 +
  43 + @Schema(description = "仓库名称", example = "北京仓")
  44 + private String warehouseName;
  45 +
  46 + @Schema(description = "库区编号", example = "1024")
  47 + private Long areaId;
  48 +
  49 + @Schema(description = "库区名称", example = "北京库区01")
  50 + private String areaName;
  51 +
  52 + @Schema(description = "库存编号", example = "1024")
  53 + private Long inventoryId;
  54 +
  55 + @Schema(description = "库存明细编号", example = "1024")
  56 + private Long inventoryDetailId;
  57 +
  58 + @Schema(description = "批号", example = "B202605110001")
  59 + private String batchNo;
  60 +
  61 + @Schema(description = "生产日期")
  62 + private LocalDateTime productionDate;
  63 +
  64 + @Schema(description = "过期日期")
  65 + private LocalDateTime expirationDate;
  66 +
  67 + @Schema(description = "入库时间")
  68 + private LocalDateTime receiptTime;
  69 +
  70 + @Schema(description = "账面数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  71 + private BigDecimal quantity;
  72 +
  73 + @Schema(description = "实盘数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "98.00")
  74 + private BigDecimal checkQuantity;
  75 +
  76 + @Schema(description = "盈亏数量", example = "-2.00")
  77 + private BigDecimal differenceQuantity;
  78 +
  79 + @Schema(description = "金额", example = "1000.00")
  80 + private BigDecimal amount;
  81 +
  82 + @Schema(description = "备注", example = "备注")
  83 + private String remark;
  84 +
  85 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  86 + private LocalDateTime createTime;
  87 +
  88 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/detail/WmsCheckOrderDetailSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.detail;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.DecimalMin;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import jakarta.validation.constraints.Size;
  7 +import lombok.Data;
  8 +
  9 +import java.math.BigDecimal;
  10 +import java.time.LocalDateTime;
  11 +
  12 +@Schema(description = "管理后台 - WMS 盘库单明细保存 Request VO")
  13 +@Data
  14 +public class WmsCheckOrderDetailSaveReqVO {
  15 +
  16 + @Schema(description = "编号", example = "1024")
  17 + private Long id;
  18 +
  19 + @Schema(description = "SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
  20 + @NotNull(message = "SKU 不能为空")
  21 + private Long skuId;
  22 +
  23 + @Schema(description = "库区编号", example = "1024")
  24 + private Long areaId;
  25 +
  26 + @Schema(description = "库存编号", example = "1024")
  27 + private Long inventoryId;
  28 +
  29 + @Schema(description = "库存明细编号", example = "1024")
  30 + private Long inventoryDetailId;
  31 +
  32 + @Schema(description = "批号", example = "B202605110001")
  33 + @Size(max = 64, message = "批号长度不能超过 64 个字符")
  34 + private String batchNo;
  35 +
  36 + @Schema(description = "生产日期")
  37 + private LocalDateTime productionDate;
  38 +
  39 + @Schema(description = "过期日期")
  40 + private LocalDateTime expirationDate;
  41 +
  42 + @Schema(description = "入库时间")
  43 + private LocalDateTime receiptTime;
  44 +
  45 + @Schema(description = "账面数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  46 + @NotNull(message = "账面数量不能为空")
  47 + @DecimalMin(value = "0", message = "账面数量不能小于 0")
  48 + private BigDecimal quantity;
  49 +
  50 + @Schema(description = "实盘数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "98.00")
  51 + @NotNull(message = "实盘数量不能为空")
  52 + @DecimalMin(value = "0", message = "实盘数量不能小于 0")
  53 + private BigDecimal checkQuantity;
  54 +
  55 + @Schema(description = "金额", example = "1000.00")
  56 + @DecimalMin(value = "0", message = "金额不能小于 0")
  57 + private BigDecimal amount;
  58 +
  59 + @Schema(description = "备注", example = "备注")
  60 + @Size(max = 255, message = "备注长度不能超过 255 个字符")
  61 + private String remark;
  62 +
  63 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import cn.iocoder.yudao.module.wms.enums.order.WmsOrderStatusEnum;
  6 +import io.swagger.v3.oas.annotations.media.Schema;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import lombok.ToString;
  10 +import org.springframework.format.annotation.DateTimeFormat;
  11 +
  12 +import java.math.BigDecimal;
  13 +import java.time.LocalDateTime;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  16 +
  17 +@Schema(description = "管理后台 - WMS 盘库单分页 Request VO")
  18 +@Data
  19 +@EqualsAndHashCode(callSuper = true)
  20 +@ToString(callSuper = true)
  21 +public class WmsCheckOrderPageReqVO extends PageParam {
  22 +
  23 + @Schema(description = "盘库单号", example = "PK202605110001")
  24 + private String no;
  25 +
  26 + @Schema(description = "单据状态", example = "0")
  27 + @InEnum(WmsOrderStatusEnum.class)
  28 + private Integer status;
  29 +
  30 + @Schema(description = "仓库编号", example = "1024")
  31 + private Long warehouseId;
  32 +
  33 + @Schema(description = "库区编号", example = "1024")
  34 + private Long areaId;
  35 +
  36 + @Schema(description = "单据日期")
  37 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  38 + private LocalDateTime[] orderDate;
  39 +
  40 + @Schema(description = "最小盈亏数量", example = "-10.00")
  41 + private BigDecimal totalQuantityMin;
  42 +
  43 + @Schema(description = "最大盈亏数量", example = "100.00")
  44 + private BigDecimal totalQuantityMax;
  45 +
  46 + @Schema(description = "最小总金额", example = "1.00")
  47 + private BigDecimal totalAmountMin;
  48 +
  49 + @Schema(description = "最大总金额", example = "1000.00")
  50 + private BigDecimal totalAmountMax;
  51 +
  52 + @Schema(description = "创建用户", example = "1")
  53 + private String creator;
  54 +
  55 + @Schema(description = "更新用户", example = "1")
  56 + private String updater;
  57 +
  58 + @Schema(description = "创建时间")
  59 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  60 + private LocalDateTime[] createTime;
  61 +
  62 + @Schema(description = "更新时间")
  63 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  64 + private LocalDateTime[] updateTime;
  65 +
  66 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order;
  2 +
  3 +import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
  4 +import cn.idev.excel.annotation.ExcelProperty;
  5 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  6 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  7 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.detail.WmsCheckOrderDetailRespVO;
  8 +import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
  9 +import io.swagger.v3.oas.annotations.media.Schema;
  10 +import lombok.Data;
  11 +
  12 +import java.math.BigDecimal;
  13 +import java.time.LocalDateTime;
  14 +import java.util.List;
  15 +
  16 +@Schema(description = "管理后台 - WMS 盘库单 Response VO")
  17 +@Data
  18 +@ExcelIgnoreUnannotated
  19 +public class WmsCheckOrderRespVO {
  20 +
  21 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  22 + private Long id;
  23 +
  24 + @Schema(description = "盘库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "PK202605110001")
  25 + @ExcelProperty("盘库单号")
  26 + private String no;
  27 +
  28 + @Schema(description = "盘库状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  29 + @ExcelProperty(value = "盘库状态", converter = DictConvert.class)
  30 + @DictFormat(DictTypeConstants.ORDER_STATUS)
  31 + private Integer status;
  32 +
  33 + @Schema(description = "备注", example = "备注")
  34 + private String remark;
  35 +
  36 + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  37 + private Long warehouseId;
  38 +
  39 + @Schema(description = "仓库名称", example = "北京仓")
  40 + @ExcelProperty("仓库")
  41 + private String warehouseName;
  42 +
  43 + @Schema(description = "库区编号", example = "1024")
  44 + private Long areaId;
  45 +
  46 + @Schema(description = "库区名称", example = "北京库区01")
  47 + private String areaName;
  48 +
  49 + @Schema(description = "盈亏数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  50 + @ExcelProperty("盈亏数量")
  51 + private BigDecimal totalQuantity;
  52 +
  53 + @Schema(description = "总金额", example = "1000.00")
  54 + @ExcelProperty("总金额")
  55 + private BigDecimal totalAmount;
  56 +
  57 + @Schema(description = "盘库明细")
  58 + private List<WmsCheckOrderDetailRespVO> details;
  59 +
  60 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  61 + @ExcelProperty("创建时间")
  62 + private LocalDateTime createTime;
  63 +
  64 + @Schema(description = "创建者", example = "1")
  65 + private String creator;
  66 + @Schema(description = "创建者名称", example = "芋道")
  67 + private String creatorName;
  68 +
  69 + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
  70 + private LocalDateTime updateTime;
  71 +
  72 + @Schema(description = "更新者", example = "1")
  73 + private String updater;
  74 + @Schema(description = "更新者名称", example = "芋道")
  75 + private String updaterName;
  76 +
  77 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order;
  2 +
  3 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.detail.WmsCheckOrderDetailSaveReqVO;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import jakarta.validation.Valid;
  6 +import jakarta.validation.constraints.NotBlank;
  7 +import jakarta.validation.constraints.NotNull;
  8 +import jakarta.validation.constraints.Size;
  9 +import lombok.Data;
  10 +
  11 +import java.math.BigDecimal;
  12 +import java.util.List;
  13 +
  14 +@Schema(description = "管理后台 - WMS 盘库单保存 Request VO")
  15 +@Data
  16 +public class WmsCheckOrderSaveReqVO {
  17 +
  18 + @Schema(description = "编号", example = "1024")
  19 + private Long id;
  20 +
  21 + @Schema(description = "盘库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "PK202605110001")
  22 + @NotBlank(message = "盘库单号不能为空")
  23 + @Size(max = 64, message = "盘库单号长度不能超过 64 个字符")
  24 + private String no;
  25 +
  26 + @Schema(description = "备注", example = "备注")
  27 + @Size(max = 255, message = "备注长度不能超过 255 个字符")
  28 + private String remark;
  29 +
  30 + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  31 + @NotNull(message = "仓库不能为空")
  32 + private Long warehouseId;
  33 +
  34 + @Schema(description = "库区编号", example = "1024")
  35 + private Long areaId;
  36 +
  37 + @Schema(description = "盈亏数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  38 + @NotNull(message = "盈亏数量不能为空")
  39 + private BigDecimal totalQuantity;
  40 +
  41 + @Schema(description = "总金额", example = "1000.00")
  42 + private BigDecimal totalAmount;
  43 +
  44 + @Schema(description = "盘库明细")
  45 + @Valid
  46 + private List<WmsCheckOrderDetailSaveReqVO> details;
  47 +
  48 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/WmsMovementOrderController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.movement;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.NumberUtil;
  5 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  6 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  9 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  10 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  11 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  12 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  13 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  14 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.detail.WmsMovementOrderDetailRespVO;
  15 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order.WmsMovementOrderPageReqVO;
  16 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order.WmsMovementOrderRespVO;
  17 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order.WmsMovementOrderSaveReqVO;
  18 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
  19 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
  20 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO;
  21 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
  22 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.movement.WmsMovementOrderDO;
  23 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.movement.WmsMovementOrderDetailDO;
  24 +import cn.iocoder.yudao.module.wms.framework.config.WmsProperties;
  25 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
  26 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
  27 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseAreaService;
  28 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
  29 +import cn.iocoder.yudao.module.wms.service.order.movement.WmsMovementOrderDetailService;
  30 +import cn.iocoder.yudao.module.wms.service.order.movement.WmsMovementOrderService;
  31 +import io.swagger.v3.oas.annotations.Operation;
  32 +import io.swagger.v3.oas.annotations.Parameter;
  33 +import io.swagger.v3.oas.annotations.tags.Tag;
  34 +import jakarta.annotation.Resource;
  35 +import jakarta.servlet.http.HttpServletResponse;
  36 +import jakarta.validation.Valid;
  37 +import org.springframework.security.access.prepost.PreAuthorize;
  38 +import org.springframework.validation.annotation.Validated;
  39 +import org.springframework.web.bind.annotation.*;
  40 +
  41 +import java.io.IOException;
  42 +import java.util.Collections;
  43 +import java.util.List;
  44 +import java.util.Map;
  45 +import java.util.stream.Stream;
  46 +
  47 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
  48 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  49 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  50 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
  51 +
  52 +@Tag(name = "管理后台 - WMS 移库单")
  53 +@RestController
  54 +@RequestMapping("/wms/movement-order")
  55 +@Validated
  56 +public class WmsMovementOrderController {
  57 +
  58 + @Resource
  59 + private WmsMovementOrderService movementOrderService;
  60 + @Resource
  61 + private WmsMovementOrderDetailService movementOrderDetailService;
  62 + @Resource
  63 + private WmsWarehouseService warehouseService;
  64 + @Resource
  65 + private WmsWarehouseAreaService warehouseAreaService;
  66 + @Resource
  67 + private WmsItemService itemService;
  68 + @Resource
  69 + private WmsItemSkuService itemSkuService;
  70 +
  71 + @Resource
  72 + private WmsProperties wmsProperties;
  73 +
  74 + @Resource
  75 + private AdminUserApi adminUserApi;
  76 +
  77 + @PostMapping("/create")
  78 + @Operation(summary = "创建移库单")
  79 + @PreAuthorize("@ss.hasPermission('wms:movement-order:create')")
  80 + public CommonResult<Long> createMovementOrder(@Valid @RequestBody WmsMovementOrderSaveReqVO createReqVO) {
  81 + return success(movementOrderService.createMovementOrder(createReqVO));
  82 + }
  83 +
  84 + @PutMapping("/update")
  85 + @Operation(summary = "更新移库单")
  86 + @PreAuthorize("@ss.hasPermission('wms:movement-order:update')")
  87 + public CommonResult<Boolean> updateMovementOrder(@Valid @RequestBody WmsMovementOrderSaveReqVO updateReqVO) {
  88 + movementOrderService.updateMovementOrder(updateReqVO);
  89 + return success(true);
  90 + }
  91 +
  92 + @DeleteMapping("/delete")
  93 + @Operation(summary = "删除移库单")
  94 + @Parameter(name = "id", description = "编号", required = true)
  95 + @PreAuthorize("@ss.hasPermission('wms:movement-order:delete')")
  96 + public CommonResult<Boolean> deleteMovementOrder(@RequestParam("id") Long id) {
  97 + movementOrderService.deleteMovementOrder(id);
  98 + return success(true);
  99 + }
  100 +
  101 + @PutMapping("/complete")
  102 + @Operation(summary = "完成移库")
  103 + @Parameter(name = "id", description = "编号", required = true)
  104 + @PreAuthorize("@ss.hasPermission('wms:movement-order:complete')")
  105 + public CommonResult<Boolean> completeMovementOrder(@RequestParam("id") Long id) {
  106 + movementOrderService.completeMovementOrder(id);
  107 + return success(true);
  108 + }
  109 +
  110 + @PutMapping("/cancel")
  111 + @Operation(summary = "作废移库单")
  112 + @Parameter(name = "id", description = "编号", required = true)
  113 + @PreAuthorize("@ss.hasPermission('wms:movement-order:cancel')")
  114 + public CommonResult<Boolean> cancelMovementOrder(@RequestParam("id") Long id) {
  115 + movementOrderService.cancelMovementOrder(id);
  116 + return success(true);
  117 + }
  118 +
  119 + @GetMapping("/get")
  120 + @Operation(summary = "获得移库单")
  121 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  122 + @PreAuthorize("@ss.hasPermission('wms:movement-order:query')")
  123 + public CommonResult<WmsMovementOrderRespVO> getMovementOrder(@RequestParam("id") Long id) {
  124 + WmsMovementOrderDO order = movementOrderService.getMovementOrder(id);
  125 + if (order == null) {
  126 + return success(null);
  127 + }
  128 + // 获得移库单的明细列表
  129 + List<WmsMovementOrderDetailDO> detailList = movementOrderDetailService.getMovementOrderDetailList(id);
  130 + // 拼接结果返回
  131 + WmsMovementOrderRespVO respVO = buildMovementOrderRespVO(order)
  132 + .setDetails(buildMovementOrderDetailRespVOList(detailList));
  133 + return success(respVO);
  134 + }
  135 +
  136 + @GetMapping("/page")
  137 + @Operation(summary = "获得移库单分页")
  138 + @PreAuthorize("@ss.hasPermission('wms:movement-order:query')")
  139 + public CommonResult<PageResult<WmsMovementOrderRespVO>> getMovementOrderPage(
  140 + @Valid WmsMovementOrderPageReqVO pageReqVO) {
  141 + PageResult<WmsMovementOrderDO> pageResult = movementOrderService.getMovementOrderPage(pageReqVO);
  142 + return success(new PageResult<>(buildMovementOrderRespVOList(pageResult.getList()), pageResult.getTotal()));
  143 + }
  144 +
  145 + @GetMapping("/export-excel")
  146 + @Operation(summary = "导出移库单 Excel")
  147 + @PreAuthorize("@ss.hasPermission('wms:movement-order:export')")
  148 + @ApiAccessLog(operateType = EXPORT)
  149 + public void exportMovementOrderExcel(@Valid WmsMovementOrderPageReqVO pageReqVO,
  150 + HttpServletResponse response) throws IOException {
  151 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  152 + List<WmsMovementOrderDO> list = movementOrderService.getMovementOrderPage(pageReqVO).getList();
  153 + ExcelUtils.write(response, "移库单.xls", "数据", WmsMovementOrderRespVO.class,
  154 + buildMovementOrderRespVOList(list));
  155 + }
  156 +
  157 + // ==================== 拼接 VO ====================
  158 +
  159 + private WmsMovementOrderRespVO buildMovementOrderRespVO(WmsMovementOrderDO order) {
  160 + if (order == null) {
  161 + return null;
  162 + }
  163 + List<WmsMovementOrderRespVO> list = buildMovementOrderRespVOList(List.of(order));
  164 + return CollUtil.getFirst(list);
  165 + }
  166 +
  167 + private List<WmsMovementOrderRespVO> buildMovementOrderRespVOList(List<WmsMovementOrderDO> list) {
  168 + if (CollUtil.isEmpty(list)) {
  169 + return Collections.emptyList();
  170 + }
  171 + // 获取相关的仓库、库区、用户等数据
  172 + Map<Long, WmsWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(convertSetByFlatMap(list,
  173 + order -> Stream.of(order.getSourceWarehouseId(), order.getTargetWarehouseId())));
  174 + Map<Long, WmsWarehouseAreaDO> areaMap = wmsProperties.isAreaEnabled()
  175 + ? warehouseAreaService.getWarehouseAreaMap(convertSetByFlatMap(list,
  176 + order -> Stream.of(order.getSourceAreaId(), order.getTargetAreaId())))
  177 + : Collections.emptyMap();
  178 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSetByFlatMap(list,
  179 + order -> Stream.of(parseUserId(order.getCreator()), parseUserId(order.getUpdater()))));
  180 + // 拼接数据
  181 + return BeanUtils.toBean(list, WmsMovementOrderRespVO.class, vo -> {
  182 + MapUtils.findAndThen(warehouseMap, vo.getSourceWarehouseId(),
  183 + warehouse -> vo.setSourceWarehouseName(warehouse.getName()));
  184 + MapUtils.findAndThen(warehouseMap, vo.getTargetWarehouseId(),
  185 + warehouse -> vo.setTargetWarehouseName(warehouse.getName()));
  186 + MapUtils.findAndThen(areaMap, vo.getSourceAreaId(), area -> vo.setSourceAreaName(area.getName()));
  187 + MapUtils.findAndThen(areaMap, vo.getTargetAreaId(), area -> vo.setTargetAreaName(area.getName()));
  188 + MapUtils.findAndThen(userMap, parseUserId(vo.getCreator()), user -> vo.setCreatorName(user.getNickname()));
  189 + MapUtils.findAndThen(userMap, parseUserId(vo.getUpdater()), user -> vo.setUpdaterName(user.getNickname()));
  190 + });
  191 + }
  192 +
  193 + private Long parseUserId(String userId) {
  194 + return NumberUtil.parseLong(userId, null);
  195 + }
  196 +
  197 + private List<WmsMovementOrderDetailRespVO> buildMovementOrderDetailRespVOList(List<WmsMovementOrderDetailDO> list) {
  198 + if (CollUtil.isEmpty(list)) {
  199 + return Collections.emptyList();
  200 + }
  201 + // 获取相关的商品、SKU、仓库、库区等数据
  202 + Map<Long, WmsItemSkuDO> skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsMovementOrderDetailDO::getSkuId));
  203 + Map<Long, WmsItemDO> itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
  204 + Map<Long, WmsWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(convertSetByFlatMap(list,
  205 + detail -> Stream.of(detail.getSourceWarehouseId(), detail.getTargetWarehouseId())));
  206 + Map<Long, WmsWarehouseAreaDO> areaMap = wmsProperties.isAreaEnabled()
  207 + ? warehouseAreaService.getWarehouseAreaMap(convertSetByFlatMap(list,
  208 + detail -> Stream.of(detail.getSourceAreaId(), detail.getTargetAreaId())))
  209 + : Collections.emptyMap();
  210 + // 拼接数据
  211 + return BeanUtils.toBean(list, WmsMovementOrderDetailRespVO.class, vo -> {
  212 + MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
  213 + vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
  214 + MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
  215 + .setItemName(item.getName()).setUnit(item.getUnit()));
  216 + });
  217 + MapUtils.findAndThen(warehouseMap, vo.getSourceWarehouseId(),
  218 + warehouse -> vo.setSourceWarehouseName(warehouse.getName()));
  219 + MapUtils.findAndThen(warehouseMap, vo.getTargetWarehouseId(),
  220 + warehouse -> vo.setTargetWarehouseName(warehouse.getName()));
  221 + MapUtils.findAndThen(areaMap, vo.getSourceAreaId(), area -> vo.setSourceAreaName(area.getName()));
  222 + MapUtils.findAndThen(areaMap, vo.getTargetAreaId(), area -> vo.setTargetAreaName(area.getName()));
  223 + });
  224 + }
  225 +
  226 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/WmsMovementOrderDetailController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.movement;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.detail.WmsMovementOrderDetailRespVO;
  8 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
  9 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
  10 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO;
  11 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
  12 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.movement.WmsMovementOrderDetailDO;
  13 +import cn.iocoder.yudao.module.wms.framework.config.WmsProperties;
  14 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
  15 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
  16 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseAreaService;
  17 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
  18 +import cn.iocoder.yudao.module.wms.service.order.movement.WmsMovementOrderDetailService;
  19 +import io.swagger.v3.oas.annotations.Operation;
  20 +import io.swagger.v3.oas.annotations.Parameter;
  21 +import io.swagger.v3.oas.annotations.tags.Tag;
  22 +import jakarta.annotation.Resource;
  23 +import org.springframework.security.access.prepost.PreAuthorize;
  24 +import org.springframework.validation.annotation.Validated;
  25 +import org.springframework.web.bind.annotation.GetMapping;
  26 +import org.springframework.web.bind.annotation.RequestMapping;
  27 +import org.springframework.web.bind.annotation.RequestParam;
  28 +import org.springframework.web.bind.annotation.RestController;
  29 +
  30 +import java.util.Collections;
  31 +import java.util.List;
  32 +import java.util.Map;
  33 +import java.util.stream.Stream;
  34 +
  35 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  36 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  37 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
  38 +
  39 +@Tag(name = "管理后台 - WMS 移库单明细")
  40 +@RestController
  41 +@RequestMapping("/wms/movement-order-detail")
  42 +@Validated
  43 +public class WmsMovementOrderDetailController {
  44 +
  45 + @Resource
  46 + private WmsMovementOrderDetailService movementOrderDetailService;
  47 + @Resource
  48 + private WmsItemService itemService;
  49 + @Resource
  50 + private WmsItemSkuService itemSkuService;
  51 + @Resource
  52 + private WmsWarehouseService warehouseService;
  53 + @Resource
  54 + private WmsWarehouseAreaService warehouseAreaService;
  55 +
  56 + @Resource
  57 + private WmsProperties wmsProperties;
  58 +
  59 + @GetMapping("/list-by-order-id")
  60 + @Operation(summary = "获得移库单明细列表")
  61 + @Parameter(name = "orderId", description = "移库单编号", required = true, example = "1024")
  62 + @PreAuthorize("@ss.hasPermission('wms:movement-order:query')")
  63 + public CommonResult<List<WmsMovementOrderDetailRespVO>> getMovementOrderDetailListByOrderId(
  64 + @RequestParam("orderId") Long orderId) {
  65 + List<WmsMovementOrderDetailDO> list = movementOrderDetailService.getMovementOrderDetailList(orderId);
  66 + return success(buildMovementOrderDetailRespVOList(list));
  67 + }
  68 +
  69 + // ==================== 拼接 VO ====================
  70 +
  71 + private List<WmsMovementOrderDetailRespVO> buildMovementOrderDetailRespVOList(List<WmsMovementOrderDetailDO> list) {
  72 + if (CollUtil.isEmpty(list)) {
  73 + return Collections.emptyList();
  74 + }
  75 + // 查询关联数据
  76 + Map<Long, WmsItemSkuDO> skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsMovementOrderDetailDO::getSkuId));
  77 + Map<Long, WmsItemDO> itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
  78 + Map<Long, WmsWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(convertSetByFlatMap(list,
  79 + detail -> Stream.of(detail.getSourceWarehouseId(), detail.getTargetWarehouseId())));
  80 + Map<Long, WmsWarehouseAreaDO> areaMap = wmsProperties.isAreaEnabled()
  81 + ? warehouseAreaService.getWarehouseAreaMap(convertSetByFlatMap(list,
  82 + detail -> Stream.of(detail.getSourceAreaId(), detail.getTargetAreaId())))
  83 + : Collections.emptyMap();
  84 + // 拼接数据
  85 + return BeanUtils.toBean(list, WmsMovementOrderDetailRespVO.class, vo -> {
  86 + MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
  87 + vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
  88 + MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
  89 + .setItemName(item.getName()).setUnit(item.getUnit()));
  90 + });
  91 + MapUtils.findAndThen(warehouseMap, vo.getSourceWarehouseId(),
  92 + warehouse -> vo.setSourceWarehouseName(warehouse.getName()));
  93 + MapUtils.findAndThen(warehouseMap, vo.getTargetWarehouseId(),
  94 + warehouse -> vo.setTargetWarehouseName(warehouse.getName()));
  95 + MapUtils.findAndThen(areaMap, vo.getSourceAreaId(), area -> vo.setSourceAreaName(area.getName()));
  96 + MapUtils.findAndThen(areaMap, vo.getTargetAreaId(), area -> vo.setTargetAreaName(area.getName()));
  97 + });
  98 + }
  99 +
  100 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/detail/WmsMovementOrderDetailRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.detail;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.math.BigDecimal;
  7 +import java.time.LocalDateTime;
  8 +
  9 +@Schema(description = "管理后台 - WMS 移库单明细 Response VO")
  10 +@Data
  11 +public class WmsMovementOrderDetailRespVO {
  12 +
  13 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  14 + private Long id;
  15 +
  16 + @Schema(description = "移库单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  17 + private Long orderId;
  18 +
  19 + @Schema(description = "商品编号", example = "2048")
  20 + private Long itemId;
  21 +
  22 + @Schema(description = "商品编号", example = "SPU-APPLE")
  23 + private String itemCode;
  24 +
  25 + @Schema(description = "商品名称", example = "红富士苹果")
  26 + private String itemName;
  27 +
  28 + @Schema(description = "商品单位", example = "箱")
  29 + private String unit;
  30 +
  31 + @Schema(description = "SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
  32 + private Long skuId;
  33 +
  34 + @Schema(description = "规格编号", example = "SKU-APPLE-10KG")
  35 + private String skuCode;
  36 +
  37 + @Schema(description = "规格名称", example = "10kg 箱装")
  38 + private String skuName;
  39 +
  40 + @Schema(description = "来源仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  41 + private Long sourceWarehouseId;
  42 +
  43 + @Schema(description = "来源仓库名称", example = "北京仓")
  44 + private String sourceWarehouseName;
  45 +
  46 + @Schema(description = "来源库区编号", example = "1024")
  47 + private Long sourceAreaId;
  48 +
  49 + @Schema(description = "来源库区名称", example = "北京库区01")
  50 + private String sourceAreaName;
  51 +
  52 + @Schema(description = "目标仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
  53 + private Long targetWarehouseId;
  54 +
  55 + @Schema(description = "目标仓库名称", example = "上海仓")
  56 + private String targetWarehouseName;
  57 +
  58 + @Schema(description = "目标库区编号", example = "2048")
  59 + private Long targetAreaId;
  60 +
  61 + @Schema(description = "目标库区名称", example = "上海库区01")
  62 + private String targetAreaName;
  63 +
  64 + @Schema(description = "库存明细编号", example = "1024")
  65 + private Long inventoryDetailId;
  66 +
  67 + @Schema(description = "批号", example = "B202605110001")
  68 + private String batchNo;
  69 +
  70 + @Schema(description = "生产日期")
  71 + private LocalDateTime productionDate;
  72 +
  73 + @Schema(description = "过期日期")
  74 + private LocalDateTime expirationDate;
  75 +
  76 + @Schema(description = "移库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  77 + private BigDecimal quantity;
  78 +
  79 + @Schema(description = "金额", example = "1000.00")
  80 + private BigDecimal amount;
  81 +
  82 + @Schema(description = "备注", example = "备注")
  83 + private String remark;
  84 +
  85 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  86 + private LocalDateTime createTime;
  87 +
  88 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/detail/WmsMovementOrderDetailSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.detail;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.DecimalMin;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import jakarta.validation.constraints.Size;
  7 +import lombok.Data;
  8 +
  9 +import java.math.BigDecimal;
  10 +import java.time.LocalDateTime;
  11 +
  12 +@Schema(description = "管理后台 - WMS 移库单明细保存 Request VO")
  13 +@Data
  14 +public class WmsMovementOrderDetailSaveReqVO {
  15 +
  16 + @Schema(description = "编号", example = "1024")
  17 + private Long id;
  18 +
  19 + @Schema(description = "SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
  20 + @NotNull(message = "SKU 不能为空")
  21 + private Long skuId;
  22 +
  23 + @Schema(description = "来源库区编号", example = "1024")
  24 + private Long sourceAreaId;
  25 +
  26 + @Schema(description = "目标库区编号", example = "2048")
  27 + private Long targetAreaId;
  28 +
  29 + @Schema(description = "库存明细编号", example = "1024")
  30 + private Long inventoryDetailId;
  31 +
  32 + @Schema(description = "批号", example = "B202605110001")
  33 + @Size(max = 64, message = "批号长度不能超过 64 个字符")
  34 + private String batchNo;
  35 +
  36 + @Schema(description = "生产日期")
  37 + private LocalDateTime productionDate;
  38 +
  39 + @Schema(description = "过期日期")
  40 + private LocalDateTime expirationDate;
  41 +
  42 + @Schema(description = "移库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  43 + @NotNull(message = "移库数量不能为空")
  44 + @DecimalMin(value = "0", inclusive = false, message = "移库数量必须大于 0")
  45 + private BigDecimal quantity;
  46 +
  47 + @Schema(description = "金额", example = "1000.00")
  48 + @DecimalMin(value = "0", message = "金额不能小于 0")
  49 + private BigDecimal amount;
  50 +
  51 + @Schema(description = "备注", example = "备注")
  52 + @Size(max = 255, message = "备注长度不能超过 255 个字符")
  53 + private String remark;
  54 +
  55 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import cn.iocoder.yudao.module.wms.enums.order.WmsOrderStatusEnum;
  6 +import io.swagger.v3.oas.annotations.media.Schema;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import lombok.ToString;
  10 +import org.springframework.format.annotation.DateTimeFormat;
  11 +
  12 +import java.math.BigDecimal;
  13 +import java.time.LocalDateTime;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  16 +
  17 +@Schema(description = "管理后台 - WMS 移库单分页 Request VO")
  18 +@Data
  19 +@EqualsAndHashCode(callSuper = true)
  20 +@ToString(callSuper = true)
  21 +public class WmsMovementOrderPageReqVO extends PageParam {
  22 +
  23 + @Schema(description = "移库单号", example = "YK202605110001")
  24 + private String no;
  25 +
  26 + @Schema(description = "单据状态", example = "0")
  27 + @InEnum(WmsOrderStatusEnum.class)
  28 + private Integer status;
  29 +
  30 + @Schema(description = "来源仓库编号", example = "1024")
  31 + private Long sourceWarehouseId;
  32 +
  33 + @Schema(description = "目标仓库编号", example = "2048")
  34 + private Long targetWarehouseId;
  35 +
  36 + @Schema(description = "单据日期")
  37 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  38 + private LocalDateTime[] orderDate;
  39 +
  40 + @Schema(description = "最小数量", example = "1.00")
  41 + private BigDecimal totalQuantityMin;
  42 +
  43 + @Schema(description = "最大数量", example = "100.00")
  44 + private BigDecimal totalQuantityMax;
  45 +
  46 + @Schema(description = "最小总金额", example = "1.00")
  47 + private BigDecimal totalAmountMin;
  48 +
  49 + @Schema(description = "最大总金额", example = "1000.00")
  50 + private BigDecimal totalAmountMax;
  51 +
  52 + @Schema(description = "创建用户", example = "1")
  53 + private String creator;
  54 +
  55 + @Schema(description = "更新用户", example = "1")
  56 + private String updater;
  57 +
  58 + @Schema(description = "创建时间")
  59 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  60 + private LocalDateTime[] createTime;
  61 +
  62 + @Schema(description = "更新时间")
  63 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  64 + private LocalDateTime[] updateTime;
  65 +
  66 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order;
  2 +
  3 +import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
  4 +import cn.idev.excel.annotation.ExcelProperty;
  5 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  6 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  7 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.detail.WmsMovementOrderDetailRespVO;
  8 +import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
  9 +import io.swagger.v3.oas.annotations.media.Schema;
  10 +import lombok.Data;
  11 +
  12 +import java.math.BigDecimal;
  13 +import java.time.LocalDateTime;
  14 +import java.util.List;
  15 +
  16 +@Schema(description = "管理后台 - WMS 移库单 Response VO")
  17 +@Data
  18 +@ExcelIgnoreUnannotated
  19 +public class WmsMovementOrderRespVO {
  20 +
  21 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  22 + private Long id;
  23 +
  24 + @Schema(description = "移库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "YK202605110001")
  25 + @ExcelProperty("移库单号")
  26 + private String no;
  27 +
  28 + @Schema(description = "移库状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  29 + @ExcelProperty(value = "移库状态", converter = DictConvert.class)
  30 + @DictFormat(DictTypeConstants.ORDER_STATUS)
  31 + private Integer status;
  32 +
  33 + @Schema(description = "备注", example = "备注")
  34 + private String remark;
  35 +
  36 + @Schema(description = "来源仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  37 + private Long sourceWarehouseId;
  38 +
  39 + @Schema(description = "来源仓库名称", example = "北京仓")
  40 + @ExcelProperty("来源仓库")
  41 + private String sourceWarehouseName;
  42 +
  43 + @Schema(description = "来源库区编号", example = "1024")
  44 + private Long sourceAreaId;
  45 +
  46 + @Schema(description = "来源库区名称", example = "北京库区01")
  47 + private String sourceAreaName;
  48 +
  49 + @Schema(description = "目标仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
  50 + private Long targetWarehouseId;
  51 +
  52 + @Schema(description = "目标仓库名称", example = "上海仓")
  53 + @ExcelProperty("目标仓库")
  54 + private String targetWarehouseName;
  55 +
  56 + @Schema(description = "目标库区编号", example = "2048")
  57 + private Long targetAreaId;
  58 +
  59 + @Schema(description = "目标库区名称", example = "上海库区01")
  60 + private String targetAreaName;
  61 +
  62 + @Schema(description = "移库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  63 + @ExcelProperty("移库数量")
  64 + private BigDecimal totalQuantity;
  65 +
  66 + @Schema(description = "总金额", example = "1000.00")
  67 + @ExcelProperty("总金额")
  68 + private BigDecimal totalAmount;
  69 +
  70 + @Schema(description = "移库明细")
  71 + private List<WmsMovementOrderDetailRespVO> details;
  72 +
  73 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  74 + @ExcelProperty("创建时间")
  75 + private LocalDateTime createTime;
  76 +
  77 + @Schema(description = "创建者", example = "1")
  78 + private String creator;
  79 + @Schema(description = "创建者名称", example = "芋道")
  80 + private String creatorName;
  81 +
  82 + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
  83 + private LocalDateTime updateTime;
  84 +
  85 + @Schema(description = "更新者", example = "1")
  86 + private String updater;
  87 + @Schema(description = "更新者名称", example = "芋道")
  88 + private String updaterName;
  89 +
  90 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order;
  2 +
  3 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.detail.WmsMovementOrderDetailSaveReqVO;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import jakarta.validation.Valid;
  6 +import jakarta.validation.constraints.NotBlank;
  7 +import jakarta.validation.constraints.NotNull;
  8 +import jakarta.validation.constraints.Size;
  9 +import lombok.Data;
  10 +
  11 +import java.math.BigDecimal;
  12 +import java.util.List;
  13 +
  14 +@Schema(description = "管理后台 - WMS 移库单保存 Request VO")
  15 +@Data
  16 +public class WmsMovementOrderSaveReqVO {
  17 +
  18 + @Schema(description = "编号", example = "1024")
  19 + private Long id;
  20 +
  21 + @Schema(description = "移库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "YK202605110001")
  22 + @NotBlank(message = "移库单号不能为空")
  23 + @Size(max = 64, message = "移库单号长度不能超过 64 个字符")
  24 + private String no;
  25 +
  26 + @Schema(description = "备注", example = "备注")
  27 + @Size(max = 255, message = "备注长度不能超过 255 个字符")
  28 + private String remark;
  29 +
  30 + @Schema(description = "来源仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  31 + @NotNull(message = "来源仓库不能为空")
  32 + private Long sourceWarehouseId;
  33 +
  34 + @Schema(description = "来源库区编号", example = "1024")
  35 + private Long sourceAreaId;
  36 +
  37 + @Schema(description = "目标仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
  38 + @NotNull(message = "目标仓库不能为空")
  39 + private Long targetWarehouseId;
  40 +
  41 + @Schema(description = "目标库区编号", example = "2048")
  42 + private Long targetAreaId;
  43 +
  44 + @Schema(description = "移库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  45 + @NotNull(message = "移库数量不能为空")
  46 + private BigDecimal totalQuantity;
  47 +
  48 + @Schema(description = "总金额", example = "1000.00")
  49 + private BigDecimal totalAmount;
  50 +
  51 + @Schema(description = "移库明细")
  52 + @Valid
  53 + private List<WmsMovementOrderDetailSaveReqVO> details;
  54 +
  55 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/check/WmsCheckOrderDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.dataobject.order.check;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO;
  5 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
  6 +import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
  7 +import com.baomidou.mybatisplus.annotation.KeySequence;
  8 +import com.baomidou.mybatisplus.annotation.TableId;
  9 +import com.baomidou.mybatisplus.annotation.TableName;
  10 +import lombok.*;
  11 +
  12 +import java.math.BigDecimal;
  13 +
  14 +/**
  15 + * WMS 盘库单 DO
  16 + *
  17 + * @author 芋道源码
  18 + */
  19 +@TableName("wms_check_order")
  20 +@KeySequence("wms_check_order_seq")
  21 +@Data
  22 +@EqualsAndHashCode(callSuper = true)
  23 +@ToString(callSuper = true)
  24 +@Builder
  25 +@NoArgsConstructor
  26 +@AllArgsConstructor
  27 +public class WmsCheckOrderDO extends BaseDO {
  28 +
  29 + /**
  30 + * 主键编号
  31 + */
  32 + @TableId
  33 + private Long id;
  34 + /**
  35 + * 盘库单号
  36 + */
  37 + private String no;
  38 + /**
  39 + * 盘库状态
  40 + *
  41 + * 字典 {@link DictTypeConstants#ORDER_STATUS}
  42 + */
  43 + private Integer status;
  44 + /**
  45 + * 备注
  46 + */
  47 + private String remark;
  48 +
  49 + // ========= 仓库库区字段 =========
  50 +
  51 + /**
  52 + * 仓库编号
  53 + *
  54 + * 关联 {@link WmsWarehouseDO#getId()}
  55 + */
  56 + private Long warehouseId;
  57 + /**
  58 + * 库区编号
  59 + *
  60 + * 关联 {@link WmsWarehouseAreaDO#getId()}
  61 + */
  62 + private Long areaId;
  63 +
  64 + // ========= 汇总金额字段 =========
  65 +
  66 + /**
  67 + * 盈亏数量
  68 + */
  69 + private BigDecimal totalQuantity;
  70 + /**
  71 + * 总金额
  72 + */
  73 + private BigDecimal totalAmount;
  74 +
  75 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/check/WmsCheckOrderDetailDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.dataobject.order.check;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
  5 +import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDetailDO;
  6 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
  7 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO;
  8 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
  9 +import com.baomidou.mybatisplus.annotation.KeySequence;
  10 +import com.baomidou.mybatisplus.annotation.TableId;
  11 +import com.baomidou.mybatisplus.annotation.TableName;
  12 +import lombok.*;
  13 +
  14 +import java.math.BigDecimal;
  15 +import java.time.LocalDateTime;
  16 +
  17 +/**
  18 + * WMS 盘库单明细 DO
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +@TableName("wms_check_order_detail")
  23 +@KeySequence("wms_check_order_detail_seq")
  24 +@Data
  25 +@EqualsAndHashCode(callSuper = true)
  26 +@ToString(callSuper = true)
  27 +@Builder
  28 +@NoArgsConstructor
  29 +@AllArgsConstructor
  30 +public class WmsCheckOrderDetailDO extends BaseDO {
  31 +
  32 + /**
  33 + * 主键编号
  34 + */
  35 + @TableId
  36 + private Long id;
  37 + /**
  38 + * 备注
  39 + */
  40 + private String remark;
  41 +
  42 + // ========= 单据商品字段 =========
  43 +
  44 + /**
  45 + * 盘库单编号
  46 + *
  47 + * 关联 {@link WmsCheckOrderDO#getId()}
  48 + */
  49 + private Long orderId;
  50 + /**
  51 + * 商品 SKU 编号
  52 + *
  53 + * 关联 {@link WmsItemSkuDO#getId()}
  54 + */
  55 + private Long skuId;
  56 +
  57 + // ========= 仓库库区字段 =========
  58 +
  59 + /**
  60 + * 仓库编号
  61 + *
  62 + * 关联 {@link WmsWarehouseDO#getId()}
  63 + */
  64 + private Long warehouseId;
  65 + /**
  66 + * 库区编号
  67 + *
  68 + * 关联 {@link WmsWarehouseAreaDO#getId()}
  69 + */
  70 + private Long areaId;
  71 + /**
  72 + * 库存编号
  73 + *
  74 + * 关联 {@link WmsInventoryDO#getId()}
  75 + */
  76 + private Long inventoryId;
  77 + /**
  78 + * 库存明细编号
  79 + *
  80 + * 关联 {@link WmsInventoryDetailDO#getId()}
  81 + */
  82 + private Long inventoryDetailId;
  83 +
  84 + // ========= 批次效期字段 =========
  85 +
  86 + /**
  87 + * 批号
  88 + */
  89 + private String batchNo;
  90 + /**
  91 + * 生产日期
  92 + */
  93 + private LocalDateTime productionDate;
  94 + /**
  95 + * 过期日期
  96 + */
  97 + private LocalDateTime expirationDate;
  98 + /**
  99 + * 入库时间
  100 + */
  101 + private LocalDateTime receiptTime;
  102 +
  103 + // ========= 汇总金额字段 =========
  104 +
  105 + /**
  106 + * 账面数量
  107 + */
  108 + private BigDecimal quantity;
  109 + /**
  110 + * 实盘数量
  111 + */
  112 + private BigDecimal checkQuantity;
  113 + /**
  114 + * 金额(小计、非单价)
  115 + */
  116 + private BigDecimal amount;
  117 +
  118 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/movement/WmsMovementOrderDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.dataobject.order.movement;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO;
  5 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
  6 +import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
  7 +import com.baomidou.mybatisplus.annotation.KeySequence;
  8 +import com.baomidou.mybatisplus.annotation.TableId;
  9 +import com.baomidou.mybatisplus.annotation.TableName;
  10 +import lombok.*;
  11 +
  12 +import java.math.BigDecimal;
  13 +
  14 +/**
  15 + * WMS 移库单 DO
  16 + *
  17 + * @author 芋道源码
  18 + */
  19 +@TableName("wms_movement_order")
  20 +@KeySequence("wms_movement_order_seq")
  21 +@Data
  22 +@EqualsAndHashCode(callSuper = true)
  23 +@ToString(callSuper = true)
  24 +@Builder
  25 +@NoArgsConstructor
  26 +@AllArgsConstructor
  27 +public class WmsMovementOrderDO extends BaseDO {
  28 +
  29 + /**
  30 + * 主键编号
  31 + */
  32 + @TableId
  33 + private Long id;
  34 + /**
  35 + * 移库单号
  36 + */
  37 + private String no;
  38 + /**
  39 + * 移库状态
  40 + *
  41 + * 字典 {@link DictTypeConstants#ORDER_STATUS}
  42 + */
  43 + private Integer status;
  44 + /**
  45 + * 备注
  46 + */
  47 + private String remark;
  48 +
  49 + // ========= 来源仓库库区字段 =========
  50 +
  51 + /**
  52 + * 来源仓库编号
  53 + *
  54 + * 关联 {@link WmsWarehouseDO#getId()}
  55 + */
  56 + private Long sourceWarehouseId;
  57 + /**
  58 + * 来源库区编号
  59 + *
  60 + * 关联 {@link WmsWarehouseAreaDO#getId()}
  61 + */
  62 + private Long sourceAreaId;
  63 +
  64 + // ========= 目标仓库库区字段 =========
  65 +
  66 + /**
  67 + * 目标仓库编号
  68 + *
  69 + * 关联 {@link WmsWarehouseDO#getId()}
  70 + */
  71 + private Long targetWarehouseId;
  72 + /**
  73 + * 目标库区编号
  74 + *
  75 + * 关联 {@link WmsWarehouseAreaDO#getId()}
  76 + */
  77 + private Long targetAreaId;
  78 +
  79 + // ========= 汇总金额字段 =========
  80 +
  81 + /**
  82 + * 总数量
  83 + */
  84 + private BigDecimal totalQuantity;
  85 + /**
  86 + * 总金额
  87 + */
  88 + private BigDecimal totalAmount;
  89 +
  90 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/movement/WmsMovementOrderDetailDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.dataobject.order.movement;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDetailDO;
  5 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
  6 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO;
  7 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
  8 +import com.baomidou.mybatisplus.annotation.KeySequence;
  9 +import com.baomidou.mybatisplus.annotation.TableId;
  10 +import com.baomidou.mybatisplus.annotation.TableName;
  11 +import lombok.*;
  12 +
  13 +import java.math.BigDecimal;
  14 +import java.time.LocalDateTime;
  15 +
  16 +/**
  17 + * WMS 移库单明细 DO
  18 + *
  19 + * @author 芋道源码
  20 + */
  21 +@TableName("wms_movement_order_detail")
  22 +@KeySequence("wms_movement_order_detail_seq")
  23 +@Data
  24 +@EqualsAndHashCode(callSuper = true)
  25 +@ToString(callSuper = true)
  26 +@Builder
  27 +@NoArgsConstructor
  28 +@AllArgsConstructor
  29 +public class WmsMovementOrderDetailDO extends BaseDO {
  30 +
  31 + /**
  32 + * 主键编号
  33 + */
  34 + @TableId
  35 + private Long id;
  36 + /**
  37 + * 备注
  38 + */
  39 + private String remark;
  40 +
  41 + // ========= 单据商品字段 =========
  42 +
  43 + /**
  44 + * 移库单编号
  45 + *
  46 + * 关联 {@link WmsMovementOrderDO#getId()}
  47 + */
  48 + private Long orderId;
  49 + /**
  50 + * 商品 SKU 编号
  51 + *
  52 + * 关联 {@link WmsItemSkuDO#getId()}
  53 + */
  54 + private Long skuId;
  55 +
  56 + // ========= 来源仓库库区字段 =========
  57 +
  58 + /**
  59 + * 来源仓库编号
  60 + *
  61 + * 关联 {@link WmsWarehouseDO#getId()}
  62 + */
  63 + private Long sourceWarehouseId;
  64 + /**
  65 + * 来源库区编号
  66 + *
  67 + * 关联 {@link WmsWarehouseAreaDO#getId()}
  68 + */
  69 + private Long sourceAreaId;
  70 + /**
  71 + * 库存明细编号
  72 + *
  73 + * 关联 {@link WmsInventoryDetailDO#getId()}
  74 + */
  75 + private Long inventoryDetailId;
  76 +
  77 + // ========= 目标仓库库区字段 =========
  78 +
  79 + /**
  80 + * 目标仓库编号
  81 + *
  82 + * 关联 {@link WmsWarehouseDO#getId()}
  83 + */
  84 + private Long targetWarehouseId;
  85 + /**
  86 + * 目标库区编号
  87 + *
  88 + * 关联 {@link WmsWarehouseAreaDO#getId()}
  89 + */
  90 + private Long targetAreaId;
  91 +
  92 + // ========= 批次效期字段 =========
  93 +
  94 + /**
  95 + * 批号
  96 + */
  97 + private String batchNo;
  98 + /**
  99 + * 生产日期
  100 + */
  101 + private LocalDateTime productionDate;
  102 + /**
  103 + * 过期日期
  104 + */
  105 + private LocalDateTime expirationDate;
  106 +
  107 + // ========= 汇总金额字段 =========
  108 +
  109 + /**
  110 + * 移库数量
  111 + */
  112 + private BigDecimal quantity;
  113 + /**
  114 + * 金额(小计、非单价)
  115 + */
  116 + private BigDecimal amount;
  117 +
  118 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/check/WmsCheckOrderDetailMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.mysql.order.check;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  5 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.check.WmsCheckOrderDetailDO;
  6 +import org.apache.ibatis.annotations.Mapper;
  7 +
  8 +import java.util.Collection;
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * WMS 盘库单明细 Mapper
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Mapper
  17 +public interface WmsCheckOrderDetailMapper extends BaseMapperX<WmsCheckOrderDetailDO> {
  18 +
  19 + default List<WmsCheckOrderDetailDO> selectListByOrderId(Long orderId) {
  20 + return selectList(WmsCheckOrderDetailDO::getOrderId, orderId);
  21 + }
  22 +
  23 + default List<WmsCheckOrderDetailDO> selectListByOrderIds(Collection<Long> orderIds) {
  24 + return selectList(new LambdaQueryWrapperX<WmsCheckOrderDetailDO>()
  25 + .inIfPresent(WmsCheckOrderDetailDO::getOrderId, orderIds)
  26 + .orderByAsc(WmsCheckOrderDetailDO::getOrderId)
  27 + .orderByAsc(WmsCheckOrderDetailDO::getId));
  28 + }
  29 +
  30 + default void deleteByOrderId(Long orderId) {
  31 + delete(WmsCheckOrderDetailDO::getOrderId, orderId);
  32 + }
  33 +
  34 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/check/WmsCheckOrderMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.mysql.order.check;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order.WmsCheckOrderPageReqVO;
  7 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.check.WmsCheckOrderDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +/**
  11 + * WMS 盘库单 Mapper
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Mapper
  16 +public interface WmsCheckOrderMapper extends BaseMapperX<WmsCheckOrderDO> {
  17 +
  18 + default PageResult<WmsCheckOrderDO> selectPage(WmsCheckOrderPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<WmsCheckOrderDO>()
  20 + .likeIfPresent(WmsCheckOrderDO::getNo, reqVO.getNo())
  21 + .eqIfPresent(WmsCheckOrderDO::getStatus, reqVO.getStatus())
  22 + .eqIfPresent(WmsCheckOrderDO::getWarehouseId, reqVO.getWarehouseId())
  23 + .eqIfPresent(WmsCheckOrderDO::getAreaId, reqVO.getAreaId())
  24 + .betweenIfPresent(WmsCheckOrderDO::getCreateTime, reqVO.getOrderDate())
  25 + .geIfPresent(WmsCheckOrderDO::getTotalQuantity, reqVO.getTotalQuantityMin())
  26 + .leIfPresent(WmsCheckOrderDO::getTotalQuantity, reqVO.getTotalQuantityMax())
  27 + .geIfPresent(WmsCheckOrderDO::getTotalAmount, reqVO.getTotalAmountMin())
  28 + .leIfPresent(WmsCheckOrderDO::getTotalAmount, reqVO.getTotalAmountMax())
  29 + .eqIfPresent(WmsCheckOrderDO::getCreator, reqVO.getCreator())
  30 + .eqIfPresent(WmsCheckOrderDO::getUpdater, reqVO.getUpdater())
  31 + .betweenIfPresent(WmsCheckOrderDO::getCreateTime, reqVO.getCreateTime())
  32 + .betweenIfPresent(WmsCheckOrderDO::getUpdateTime, reqVO.getUpdateTime())
  33 + .orderByDesc(WmsCheckOrderDO::getId));
  34 + }
  35 +
  36 + default WmsCheckOrderDO selectByNo(String no) {
  37 + return selectOne(WmsCheckOrderDO::getNo, no);
  38 + }
  39 +
  40 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/movement/WmsMovementOrderDetailMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.mysql.order.movement;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  5 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.movement.WmsMovementOrderDetailDO;
  6 +import org.apache.ibatis.annotations.Mapper;
  7 +
  8 +import java.util.Collection;
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * WMS 移库单明细 Mapper
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Mapper
  17 +public interface WmsMovementOrderDetailMapper extends BaseMapperX<WmsMovementOrderDetailDO> {
  18 +
  19 + default List<WmsMovementOrderDetailDO> selectListByOrderId(Long orderId) {
  20 + return selectList(WmsMovementOrderDetailDO::getOrderId, orderId);
  21 + }
  22 +
  23 + default List<WmsMovementOrderDetailDO> selectListByOrderIds(Collection<Long> orderIds) {
  24 + return selectList(new LambdaQueryWrapperX<WmsMovementOrderDetailDO>()
  25 + .inIfPresent(WmsMovementOrderDetailDO::getOrderId, orderIds)
  26 + .orderByAsc(WmsMovementOrderDetailDO::getOrderId)
  27 + .orderByAsc(WmsMovementOrderDetailDO::getId));
  28 + }
  29 +
  30 + default void deleteByOrderId(Long orderId) {
  31 + delete(WmsMovementOrderDetailDO::getOrderId, orderId);
  32 + }
  33 +
  34 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/movement/WmsMovementOrderMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.mysql.order.movement;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order.WmsMovementOrderPageReqVO;
  7 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.movement.WmsMovementOrderDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +/**
  11 + * WMS 移库单 Mapper
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Mapper
  16 +public interface WmsMovementOrderMapper extends BaseMapperX<WmsMovementOrderDO> {
  17 +
  18 + default PageResult<WmsMovementOrderDO> selectPage(WmsMovementOrderPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<WmsMovementOrderDO>()
  20 + .likeIfPresent(WmsMovementOrderDO::getNo, reqVO.getNo())
  21 + .eqIfPresent(WmsMovementOrderDO::getStatus, reqVO.getStatus())
  22 + .eqIfPresent(WmsMovementOrderDO::getSourceWarehouseId, reqVO.getSourceWarehouseId())
  23 + .eqIfPresent(WmsMovementOrderDO::getTargetWarehouseId, reqVO.getTargetWarehouseId())
  24 + .betweenIfPresent(WmsMovementOrderDO::getCreateTime, reqVO.getOrderDate())
  25 + .geIfPresent(WmsMovementOrderDO::getTotalQuantity, reqVO.getTotalQuantityMin())
  26 + .leIfPresent(WmsMovementOrderDO::getTotalQuantity, reqVO.getTotalQuantityMax())
  27 + .geIfPresent(WmsMovementOrderDO::getTotalAmount, reqVO.getTotalAmountMin())
  28 + .leIfPresent(WmsMovementOrderDO::getTotalAmount, reqVO.getTotalAmountMax())
  29 + .eqIfPresent(WmsMovementOrderDO::getCreator, reqVO.getCreator())
  30 + .eqIfPresent(WmsMovementOrderDO::getUpdater, reqVO.getUpdater())
  31 + .betweenIfPresent(WmsMovementOrderDO::getCreateTime, reqVO.getCreateTime())
  32 + .betweenIfPresent(WmsMovementOrderDO::getUpdateTime, reqVO.getUpdateTime())
  33 + .orderByDesc(WmsMovementOrderDO::getId));
  34 + }
  35 +
  36 + default WmsMovementOrderDO selectByNo(String no) {
  37 + return selectOne(WmsMovementOrderDO::getNo, no);
  38 + }
  39 +
  40 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/check/WmsCheckOrderDetailService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.check;
  2 +
  3 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order.WmsCheckOrderSaveReqVO;
  4 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.check.WmsCheckOrderDetailDO;
  5 +
  6 +import java.util.Collection;
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * WMS 盘库单明细 Service 接口
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +public interface WmsCheckOrderDetailService {
  15 +
  16 + /**
  17 + * 创建盘库单明细列表
  18 + *
  19 + * @param orderId 盘库单编号
  20 + * @param reqVO 盘库单保存信息
  21 + */
  22 + void createCheckOrderDetailList(Long orderId, WmsCheckOrderSaveReqVO reqVO);
  23 +
  24 + /**
  25 + * 更新盘库单明细列表
  26 + *
  27 + * @param orderId 盘库单编号
  28 + * @param reqVO 盘库单保存信息
  29 + */
  30 + void updateCheckOrderDetailList(Long orderId, WmsCheckOrderSaveReqVO reqVO);
  31 +
  32 + /**
  33 + * 按盘库单编号删除明细列表
  34 + *
  35 + * @param orderId 盘库单编号
  36 + */
  37 + void deleteCheckOrderDetailListByOrderId(Long orderId);
  38 +
  39 + /**
  40 + * 按盘库单编号获得明细列表
  41 + *
  42 + * @param orderId 盘库单编号
  43 + * @return 明细列表
  44 + */
  45 + List<WmsCheckOrderDetailDO> getCheckOrderDetailList(Long orderId);
  46 +
  47 + /**
  48 + * 按盘库单编号集合获得明细列表
  49 + *
  50 + * @param orderIds 盘库单编号集合
  51 + * @return 明细列表
  52 + */
  53 + List<WmsCheckOrderDetailDO> getCheckOrderDetailList(Collection<Long> orderIds);
  54 +
  55 + /**
  56 + * 校验盘库单明细列表存在
  57 + *
  58 + * @param orderId 盘库单编号
  59 + * @return 明细列表
  60 + */
  61 + List<WmsCheckOrderDetailDO> validateCheckOrderDetailListExists(Long orderId);
  62 +
  63 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/check/WmsCheckOrderDetailServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.check;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.collection.ListUtil;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  7 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order.WmsCheckOrderSaveReqVO;
  8 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO;
  9 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.check.WmsCheckOrderDetailDO;
  10 +import cn.iocoder.yudao.module.wms.dal.mysql.order.check.WmsCheckOrderDetailMapper;
  11 +import cn.iocoder.yudao.module.wms.framework.config.WmsProperties;
  12 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
  13 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseAreaService;
  14 +import jakarta.annotation.Resource;
  15 +import org.springframework.stereotype.Service;
  16 +import org.springframework.transaction.annotation.Transactional;
  17 +import org.springframework.validation.annotation.Validated;
  18 +
  19 +import java.util.Collection;
  20 +import java.util.List;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  23 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  24 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
  25 +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;
  26 +
  27 +/**
  28 + * WMS 盘库单明细 Service 实现类
  29 + *
  30 + * @author 芋道源码
  31 + */
  32 +@Service
  33 +@Validated
  34 +public class WmsCheckOrderDetailServiceImpl implements WmsCheckOrderDetailService {
  35 +
  36 + @Resource
  37 + private WmsCheckOrderDetailMapper checkOrderDetailMapper;
  38 + @Resource
  39 + private WmsItemSkuService itemSkuService;
  40 + @Resource
  41 + private WmsWarehouseAreaService warehouseAreaService;
  42 + @Resource
  43 + private WmsProperties wmsProperties;
  44 +
  45 + @Override
  46 + @Transactional(rollbackFor = Exception.class)
  47 + public void createCheckOrderDetailList(Long orderId, WmsCheckOrderSaveReqVO reqVO) {
  48 + List<WmsCheckOrderDetailDO> list = buildCheckOrderDetailList(reqVO);
  49 + if (CollUtil.isEmpty(list)) {
  50 + return;
  51 + }
  52 + list.forEach(detail -> detail.setId(null).setOrderId(orderId));
  53 + checkOrderDetailMapper.insertBatch(list);
  54 + }
  55 +
  56 + @Override
  57 + @Transactional(rollbackFor = Exception.class)
  58 + public void updateCheckOrderDetailList(Long orderId, WmsCheckOrderSaveReqVO reqVO) {
  59 + // 第一步,对比新老数据,获得添加、修改、删除的列表
  60 + List<WmsCheckOrderDetailDO> oldList = checkOrderDetailMapper.selectListByOrderId(orderId);
  61 + List<WmsCheckOrderDetailDO> list = buildCheckOrderDetailList(reqVO);
  62 + List<WmsCheckOrderDetailDO> newList = CollUtil.isEmpty(list) ? ListUtil.of() : list;
  63 + List<List<WmsCheckOrderDetailDO>> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录
  64 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId()));
  65 +
  66 + // 第二步,批量添加、修改、删除
  67 + if (CollUtil.isNotEmpty(diffList.get(0))) {
  68 + if (CollUtil.isNotEmpty(convertList(diffList.get(0), WmsCheckOrderDetailDO::getId))) {
  69 + throw exception(CHECK_ORDER_DETAIL_NOT_EXISTS);
  70 + }
  71 + diffList.get(0).forEach(detail -> detail.setOrderId(orderId));
  72 + checkOrderDetailMapper.insertBatch(diffList.get(0));
  73 + }
  74 + if (CollUtil.isNotEmpty(diffList.get(1))) {
  75 + diffList.get(1).forEach(detail -> detail.setOrderId(orderId));
  76 + checkOrderDetailMapper.updateBatch(diffList.get(1));
  77 + }
  78 + if (CollUtil.isNotEmpty(diffList.get(2))) {
  79 + checkOrderDetailMapper.deleteByIds(convertList(diffList.get(2), WmsCheckOrderDetailDO::getId));
  80 + }
  81 + }
  82 +
  83 + @Override
  84 + public void deleteCheckOrderDetailListByOrderId(Long orderId) {
  85 + checkOrderDetailMapper.deleteByOrderId(orderId);
  86 + }
  87 +
  88 + @Override
  89 + public List<WmsCheckOrderDetailDO> getCheckOrderDetailList(Long orderId) {
  90 + return checkOrderDetailMapper.selectListByOrderId(orderId);
  91 + }
  92 +
  93 + @Override
  94 + public List<WmsCheckOrderDetailDO> getCheckOrderDetailList(Collection<Long> orderIds) {
  95 + if (CollUtil.isEmpty(orderIds)) {
  96 + return ListUtil.of();
  97 + }
  98 + return checkOrderDetailMapper.selectListByOrderIds(orderIds);
  99 + }
  100 +
  101 + @Override
  102 + public List<WmsCheckOrderDetailDO> validateCheckOrderDetailListExists(Long orderId) {
  103 + List<WmsCheckOrderDetailDO> details = checkOrderDetailMapper.selectListByOrderId(orderId);
  104 + if (CollUtil.isEmpty(details)) {
  105 + throw exception(CHECK_ORDER_DETAIL_REQUIRED);
  106 + }
  107 + if (wmsProperties.isAreaEnabled() && details.stream()
  108 + .anyMatch(detail -> ObjectUtils.equalsAny(detail.getAreaId(), null, WmsWarehouseAreaDO.ID_EMPTY))) {
  109 + throw exception(CHECK_ORDER_AREA_REQUIRED);
  110 + }
  111 + return details;
  112 + }
  113 +
  114 + private List<WmsCheckOrderDetailDO> buildCheckOrderDetailList(WmsCheckOrderSaveReqVO reqVO) {
  115 + if (CollUtil.isEmpty(reqVO.getDetails())) {
  116 + return ListUtil.of();
  117 + }
  118 + return convertList(reqVO.getDetails(), detail -> {
  119 + // 校验 SKU 存在
  120 + itemSkuService.validateItemSkuExists(detail.getSkuId());
  121 + // 校验库区存在,并且属于当前仓库
  122 + Long areaId = warehouseAreaService.validateAndNormalizeWarehouseAreaId(
  123 + detail.getAreaId() == null ? reqVO.getAreaId() : detail.getAreaId(), reqVO.getWarehouseId());
  124 + // 构建对象
  125 + return BeanUtils.toBean(detail, WmsCheckOrderDetailDO.class)
  126 + .setWarehouseId(reqVO.getWarehouseId()).setAreaId(areaId);
  127 + });
  128 + }
  129 +
  130 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/check/WmsCheckOrderService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.check;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order.WmsCheckOrderPageReqVO;
  5 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order.WmsCheckOrderSaveReqVO;
  6 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.check.WmsCheckOrderDO;
  7 +import jakarta.validation.Valid;
  8 +
  9 +/**
  10 + * WMS 盘库单 Service 接口
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +public interface WmsCheckOrderService {
  15 +
  16 + /**
  17 + * 创建盘库单
  18 + *
  19 + * @param createReqVO 创建信息
  20 + * @return 编号
  21 + */
  22 + Long createCheckOrder(@Valid WmsCheckOrderSaveReqVO createReqVO);
  23 +
  24 + /**
  25 + * 更新盘库单
  26 + *
  27 + * @param updateReqVO 更新信息
  28 + */
  29 + void updateCheckOrder(@Valid WmsCheckOrderSaveReqVO updateReqVO);
  30 +
  31 + /**
  32 + * 删除盘库单
  33 + *
  34 + * @param id 编号
  35 + */
  36 + void deleteCheckOrder(Long id);
  37 +
  38 + /**
  39 + * 完成盘库
  40 + *
  41 + * @param id 编号
  42 + */
  43 + void completeCheckOrder(Long id);
  44 +
  45 + /**
  46 + * 作废盘库单
  47 + *
  48 + * @param id 编号
  49 + */
  50 + void cancelCheckOrder(Long id);
  51 +
  52 + /**
  53 + * 获得盘库单
  54 + *
  55 + * @param id 编号
  56 + * @return 盘库单
  57 + */
  58 + WmsCheckOrderDO getCheckOrder(Long id);
  59 +
  60 + /**
  61 + * 获得盘库单分页
  62 + *
  63 + * @param pageReqVO 分页查询
  64 + * @return 盘库单分页
  65 + */
  66 + PageResult<WmsCheckOrderDO> getCheckOrderPage(WmsCheckOrderPageReqVO pageReqVO);
  67 +
  68 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/check/WmsCheckOrderServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.check;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order.WmsCheckOrderPageReqVO;
  7 +import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order.WmsCheckOrderSaveReqVO;
  8 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.check.WmsCheckOrderDO;
  9 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.check.WmsCheckOrderDetailDO;
  10 +import cn.iocoder.yudao.module.wms.dal.mysql.order.check.WmsCheckOrderMapper;
  11 +import cn.iocoder.yudao.module.wms.enums.inventory.WmsInventoryOrderTypeEnum;
  12 +import cn.iocoder.yudao.module.wms.enums.order.WmsOrderStatusEnum;
  13 +import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryService;
  14 +import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO;
  15 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseAreaService;
  16 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
  17 +import jakarta.annotation.Resource;
  18 +import org.springframework.stereotype.Service;
  19 +import org.springframework.transaction.annotation.Transactional;
  20 +import org.springframework.validation.annotation.Validated;
  21 +
  22 +import java.math.BigDecimal;
  23 +import java.util.ArrayList;
  24 +import java.util.List;
  25 +
  26 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  27 +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;
  28 +
  29 +/**
  30 + * WMS 盘库单 Service 实现类
  31 + *
  32 + * @author 芋道源码
  33 + */
  34 +@Service
  35 +@Validated
  36 +public class WmsCheckOrderServiceImpl implements WmsCheckOrderService {
  37 +
  38 + @Resource
  39 + private WmsCheckOrderMapper checkOrderMapper;
  40 + @Resource
  41 + private WmsCheckOrderDetailService checkOrderDetailService;
  42 + @Resource
  43 + private WmsWarehouseService warehouseService;
  44 + @Resource
  45 + private WmsWarehouseAreaService warehouseAreaService;
  46 + @Resource
  47 + private WmsInventoryService inventoryService;
  48 +
  49 + @Override
  50 + @Transactional(rollbackFor = Exception.class)
  51 + public Long createCheckOrder(WmsCheckOrderSaveReqVO createReqVO) {
  52 + // 1. 校验盘库单保存数据
  53 + validateCheckOrderSaveData(createReqVO);
  54 +
  55 + // 2.1 插入盘库单
  56 + WmsCheckOrderDO order = BeanUtils.toBean(createReqVO, WmsCheckOrderDO.class);
  57 + order.setStatus(WmsOrderStatusEnum.PREPARE.getStatus());
  58 + checkOrderMapper.insert(order);
  59 + // 2.2 插入盘库单明细
  60 + checkOrderDetailService.createCheckOrderDetailList(order.getId(), createReqVO);
  61 + return order.getId();
  62 + }
  63 +
  64 + @Override
  65 + @Transactional(rollbackFor = Exception.class)
  66 + public void updateCheckOrder(WmsCheckOrderSaveReqVO updateReqVO) {
  67 + // 1. 校验盘库单保存数据
  68 + validateCheckOrderPrepare(updateReqVO.getId());
  69 + validateCheckOrderSaveData(updateReqVO);
  70 +
  71 + // 2.1 更新盘库单
  72 + WmsCheckOrderDO updateObj = BeanUtils.toBean(updateReqVO, WmsCheckOrderDO.class)
  73 + .setStatus(WmsOrderStatusEnum.PREPARE.getStatus());
  74 + checkOrderMapper.updateById(updateObj);
  75 + // 2.2 更新盘库单明细
  76 + checkOrderDetailService.updateCheckOrderDetailList(updateReqVO.getId(), updateReqVO);
  77 + }
  78 +
  79 + @Override
  80 + @Transactional(rollbackFor = Exception.class)
  81 + public void deleteCheckOrder(Long id) {
  82 + // 1. 校验存在,且可删除
  83 + WmsCheckOrderDO order = validateCheckOrderExists(id);
  84 + if (ObjectUtil.notEqual(order.getStatus(), WmsOrderStatusEnum.PREPARE.getStatus())
  85 + && ObjectUtil.notEqual(order.getStatus(), WmsOrderStatusEnum.CANCELED.getStatus())) {
  86 + throw exception(CHECK_ORDER_STATUS_NOT_DELETABLE);
  87 + }
  88 +
  89 + // 2.1 删除盘库单
  90 + checkOrderMapper.deleteById(id);
  91 + // 2.2 删除盘库单明细
  92 + checkOrderDetailService.deleteCheckOrderDetailListByOrderId(id);
  93 + }
  94 +
  95 + @Override
  96 + @Transactional(rollbackFor = Exception.class)
  97 + public void completeCheckOrder(Long id) {
  98 + // 1.1 校验存在,且草稿
  99 + WmsCheckOrderDO order = validateCheckOrderPrepare(id);
  100 + // 1.2 校验盘库单明细存在
  101 + List<WmsCheckOrderDetailDO> details = checkOrderDetailService.validateCheckOrderDetailListExists(id);
  102 +
  103 + // 2. 完成盘库单
  104 + checkOrderMapper.updateById(new WmsCheckOrderDO().setId(id)
  105 + .setStatus(WmsOrderStatusEnum.FINISHED.getStatus()));
  106 +
  107 + // 3. 盘点库存
  108 + changeInventory(order, details);
  109 + }
  110 +
  111 + @Override
  112 + @Transactional(rollbackFor = Exception.class)
  113 + public void cancelCheckOrder(Long id) {
  114 + // 1. 校验存在,且草稿
  115 + validateCheckOrderPrepare(id);
  116 +
  117 + // 2. 作废盘库单
  118 + checkOrderMapper.updateById(new WmsCheckOrderDO().setId(id)
  119 + .setStatus(WmsOrderStatusEnum.CANCELED.getStatus()));
  120 + }
  121 +
  122 + @Override
  123 + public WmsCheckOrderDO getCheckOrder(Long id) {
  124 + return checkOrderMapper.selectById(id);
  125 + }
  126 +
  127 + @Override
  128 + public PageResult<WmsCheckOrderDO> getCheckOrderPage(WmsCheckOrderPageReqVO pageReqVO) {
  129 + return checkOrderMapper.selectPage(pageReqVO);
  130 + }
  131 +
  132 + private void validateCheckOrderSaveData(WmsCheckOrderSaveReqVO reqVO) {
  133 + // 校验盘库单号唯一
  134 + validateCheckOrderNoUnique(reqVO.getId(), reqVO.getNo());
  135 + // 校验仓库、库区存在
  136 + warehouseService.validateWarehouseExists(reqVO.getWarehouseId());
  137 + reqVO.setAreaId(warehouseAreaService.validateAndNormalizeWarehouseAreaId(reqVO.getAreaId(),
  138 + reqVO.getWarehouseId()));
  139 + }
  140 +
  141 + private void validateCheckOrderNoUnique(Long id, String no) {
  142 + WmsCheckOrderDO order = checkOrderMapper.selectByNo(no);
  143 + if (order == null) {
  144 + return;
  145 + }
  146 + if (id == null || ObjectUtil.notEqual(order.getId(), id)) {
  147 + throw exception(CHECK_ORDER_NO_DUPLICATE);
  148 + }
  149 + }
  150 +
  151 + private WmsCheckOrderDO validateCheckOrderExists(Long id) {
  152 + WmsCheckOrderDO order = id == null ? null : checkOrderMapper.selectById(id);
  153 + if (order == null) {
  154 + throw exception(CHECK_ORDER_NOT_EXISTS);
  155 + }
  156 + return order;
  157 + }
  158 +
  159 + /**
  160 + * 校验盘库单存在且为草稿状态
  161 + *
  162 + * @param id 盘库单编号
  163 + * @return 盘库单
  164 + */
  165 + private WmsCheckOrderDO validateCheckOrderPrepare(Long id) {
  166 + WmsCheckOrderDO order = validateCheckOrderExists(id);
  167 + if (ObjectUtil.notEqual(order.getStatus(), WmsOrderStatusEnum.PREPARE.getStatus())) {
  168 + throw exception(CHECK_ORDER_STATUS_NOT_PREPARE);
  169 + }
  170 + return order;
  171 + }
  172 +
  173 + /**
  174 + * 盘点盘库单对应库存。
  175 + *
  176 + * 盘库只对盈亏数量生成库存变更:实盘数量大于账面数量时增加库存,反之扣减库存;批次模式下,扣减库存会使用
  177 + * inventoryDetailId 扣减对应库存明细的剩余数量。
  178 + *
  179 + * @param order 盘库单
  180 + * @param details 盘库单明细列表
  181 + */
  182 + private void changeInventory(WmsCheckOrderDO order, List<WmsCheckOrderDetailDO> details) {
  183 + List<WmsInventoryChangeReqDTO.Item> items = new ArrayList<>(details.size());
  184 + for (WmsCheckOrderDetailDO detail : details) {
  185 + BigDecimal differenceQuantity = detail.getCheckQuantity().subtract(detail.getQuantity());
  186 + if (differenceQuantity.compareTo(BigDecimal.ZERO) == 0) {
  187 + continue;
  188 + }
  189 + WmsInventoryChangeReqDTO.Item item = BeanUtils.toBean(detail, WmsInventoryChangeReqDTO.Item.class)
  190 + .setQuantity(differenceQuantity);
  191 + if (differenceQuantity.compareTo(BigDecimal.ZERO) > 0) {
  192 + item.setInventoryDetailId(null);
  193 + }
  194 + items.add(item);
  195 + }
  196 + inventoryService.changeInventory(new WmsInventoryChangeReqDTO()
  197 + .setOrderId(order.getId()).setOrderNo(order.getNo())
  198 + .setOrderType(WmsInventoryOrderTypeEnum.CHECK.getType()).setItems(items));
  199 + }
  200 +
  201 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/movement/WmsMovementOrderDetailService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.movement;
  2 +
  3 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order.WmsMovementOrderSaveReqVO;
  4 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.movement.WmsMovementOrderDetailDO;
  5 +
  6 +import java.util.Collection;
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * WMS 移库单明细 Service 接口
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +public interface WmsMovementOrderDetailService {
  15 +
  16 + /**
  17 + * 创建移库单明细列表
  18 + *
  19 + * @param orderId 移库单编号
  20 + * @param reqVO 移库单保存信息
  21 + */
  22 + void createMovementOrderDetailList(Long orderId, WmsMovementOrderSaveReqVO reqVO);
  23 +
  24 + /**
  25 + * 更新移库单明细列表
  26 + *
  27 + * @param orderId 移库单编号
  28 + * @param reqVO 移库单保存信息
  29 + */
  30 + void updateMovementOrderDetailList(Long orderId, WmsMovementOrderSaveReqVO reqVO);
  31 +
  32 + /**
  33 + * 按移库单编号删除明细列表
  34 + *
  35 + * @param orderId 移库单编号
  36 + */
  37 + void deleteMovementOrderDetailListByOrderId(Long orderId);
  38 +
  39 + /**
  40 + * 按移库单编号获得明细列表
  41 + *
  42 + * @param orderId 移库单编号
  43 + * @return 明细列表
  44 + */
  45 + List<WmsMovementOrderDetailDO> getMovementOrderDetailList(Long orderId);
  46 +
  47 + /**
  48 + * 按移库单编号集合获得明细列表
  49 + *
  50 + * @param orderIds 移库单编号集合
  51 + * @return 明细列表
  52 + */
  53 + List<WmsMovementOrderDetailDO> getMovementOrderDetailList(Collection<Long> orderIds);
  54 +
  55 + /**
  56 + * 校验移库单明细列表存在
  57 + *
  58 + * @param orderId 移库单编号
  59 + * @return 明细列表
  60 + */
  61 + List<WmsMovementOrderDetailDO> validateMovementOrderDetailListExists(Long orderId);
  62 +
  63 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/movement/WmsMovementOrderDetailServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.movement;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.collection.ListUtil;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  7 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order.WmsMovementOrderSaveReqVO;
  8 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO;
  9 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.movement.WmsMovementOrderDetailDO;
  10 +import cn.iocoder.yudao.module.wms.dal.mysql.order.movement.WmsMovementOrderDetailMapper;
  11 +import cn.iocoder.yudao.module.wms.framework.config.WmsProperties;
  12 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
  13 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseAreaService;
  14 +import jakarta.annotation.Resource;
  15 +import org.springframework.stereotype.Service;
  16 +import org.springframework.transaction.annotation.Transactional;
  17 +import org.springframework.validation.annotation.Validated;
  18 +
  19 +import java.util.Collection;
  20 +import java.util.List;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  23 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  24 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
  25 +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;
  26 +
  27 +/**
  28 + * WMS 移库单明细 Service 实现类
  29 + *
  30 + * @author 芋道源码
  31 + */
  32 +@Service
  33 +@Validated
  34 +public class WmsMovementOrderDetailServiceImpl implements WmsMovementOrderDetailService {
  35 +
  36 + @Resource
  37 + private WmsMovementOrderDetailMapper movementOrderDetailMapper;
  38 + @Resource
  39 + private WmsItemSkuService itemSkuService;
  40 + @Resource
  41 + private WmsWarehouseAreaService warehouseAreaService;
  42 + @Resource
  43 + private WmsProperties wmsProperties;
  44 +
  45 + @Override
  46 + @Transactional(rollbackFor = Exception.class)
  47 + public void createMovementOrderDetailList(Long orderId, WmsMovementOrderSaveReqVO reqVO) {
  48 + List<WmsMovementOrderDetailDO> list = buildMovementOrderDetailList(reqVO);
  49 + if (CollUtil.isEmpty(list)) {
  50 + return;
  51 + }
  52 + list.forEach(detail -> detail.setId(null).setOrderId(orderId));
  53 + movementOrderDetailMapper.insertBatch(list);
  54 + }
  55 +
  56 + @Override
  57 + @Transactional(rollbackFor = Exception.class)
  58 + public void updateMovementOrderDetailList(Long orderId, WmsMovementOrderSaveReqVO reqVO) {
  59 + // 第一步,对比新老数据,获得添加、修改、删除的列表
  60 + List<WmsMovementOrderDetailDO> oldList = movementOrderDetailMapper.selectListByOrderId(orderId);
  61 + List<WmsMovementOrderDetailDO> list = buildMovementOrderDetailList(reqVO);
  62 + List<WmsMovementOrderDetailDO> newList = CollUtil.isEmpty(list) ? ListUtil.of() : list;
  63 + List<List<WmsMovementOrderDetailDO>> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录
  64 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId()));
  65 +
  66 + // 第二步,批量添加、修改、删除
  67 + if (CollUtil.isNotEmpty(diffList.get(0))) {
  68 + if (CollUtil.isNotEmpty(convertList(diffList.get(0), WmsMovementOrderDetailDO::getId))) {
  69 + throw exception(MOVEMENT_ORDER_DETAIL_NOT_EXISTS);
  70 + }
  71 + diffList.get(0).forEach(detail -> detail.setOrderId(orderId));
  72 + movementOrderDetailMapper.insertBatch(diffList.get(0));
  73 + }
  74 + if (CollUtil.isNotEmpty(diffList.get(1))) {
  75 + diffList.get(1).forEach(detail -> detail.setOrderId(orderId));
  76 + movementOrderDetailMapper.updateBatch(diffList.get(1));
  77 + }
  78 + if (CollUtil.isNotEmpty(diffList.get(2))) {
  79 + movementOrderDetailMapper.deleteByIds(convertList(diffList.get(2), WmsMovementOrderDetailDO::getId));
  80 + }
  81 + }
  82 +
  83 + @Override
  84 + public void deleteMovementOrderDetailListByOrderId(Long orderId) {
  85 + movementOrderDetailMapper.deleteByOrderId(orderId);
  86 + }
  87 +
  88 + @Override
  89 + public List<WmsMovementOrderDetailDO> getMovementOrderDetailList(Long orderId) {
  90 + return movementOrderDetailMapper.selectListByOrderId(orderId);
  91 + }
  92 +
  93 + @Override
  94 + public List<WmsMovementOrderDetailDO> getMovementOrderDetailList(Collection<Long> orderIds) {
  95 + if (CollUtil.isEmpty(orderIds)) {
  96 + return ListUtil.of();
  97 + }
  98 + return movementOrderDetailMapper.selectListByOrderIds(orderIds);
  99 + }
  100 +
  101 + @Override
  102 + public List<WmsMovementOrderDetailDO> validateMovementOrderDetailListExists(Long orderId) {
  103 + List<WmsMovementOrderDetailDO> details = movementOrderDetailMapper.selectListByOrderId(orderId);
  104 + if (CollUtil.isEmpty(details)) {
  105 + throw exception(MOVEMENT_ORDER_DETAIL_REQUIRED);
  106 + }
  107 + if (wmsProperties.isAreaEnabled() && details.stream().anyMatch(detail ->
  108 + ObjectUtils.equalsAny(detail.getSourceAreaId(), null, WmsWarehouseAreaDO.ID_EMPTY)
  109 + || ObjectUtils.equalsAny(detail.getTargetAreaId(), null, WmsWarehouseAreaDO.ID_EMPTY))) {
  110 + throw exception(MOVEMENT_ORDER_AREA_REQUIRED);
  111 + }
  112 + return details;
  113 + }
  114 +
  115 + private List<WmsMovementOrderDetailDO> buildMovementOrderDetailList(WmsMovementOrderSaveReqVO reqVO) {
  116 + if (CollUtil.isEmpty(reqVO.getDetails())) {
  117 + return ListUtil.of();
  118 + }
  119 + return convertList(reqVO.getDetails(), detail -> {
  120 + // 校验 SKU 存在
  121 + itemSkuService.validateItemSkuExists(detail.getSkuId());
  122 + // 校验来源、目标库区存在,并且属于对应仓库
  123 + Long sourceAreaId = warehouseAreaService.validateAndNormalizeWarehouseAreaId(
  124 + detail.getSourceAreaId() == null ? reqVO.getSourceAreaId() : detail.getSourceAreaId(),
  125 + reqVO.getSourceWarehouseId());
  126 + Long targetAreaId = warehouseAreaService.validateAndNormalizeWarehouseAreaId(
  127 + detail.getTargetAreaId() == null ? reqVO.getTargetAreaId() : detail.getTargetAreaId(),
  128 + reqVO.getTargetWarehouseId());
  129 + // 构建对象
  130 + return BeanUtils.toBean(detail, WmsMovementOrderDetailDO.class)
  131 + .setSourceWarehouseId(reqVO.getSourceWarehouseId()).setSourceAreaId(sourceAreaId)
  132 + .setTargetWarehouseId(reqVO.getTargetWarehouseId()).setTargetAreaId(targetAreaId);
  133 + });
  134 + }
  135 +
  136 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/movement/WmsMovementOrderService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.movement;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order.WmsMovementOrderPageReqVO;
  5 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order.WmsMovementOrderSaveReqVO;
  6 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.movement.WmsMovementOrderDO;
  7 +import jakarta.validation.Valid;
  8 +
  9 +/**
  10 + * WMS 移库单 Service 接口
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +public interface WmsMovementOrderService {
  15 +
  16 + /**
  17 + * 创建移库单
  18 + *
  19 + * @param createReqVO 创建信息
  20 + * @return 编号
  21 + */
  22 + Long createMovementOrder(@Valid WmsMovementOrderSaveReqVO createReqVO);
  23 +
  24 + /**
  25 + * 更新移库单
  26 + *
  27 + * @param updateReqVO 更新信息
  28 + */
  29 + void updateMovementOrder(@Valid WmsMovementOrderSaveReqVO updateReqVO);
  30 +
  31 + /**
  32 + * 删除移库单
  33 + *
  34 + * @param id 编号
  35 + */
  36 + void deleteMovementOrder(Long id);
  37 +
  38 + /**
  39 + * 完成移库
  40 + *
  41 + * @param id 编号
  42 + */
  43 + void completeMovementOrder(Long id);
  44 +
  45 + /**
  46 + * 作废移库单
  47 + *
  48 + * @param id 编号
  49 + */
  50 + void cancelMovementOrder(Long id);
  51 +
  52 + /**
  53 + * 获得移库单
  54 + *
  55 + * @param id 编号
  56 + * @return 移库单
  57 + */
  58 + WmsMovementOrderDO getMovementOrder(Long id);
  59 +
  60 + /**
  61 + * 获得移库单分页
  62 + *
  63 + * @param pageReqVO 分页查询
  64 + * @return 移库单分页
  65 + */
  66 + PageResult<WmsMovementOrderDO> getMovementOrderPage(WmsMovementOrderPageReqVO pageReqVO);
  67 +
  68 +}
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/movement/WmsMovementOrderServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.movement;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order.WmsMovementOrderPageReqVO;
  7 +import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order.WmsMovementOrderSaveReqVO;
  8 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.movement.WmsMovementOrderDO;
  9 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.movement.WmsMovementOrderDetailDO;
  10 +import cn.iocoder.yudao.module.wms.dal.mysql.order.movement.WmsMovementOrderMapper;
  11 +import cn.iocoder.yudao.module.wms.enums.inventory.WmsInventoryOrderTypeEnum;
  12 +import cn.iocoder.yudao.module.wms.enums.order.WmsOrderStatusEnum;
  13 +import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryService;
  14 +import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO;
  15 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseAreaService;
  16 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
  17 +import jakarta.annotation.Resource;
  18 +import org.springframework.stereotype.Service;
  19 +import org.springframework.transaction.annotation.Transactional;
  20 +import org.springframework.validation.annotation.Validated;
  21 +
  22 +import java.util.ArrayList;
  23 +import java.util.List;
  24 +
  25 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  26 +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;
  27 +
  28 +/**
  29 + * WMS 移库单 Service 实现类
  30 + *
  31 + * @author 芋道源码
  32 + */
  33 +@Service
  34 +@Validated
  35 +public class WmsMovementOrderServiceImpl implements WmsMovementOrderService {
  36 +
  37 + @Resource
  38 + private WmsMovementOrderMapper movementOrderMapper;
  39 + @Resource
  40 + private WmsMovementOrderDetailService movementOrderDetailService;
  41 + @Resource
  42 + private WmsWarehouseService warehouseService;
  43 + @Resource
  44 + private WmsWarehouseAreaService warehouseAreaService;
  45 + @Resource
  46 + private WmsInventoryService inventoryService;
  47 +
  48 + @Override
  49 + @Transactional(rollbackFor = Exception.class)
  50 + public Long createMovementOrder(WmsMovementOrderSaveReqVO createReqVO) {
  51 + // 1. 校验移库单保存数据
  52 + validateMovementOrderSaveData(createReqVO);
  53 +
  54 + // 2.1 插入移库单
  55 + WmsMovementOrderDO order = BeanUtils.toBean(createReqVO, WmsMovementOrderDO.class);
  56 + order.setStatus(WmsOrderStatusEnum.PREPARE.getStatus());
  57 + movementOrderMapper.insert(order);
  58 + // 2.2 插入移库单明细
  59 + movementOrderDetailService.createMovementOrderDetailList(order.getId(), createReqVO);
  60 + return order.getId();
  61 + }
  62 +
  63 + @Override
  64 + @Transactional(rollbackFor = Exception.class)
  65 + public void updateMovementOrder(WmsMovementOrderSaveReqVO updateReqVO) {
  66 + // 1. 校验移库单保存数据
  67 + validateMovementOrderPrepare(updateReqVO.getId());
  68 + validateMovementOrderSaveData(updateReqVO);
  69 +
  70 + // 2.1 更新移库单
  71 + WmsMovementOrderDO updateObj = BeanUtils.toBean(updateReqVO, WmsMovementOrderDO.class)
  72 + .setStatus(WmsOrderStatusEnum.PREPARE.getStatus());
  73 + movementOrderMapper.updateById(updateObj);
  74 + // 2.2 更新移库单明细
  75 + movementOrderDetailService.updateMovementOrderDetailList(updateReqVO.getId(), updateReqVO);
  76 + }
  77 +
  78 + @Override
  79 + @Transactional(rollbackFor = Exception.class)
  80 + public void deleteMovementOrder(Long id) {
  81 + // 1. 校验存在,且可删除
  82 + WmsMovementOrderDO order = validateMovementOrderExists(id);
  83 + if (ObjectUtil.notEqual(order.getStatus(), WmsOrderStatusEnum.PREPARE.getStatus())
  84 + && ObjectUtil.notEqual(order.getStatus(), WmsOrderStatusEnum.CANCELED.getStatus())) {
  85 + throw exception(MOVEMENT_ORDER_STATUS_NOT_DELETABLE);
  86 + }
  87 +
  88 + // 2.1 删除移库单
  89 + movementOrderMapper.deleteById(id);
  90 + // 2.2 删除移库单明细
  91 + movementOrderDetailService.deleteMovementOrderDetailListByOrderId(id);
  92 + }
  93 +
  94 + @Override
  95 + @Transactional(rollbackFor = Exception.class)
  96 + public void completeMovementOrder(Long id) {
  97 + // 1.1 校验存在,且草稿
  98 + WmsMovementOrderDO order = validateMovementOrderPrepare(id);
  99 + // 1.2 校验移库单明细存在
  100 + List<WmsMovementOrderDetailDO> details = movementOrderDetailService.validateMovementOrderDetailListExists(id);
  101 +
  102 + // 2. 完成移库单
  103 + movementOrderMapper.updateById(new WmsMovementOrderDO().setId(id)
  104 + .setStatus(WmsOrderStatusEnum.FINISHED.getStatus()));
  105 +
  106 + // 3. 移动库存
  107 + changeInventory(order, details);
  108 + }
  109 +
  110 + @Override
  111 + @Transactional(rollbackFor = Exception.class)
  112 + public void cancelMovementOrder(Long id) {
  113 + // 1. 校验存在,且草稿
  114 + validateMovementOrderPrepare(id);
  115 +
  116 + // 2. 作废移库单
  117 + movementOrderMapper.updateById(new WmsMovementOrderDO().setId(id)
  118 + .setStatus(WmsOrderStatusEnum.CANCELED.getStatus()));
  119 + }
  120 +
  121 + @Override
  122 + public WmsMovementOrderDO getMovementOrder(Long id) {
  123 + return movementOrderMapper.selectById(id);
  124 + }
  125 +
  126 + @Override
  127 + public PageResult<WmsMovementOrderDO> getMovementOrderPage(WmsMovementOrderPageReqVO pageReqVO) {
  128 + return movementOrderMapper.selectPage(pageReqVO);
  129 + }
  130 +
  131 + private void validateMovementOrderSaveData(WmsMovementOrderSaveReqVO reqVO) {
  132 + // 校验移库单号唯一
  133 + validateMovementOrderNoUnique(reqVO.getId(), reqVO.getNo());
  134 + // 校验仓库、库区存在
  135 + warehouseService.validateWarehouseExists(reqVO.getSourceWarehouseId());
  136 + warehouseService.validateWarehouseExists(reqVO.getTargetWarehouseId());
  137 + reqVO.setSourceAreaId(warehouseAreaService.validateAndNormalizeWarehouseAreaId(reqVO.getSourceAreaId(),
  138 + reqVO.getSourceWarehouseId()));
  139 + reqVO.setTargetAreaId(warehouseAreaService.validateAndNormalizeWarehouseAreaId(reqVO.getTargetAreaId(),
  140 + reqVO.getTargetWarehouseId()));
  141 + // 校验来源和目标不能相同
  142 + if (ObjectUtil.equal(reqVO.getSourceWarehouseId(), reqVO.getTargetWarehouseId())
  143 + && ObjectUtil.equal(reqVO.getSourceAreaId(), reqVO.getTargetAreaId())) {
  144 + throw exception(MOVEMENT_ORDER_WAREHOUSE_AREA_SAME);
  145 + }
  146 + }
  147 +
  148 + private void validateMovementOrderNoUnique(Long id, String no) {
  149 + WmsMovementOrderDO order = movementOrderMapper.selectByNo(no);
  150 + if (order == null) {
  151 + return;
  152 + }
  153 + if (id == null || ObjectUtil.notEqual(order.getId(), id)) {
  154 + throw exception(MOVEMENT_ORDER_NO_DUPLICATE);
  155 + }
  156 + }
  157 +
  158 + private WmsMovementOrderDO validateMovementOrderExists(Long id) {
  159 + WmsMovementOrderDO order = id == null ? null : movementOrderMapper.selectById(id);
  160 + if (order == null) {
  161 + throw exception(MOVEMENT_ORDER_NOT_EXISTS);
  162 + }
  163 + return order;
  164 + }
  165 +
  166 + /**
  167 + * 校验移库单存在且为草稿状态
  168 + *
  169 + * @param id 移库单编号
  170 + * @return 移库单
  171 + */
  172 + private WmsMovementOrderDO validateMovementOrderPrepare(Long id) {
  173 + WmsMovementOrderDO order = validateMovementOrderExists(id);
  174 + if (ObjectUtil.notEqual(order.getStatus(), WmsOrderStatusEnum.PREPARE.getStatus())) {
  175 + throw exception(MOVEMENT_ORDER_STATUS_NOT_PREPARE);
  176 + }
  177 + return order;
  178 + }
  179 +
  180 + /**
  181 + * 移动移库单对应库存。
  182 + *
  183 + * 移库会生成两条库存变更:来源仓库扣减库存,目标仓库增加库存;批次模式下,来源库存明细用
  184 + * inventoryDetailId 扣减剩余数量,目标仓库生成新的库存明细。
  185 + *
  186 + * @param order 移库单
  187 + * @param details 移库单明细列表
  188 + */
  189 + private void changeInventory(WmsMovementOrderDO order, List<WmsMovementOrderDetailDO> details) {
  190 + List<WmsInventoryChangeReqDTO.Item> items = new ArrayList<>(details.size() * 2);
  191 + for (WmsMovementOrderDetailDO detail : details) {
  192 + items.add(BeanUtils.toBean(detail, WmsInventoryChangeReqDTO.Item.class)
  193 + .setWarehouseId(detail.getSourceWarehouseId()).setAreaId(detail.getSourceAreaId())
  194 + .setQuantity(detail.getQuantity().negate()));
  195 + items.add(BeanUtils.toBean(detail, WmsInventoryChangeReqDTO.Item.class)
  196 + .setWarehouseId(detail.getTargetWarehouseId()).setAreaId(detail.getTargetAreaId())
  197 + .setInventoryDetailId(null).setQuantity(detail.getQuantity()));
  198 + }
  199 + inventoryService.changeInventory(new WmsInventoryChangeReqDTO()
  200 + .setOrderId(order.getId()).setOrderNo(order.getNo())
  201 + .setOrderType(WmsInventoryOrderTypeEnum.MOVEMENT.getType()).setItems(items));
  202 + }
  203 +
  204 +}
... ...