Commit 55426245a1ff84a8ce67ce33e6b53f4f38f720f7

Authored by YunaiV
1 parent ee20f777

feat(wms):优化 receipt order 实体的实现(增加 code review)

Showing 19 changed files with 1535 additions and 1 deletions
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/WmsReceiptOrderController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.receipt;
  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.receipt.vo.detail.WmsReceiptOrderDetailRespVO;
  15 +import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order.WmsReceiptOrderPageReqVO;
  16 +import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order.WmsReceiptOrderRespVO;
  17 +import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order.WmsReceiptOrderSaveReqVO;
  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.merchant.WmsMerchantDO;
  21 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO;
  22 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
  23 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDO;
  24 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDetailDO;
  25 +import cn.iocoder.yudao.module.wms.framework.config.WmsProperties;
  26 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
  27 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
  28 +import cn.iocoder.yudao.module.wms.service.md.merchant.WmsMerchantService;
  29 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseAreaService;
  30 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
  31 +import cn.iocoder.yudao.module.wms.service.order.receipt.WmsReceiptOrderDetailService;
  32 +import cn.iocoder.yudao.module.wms.service.order.receipt.WmsReceiptOrderService;
  33 +import io.swagger.v3.oas.annotations.Operation;
  34 +import io.swagger.v3.oas.annotations.Parameter;
  35 +import io.swagger.v3.oas.annotations.tags.Tag;
  36 +import jakarta.annotation.Resource;
  37 +import jakarta.servlet.http.HttpServletResponse;
  38 +import jakarta.validation.Valid;
  39 +import org.springframework.security.access.prepost.PreAuthorize;
  40 +import org.springframework.validation.annotation.Validated;
  41 +import org.springframework.web.bind.annotation.*;
  42 +
  43 +import java.io.IOException;
  44 +import java.util.Collections;
  45 +import java.util.List;
  46 +import java.util.Map;
  47 +import java.util.stream.Stream;
  48 +
  49 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
  50 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  51 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  52 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
  53 +
  54 +@Tag(name = "管理后台 - WMS 入库单")
  55 +@RestController
  56 +@RequestMapping("/wms/receipt-order")
  57 +@Validated
  58 +public class WmsReceiptOrderController {
  59 +
  60 + @Resource
  61 + private WmsReceiptOrderService receiptOrderService;
  62 + @Resource
  63 + private WmsReceiptOrderDetailService receiptOrderDetailService;
  64 + @Resource
  65 + private WmsMerchantService merchantService;
  66 + @Resource
  67 + private WmsWarehouseService warehouseService;
  68 + @Resource
  69 + private WmsWarehouseAreaService warehouseAreaService;
  70 + @Resource
  71 + private WmsItemService itemService;
  72 + @Resource
  73 + private WmsItemSkuService itemSkuService;
  74 +
  75 + @Resource
  76 + private WmsProperties wmsProperties;
  77 +
  78 + @Resource
  79 + private AdminUserApi adminUserApi;
  80 +
  81 + @PostMapping("/create")
  82 + @Operation(summary = "创建入库单")
  83 + @PreAuthorize("@ss.hasPermission('wms:receipt-order:create')")
  84 + public CommonResult<Long> createReceiptOrder(@Valid @RequestBody WmsReceiptOrderSaveReqVO createReqVO) {
  85 + return success(receiptOrderService.createReceiptOrder(createReqVO));
  86 + }
  87 +
  88 + @PutMapping("/update")
  89 + @Operation(summary = "更新入库单")
  90 + @PreAuthorize("@ss.hasPermission('wms:receipt-order:update')")
  91 + public CommonResult<Boolean> updateReceiptOrder(@Valid @RequestBody WmsReceiptOrderSaveReqVO updateReqVO) {
  92 + receiptOrderService.updateReceiptOrder(updateReqVO);
  93 + return success(true);
  94 + }
  95 +
  96 + @DeleteMapping("/delete")
  97 + @Operation(summary = "删除入库单")
  98 + @Parameter(name = "id", description = "编号", required = true)
  99 + @PreAuthorize("@ss.hasPermission('wms:receipt-order:delete')")
  100 + public CommonResult<Boolean> deleteReceiptOrder(@RequestParam("id") Long id) {
  101 + receiptOrderService.deleteReceiptOrder(id);
  102 + return success(true);
  103 + }
  104 +
  105 + @PutMapping("/complete")
  106 + @Operation(summary = "完成入库")
  107 + @Parameter(name = "id", description = "编号", required = true)
  108 + @PreAuthorize("@ss.hasPermission('wms:receipt-order:complete')")
  109 + public CommonResult<Boolean> completeReceiptOrder(@RequestParam("id") Long id) {
  110 + receiptOrderService.completeReceiptOrder(id);
  111 + return success(true);
  112 + }
  113 +
  114 + @PutMapping("/cancel")
  115 + @Operation(summary = "作废入库单")
  116 + @Parameter(name = "id", description = "编号", required = true)
  117 + @PreAuthorize("@ss.hasPermission('wms:receipt-order:cancel')")
  118 + public CommonResult<Boolean> cancelReceiptOrder(@RequestParam("id") Long id) {
  119 + receiptOrderService.cancelReceiptOrder(id);
  120 + return success(true);
  121 + }
  122 +
  123 + @GetMapping("/get")
  124 + @Operation(summary = "获得入库单")
  125 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  126 + @PreAuthorize("@ss.hasPermission('wms:receipt-order:query')")
  127 + public CommonResult<WmsReceiptOrderRespVO> getReceiptOrder(@RequestParam("id") Long id) {
  128 + WmsReceiptOrderDO order = receiptOrderService.getReceiptOrder(id);
  129 + if (order == null) {
  130 + return success(null);
  131 + }
  132 + // 获得入库单的明细列表
  133 + List<WmsReceiptOrderDetailDO> detailList = receiptOrderDetailService.getReceiptOrderDetailList(id);
  134 + // 拼接结果返回
  135 + WmsReceiptOrderRespVO respVO = buildReceiptOrderRespVO(order)
  136 + .setDetails(buildReceiptOrderDetailRespVOList(detailList));
  137 + return success(respVO);
  138 + }
  139 +
  140 + @GetMapping("/page")
  141 + @Operation(summary = "获得入库单分页")
  142 + @PreAuthorize("@ss.hasPermission('wms:receipt-order:query')")
  143 + public CommonResult<PageResult<WmsReceiptOrderRespVO>> getReceiptOrderPage(@Valid WmsReceiptOrderPageReqVO pageReqVO) {
  144 + PageResult<WmsReceiptOrderDO> pageResult = receiptOrderService.getReceiptOrderPage(pageReqVO);
  145 + return success(new PageResult<>(buildReceiptOrderRespVOList(pageResult.getList()), pageResult.getTotal()));
  146 + }
  147 +
  148 + @GetMapping("/export-excel")
  149 + @Operation(summary = "导出入库单 Excel")
  150 + @PreAuthorize("@ss.hasPermission('wms:receipt-order:export')")
  151 + @ApiAccessLog(operateType = EXPORT)
  152 + public void exportReceiptOrderExcel(@Valid WmsReceiptOrderPageReqVO pageReqVO,
  153 + HttpServletResponse response) throws IOException {
  154 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  155 + List<WmsReceiptOrderDO> list = receiptOrderService.getReceiptOrderPage(pageReqVO).getList();
  156 + ExcelUtils.write(response, "入库单.xls", "数据", WmsReceiptOrderRespVO.class,
  157 + buildReceiptOrderRespVOList(list));
  158 + }
  159 +
  160 + // ==================== 拼接 VO ====================
  161 +
  162 + private WmsReceiptOrderRespVO buildReceiptOrderRespVO(WmsReceiptOrderDO order) {
  163 + if (order == null) {
  164 + return null;
  165 + }
  166 + List<WmsReceiptOrderRespVO> list = buildReceiptOrderRespVOList(List.of(order));
  167 + return CollUtil.getFirst(list);
  168 + }
  169 +
  170 + private List<WmsReceiptOrderRespVO> buildReceiptOrderRespVOList(List<WmsReceiptOrderDO> list) {
  171 + if (CollUtil.isEmpty(list)) {
  172 + return Collections.emptyList();
  173 + }
  174 + // 获取相关的商户、仓库、库区、用户等数据
  175 + Map<Long, WmsMerchantDO> merchantMap = merchantService.getMerchantMap(convertSet(list, WmsReceiptOrderDO::getMerchantId));
  176 + Map<Long, WmsWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(convertSet(list, WmsReceiptOrderDO::getWarehouseId));
  177 + Map<Long, WmsWarehouseAreaDO> areaMap = wmsProperties.isAreaEnabled()
  178 + ? warehouseAreaService.getWarehouseAreaMap(convertSet(list, WmsReceiptOrderDO::getAreaId))
  179 + : Collections.emptyMap();
  180 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSetByFlatMap(list,
  181 + order -> Stream.of(parseUserId(order.getCreator()), parseUserId(order.getUpdater()))));
  182 + // 拼接数据
  183 + return BeanUtils.toBean(list, WmsReceiptOrderRespVO.class, vo -> {
  184 + MapUtils.findAndThen(merchantMap, vo.getMerchantId(), merchant -> vo.setMerchantName(merchant.getName()));
  185 + MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
  186 + MapUtils.findAndThen(areaMap, vo.getAreaId(), area -> vo.setAreaName(area.getName()));
  187 + MapUtils.findAndThen(userMap, parseUserId(vo.getCreator()), user -> vo.setCreatorName(user.getNickname()));
  188 + MapUtils.findAndThen(userMap, parseUserId(vo.getUpdater()), user -> vo.setUpdaterName(user.getNickname()));
  189 + });
  190 + }
  191 +
  192 + private Long parseUserId(String userId) {
  193 + return NumberUtil.parseLong(userId, null);
  194 + }
  195 +
  196 + private List<WmsReceiptOrderDetailRespVO> buildReceiptOrderDetailRespVOList(List<WmsReceiptOrderDetailDO> list) {
  197 + if (CollUtil.isEmpty(list)) {
  198 + return Collections.emptyList();
  199 + }
  200 + // 获取相关的商品、SKU、仓库、库区等数据
  201 + Map<Long, WmsItemSkuDO> skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsReceiptOrderDetailDO::getSkuId));
  202 + Map<Long, WmsItemDO> itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
  203 + Map<Long, WmsWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(
  204 + convertSet(list, WmsReceiptOrderDetailDO::getWarehouseId));
  205 + Map<Long, WmsWarehouseAreaDO> areaMap = wmsProperties.isAreaEnabled()
  206 + ? warehouseAreaService.getWarehouseAreaMap(convertSet(list, WmsReceiptOrderDetailDO::getAreaId))
  207 + : Collections.emptyMap();
  208 + // 拼接数据
  209 + return BeanUtils.toBean(list, WmsReceiptOrderDetailRespVO.class, vo -> {
  210 + MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
  211 + vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
  212 + MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
  213 + .setItemName(item.getName()).setUnit(item.getUnit()));
  214 + });
  215 + MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
  216 + MapUtils.findAndThen(areaMap, vo.getAreaId(), area -> vo.setAreaName(area.getName()));
  217 + });
  218 + }
  219 +
  220 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/WmsReceiptOrderDetailController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.receipt;
  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.receipt.vo.detail.WmsReceiptOrderDetailRespVO;
  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.receipt.WmsReceiptOrderDetailDO;
  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.receipt.WmsReceiptOrderDetailService;
  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 +
  34 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  36 +
  37 +@Tag(name = "管理后台 - WMS 入库单明细")
  38 +@RestController
  39 +@RequestMapping("/wms/receipt-order-detail")
  40 +@Validated
  41 +public class WmsReceiptOrderDetailController {
  42 +
  43 + @Resource
  44 + private WmsReceiptOrderDetailService receiptOrderDetailService;
  45 + @Resource
  46 + private WmsItemService itemService;
  47 + @Resource
  48 + private WmsItemSkuService itemSkuService;
  49 + @Resource
  50 + private WmsWarehouseService warehouseService;
  51 + @Resource
  52 + private WmsWarehouseAreaService warehouseAreaService;
  53 +
  54 + @Resource
  55 + private WmsProperties wmsProperties;
  56 +
  57 + @GetMapping("/list-by-order-id")
  58 + @Operation(summary = "获得入库单明细列表")
  59 + @Parameter(name = "orderId", description = "入库单编号", required = true, example = "1024")
  60 + @PreAuthorize("@ss.hasPermission('wms:receipt-order:query')")
  61 + public CommonResult<List<WmsReceiptOrderDetailRespVO>> getReceiptOrderDetailListByOrderId(
  62 + @RequestParam("orderId") Long orderId) {
  63 + List<WmsReceiptOrderDetailDO> list = receiptOrderDetailService.getReceiptOrderDetailList(orderId);
  64 + return success(buildReceiptOrderDetailRespVOList(list));
  65 + }
  66 +
  67 + // ==================== 拼接 VO ====================
  68 +
  69 + private List<WmsReceiptOrderDetailRespVO> buildReceiptOrderDetailRespVOList(List<WmsReceiptOrderDetailDO> list) {
  70 + if (CollUtil.isEmpty(list)) {
  71 + return Collections.emptyList();
  72 + }
  73 + // 查询关联数据
  74 + Map<Long, WmsItemSkuDO> skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsReceiptOrderDetailDO::getSkuId));
  75 + Map<Long, WmsItemDO> itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
  76 + Map<Long, WmsWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(
  77 + convertSet(list, WmsReceiptOrderDetailDO::getWarehouseId));
  78 + Map<Long, WmsWarehouseAreaDO> areaMap = wmsProperties.isAreaEnabled()
  79 + ? warehouseAreaService.getWarehouseAreaMap(convertSet(list, WmsReceiptOrderDetailDO::getAreaId))
  80 + : Collections.emptyMap();
  81 + // 拼接数据
  82 + return BeanUtils.toBean(list, WmsReceiptOrderDetailRespVO.class, vo -> {
  83 + MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
  84 + vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
  85 + MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
  86 + .setItemName(item.getName()).setUnit(item.getUnit()));
  87 + });
  88 + MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
  89 + MapUtils.findAndThen(areaMap, vo.getAreaId(), area -> vo.setAreaName(area.getName()));
  90 + });
  91 + }
  92 +
  93 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/detail/WmsReceiptOrderDetailRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.receipt.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 WmsReceiptOrderDetailRespVO {
  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 = "B202605110001")
  53 + private String batchNo;
  54 +
  55 + @Schema(description = "生产日期")
  56 + private LocalDateTime productionDate;
  57 +
  58 + @Schema(description = "过期日期")
  59 + private LocalDateTime expirationDate;
  60 +
  61 + @Schema(description = "入库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  62 + private BigDecimal quantity;
  63 +
  64 + @Schema(description = "金额", example = "1000.00")
  65 + private BigDecimal amount;
  66 +
  67 + @Schema(description = "备注", example = "备注")
  68 + private String remark;
  69 +
  70 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  71 + private LocalDateTime createTime;
  72 +
  73 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/detail/WmsReceiptOrderDetailSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.receipt.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 WmsReceiptOrderDetailSaveReqVO {
  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 = "B202605110001")
  27 + @Size(max = 64, message = "批号长度不能超过 64 个字符")
  28 + private String batchNo;
  29 +
  30 + @Schema(description = "生产日期")
  31 + private LocalDateTime productionDate;
  32 +
  33 + @Schema(description = "过期日期")
  34 + private LocalDateTime expirationDate;
  35 +
  36 + @Schema(description = "入库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  37 + @NotNull(message = "入库数量不能为空")
  38 + @DecimalMin(value = "0", inclusive = false, message = "入库数量必须大于 0")
  39 + private BigDecimal quantity;
  40 +
  41 + @Schema(description = "金额", example = "1000.00")
  42 + @DecimalMin(value = "0", message = "金额不能小于 0")
  43 + private BigDecimal amount;
  44 +
  45 + @Schema(description = "备注", example = "备注")
  46 + @Size(max = 255, message = "备注长度不能超过 255 个字符")
  47 + private String remark;
  48 +
  49 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.receipt.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.WmsReceiptOrderStatusEnum;
  6 +import cn.iocoder.yudao.module.wms.enums.order.WmsReceiptOrderTypeEnum;
  7 +import io.swagger.v3.oas.annotations.media.Schema;
  8 +import lombok.Data;
  9 +import lombok.EqualsAndHashCode;
  10 +import lombok.ToString;
  11 +import org.springframework.format.annotation.DateTimeFormat;
  12 +
  13 +import java.math.BigDecimal;
  14 +import java.time.LocalDateTime;
  15 +
  16 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  17 +
  18 +@Schema(description = "管理后台 - WMS 入库单分页 Request VO")
  19 +@Data
  20 +@EqualsAndHashCode(callSuper = true)
  21 +@ToString(callSuper = true)
  22 +public class WmsReceiptOrderPageReqVO extends PageParam {
  23 +
  24 + @Schema(description = "入库单号", example = "RK202605110001")
  25 + private String no;
  26 +
  27 + @Schema(description = "单据状态", example = "0")
  28 + @InEnum(WmsReceiptOrderStatusEnum.class)
  29 + private Integer status;
  30 +
  31 + @Schema(description = "仓库编号", example = "1024")
  32 + private Long warehouseId;
  33 +
  34 + @Schema(description = "供应商编号", example = "1024")
  35 + private Long merchantId;
  36 +
  37 + @Schema(description = "单据日期")
  38 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  39 + private LocalDateTime[] orderDate;
  40 +
  41 + @Schema(description = "最小数量", example = "1.00")
  42 + private BigDecimal totalQuantityMin;
  43 +
  44 + @Schema(description = "最大数量", example = "100.00")
  45 + private BigDecimal totalQuantityMax;
  46 +
  47 + @Schema(description = "最小总金额", example = "1.00")
  48 + private BigDecimal totalAmountMin;
  49 +
  50 + @Schema(description = "最大总金额", example = "1000.00")
  51 + private BigDecimal totalAmountMax;
  52 +
  53 + @Schema(description = "入库类型", example = "1")
  54 + @InEnum(WmsReceiptOrderTypeEnum.class)
  55 + private Integer type;
  56 +
  57 + @Schema(description = "业务单号", example = "PO202605110001")
  58 + private String bizOrderNo;
  59 +
  60 + @Schema(description = "创建用户", example = "1")
  61 + private String creator;
  62 +
  63 + @Schema(description = "更新用户", example = "1")
  64 + private String updater;
  65 +
  66 + @Schema(description = "创建时间")
  67 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  68 + private LocalDateTime[] createTime;
  69 +
  70 + @Schema(description = "更新时间")
  71 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  72 + private LocalDateTime[] updateTime;
  73 +
  74 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.receipt.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.receipt.vo.detail.WmsReceiptOrderDetailRespVO;
  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 WmsReceiptOrderRespVO {
  20 +
  21 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  22 + private Long id;
  23 +
  24 + @Schema(description = "入库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "RK202605110001")
  25 + @ExcelProperty("入库单号")
  26 + private String no;
  27 +
  28 + @Schema(description = "入库类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  29 + @ExcelProperty(value = "入库类型", converter = DictConvert.class)
  30 + @DictFormat(DictTypeConstants.RECEIPT_ORDER_TYPE)
  31 + private Integer type;
  32 +
  33 + @Schema(description = "入库状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  34 + @ExcelProperty(value = "入库状态", converter = DictConvert.class)
  35 + @DictFormat(DictTypeConstants.RECEIPT_ORDER_STATUS)
  36 + private Integer status;
  37 +
  38 + @Schema(description = "业务单号", example = "PO202605110001")
  39 + @ExcelProperty("业务单号")
  40 + private String bizOrderNo;
  41 +
  42 + @Schema(description = "供应商编号", example = "1024")
  43 + private Long merchantId;
  44 +
  45 + @Schema(description = "供应商名称", example = "某某公司")
  46 + @ExcelProperty("供应商")
  47 + private String merchantName;
  48 +
  49 + @Schema(description = "备注", example = "备注")
  50 + private String remark;
  51 +
  52 + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  53 + private Long warehouseId;
  54 +
  55 + @Schema(description = "仓库名称", example = "北京仓")
  56 + @ExcelProperty("仓库")
  57 + private String warehouseName;
  58 +
  59 + @Schema(description = "库区编号", example = "1024")
  60 + private Long areaId;
  61 +
  62 + @Schema(description = "库区名称", example = "北京库区01")
  63 + private String areaName;
  64 +
  65 + @Schema(description = "入库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  66 + @ExcelProperty("入库数量")
  67 + private BigDecimal totalQuantity;
  68 +
  69 + @Schema(description = "总金额", example = "1000.00")
  70 + @ExcelProperty("总金额")
  71 + private BigDecimal totalAmount;
  72 +
  73 + @Schema(description = "入库明细")
  74 + private List<WmsReceiptOrderDetailRespVO> details;
  75 +
  76 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  77 + @ExcelProperty("创建时间")
  78 + private LocalDateTime createTime;
  79 +
  80 + @Schema(description = "创建者", example = "1")
  81 + private String creator;
  82 + @Schema(description = "创建者名称", example = "芋道")
  83 + private String creatorName;
  84 +
  85 + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
  86 + private LocalDateTime updateTime;
  87 +
  88 + @Schema(description = "更新者", example = "1")
  89 + private String updater;
  90 + @Schema(description = "更新者名称", example = "芋道")
  91 + private String updaterName;
  92 +
  93 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.detail.WmsReceiptOrderDetailSaveReqVO;
  5 +import cn.iocoder.yudao.module.wms.enums.order.WmsReceiptOrderTypeEnum;
  6 +import io.swagger.v3.oas.annotations.media.Schema;
  7 +import jakarta.validation.Valid;
  8 +import jakarta.validation.constraints.NotBlank;
  9 +import jakarta.validation.constraints.NotNull;
  10 +import jakarta.validation.constraints.Size;
  11 +import lombok.Data;
  12 +
  13 +import java.math.BigDecimal;
  14 +import java.util.List;
  15 +
  16 +@Schema(description = "管理后台 - WMS 入库单保存 Request VO")
  17 +@Data
  18 +public class WmsReceiptOrderSaveReqVO {
  19 +
  20 + @Schema(description = "编号", example = "1024")
  21 + private Long id;
  22 +
  23 + @Schema(description = "入库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "RK202605110001")
  24 + @NotBlank(message = "入库单号不能为空")
  25 + @Size(max = 64, message = "入库单号长度不能超过 64 个字符")
  26 + private String no;
  27 +
  28 + @Schema(description = "入库类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  29 + @NotNull(message = "入库类型不能为空")
  30 + @InEnum(WmsReceiptOrderTypeEnum.class)
  31 + private Integer type;
  32 +
  33 + @Schema(description = "业务单号", example = "PO202605110001")
  34 + @Size(max = 64, message = "业务单号长度不能超过 64 个字符")
  35 + private String bizOrderNo;
  36 +
  37 + @Schema(description = "供应商编号", example = "1024")
  38 + private Long merchantId;
  39 +
  40 + @Schema(description = "备注", example = "备注")
  41 + @Size(max = 255, message = "备注长度不能超过 255 个字符")
  42 + private String remark;
  43 +
  44 + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  45 + @NotNull(message = "仓库不能为空")
  46 + private Long warehouseId;
  47 +
  48 + @Schema(description = "库区编号", example = "1024")
  49 + private Long areaId;
  50 +
  51 + @Schema(description = "入库数量", example = "100.00")
  52 + private BigDecimal totalQuantity;
  53 +
  54 + @Schema(description = "总金额", example = "1000.00")
  55 + private BigDecimal totalAmount;
  56 +
  57 + @Schema(description = "入库明细")
  58 + @Valid
  59 + private List<WmsReceiptOrderDetailSaveReqVO> details;
  60 +
  61 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/receipt/WmsReceiptOrderDO.java
@@ -53,7 +53,7 @@ public class WmsReceiptOrderDO extends BaseDO { @@ -53,7 +53,7 @@ public class WmsReceiptOrderDO extends BaseDO {
53 */ 53 */
54 private String bizOrderNo; 54 private String bizOrderNo;
55 /** 55 /**
56 - * 往来企业编号 56 + * 供应商编号
57 * 57 *
58 * 关联 {@link WmsMerchantDO#getId()} 58 * 关联 {@link WmsMerchantDO#getId()}
59 */ 59 */
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/receipt/WmsReceiptOrderDetailMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.mysql.order.receipt;
  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.receipt.WmsReceiptOrderDetailDO;
  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 WmsReceiptOrderDetailMapper extends BaseMapperX<WmsReceiptOrderDetailDO> {
  18 +
  19 + default List<WmsReceiptOrderDetailDO> selectListByOrderId(Long orderId) {
  20 + return selectList(WmsReceiptOrderDetailDO::getOrderId, orderId);
  21 + }
  22 +
  23 + default List<WmsReceiptOrderDetailDO> selectListByOrderIds(Collection<Long> orderIds) {
  24 + return selectList(new LambdaQueryWrapperX<WmsReceiptOrderDetailDO>()
  25 + .inIfPresent(WmsReceiptOrderDetailDO::getOrderId, orderIds)
  26 + .orderByAsc(WmsReceiptOrderDetailDO::getOrderId)
  27 + .orderByAsc(WmsReceiptOrderDetailDO::getId));
  28 + }
  29 +
  30 + default void deleteByOrderId(Long orderId) {
  31 + delete(WmsReceiptOrderDetailDO::getOrderId, orderId);
  32 + }
  33 +
  34 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/receipt/WmsReceiptOrderMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.mysql.order.receipt;
  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.receipt.vo.order.WmsReceiptOrderPageReqVO;
  7 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +/**
  11 + * WMS 入库单 Mapper
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Mapper
  16 +public interface WmsReceiptOrderMapper extends BaseMapperX<WmsReceiptOrderDO> {
  17 +
  18 + default PageResult<WmsReceiptOrderDO> selectPage(WmsReceiptOrderPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<WmsReceiptOrderDO>()
  20 + .likeIfPresent(WmsReceiptOrderDO::getNo, reqVO.getNo())
  21 + .eqIfPresent(WmsReceiptOrderDO::getStatus, reqVO.getStatus())
  22 + .eqIfPresent(WmsReceiptOrderDO::getWarehouseId, reqVO.getWarehouseId())
  23 + .eqIfPresent(WmsReceiptOrderDO::getMerchantId, reqVO.getMerchantId())
  24 + .betweenIfPresent(WmsReceiptOrderDO::getCreateTime, reqVO.getOrderDate())
  25 + .geIfPresent(WmsReceiptOrderDO::getTotalQuantity, reqVO.getTotalQuantityMin())
  26 + .leIfPresent(WmsReceiptOrderDO::getTotalQuantity, reqVO.getTotalQuantityMax())
  27 + .geIfPresent(WmsReceiptOrderDO::getTotalAmount, reqVO.getTotalAmountMin())
  28 + .leIfPresent(WmsReceiptOrderDO::getTotalAmount, reqVO.getTotalAmountMax())
  29 + .eqIfPresent(WmsReceiptOrderDO::getType, reqVO.getType())
  30 + .likeIfPresent(WmsReceiptOrderDO::getBizOrderNo, reqVO.getBizOrderNo())
  31 + .eqIfPresent(WmsReceiptOrderDO::getCreator, reqVO.getCreator())
  32 + .eqIfPresent(WmsReceiptOrderDO::getUpdater, reqVO.getUpdater())
  33 + .betweenIfPresent(WmsReceiptOrderDO::getCreateTime, reqVO.getCreateTime())
  34 + .betweenIfPresent(WmsReceiptOrderDO::getUpdateTime, reqVO.getUpdateTime())
  35 + .orderByDesc(WmsReceiptOrderDO::getId));
  36 + }
  37 +
  38 + default WmsReceiptOrderDO selectByNo(String no) {
  39 + return selectOne(WmsReceiptOrderDO::getNo, no);
  40 + }
  41 +
  42 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java
@@ -55,5 +55,7 @@ public interface ErrorCodeConstants { @@ -55,5 +55,7 @@ public interface ErrorCodeConstants {
55 ErrorCode RECEIPT_ORDER_AREA_REQUIRED = new ErrorCode(1_060_200_004, "库区模式下,入库单库区不能为空"); 55 ErrorCode RECEIPT_ORDER_AREA_REQUIRED = new ErrorCode(1_060_200_004, "库区模式下,入库单库区不能为空");
56 ErrorCode RECEIPT_ORDER_AREA_NOT_MATCH_WAREHOUSE = new ErrorCode(1_060_200_005, "库区不属于入库仓库"); 56 ErrorCode RECEIPT_ORDER_AREA_NOT_MATCH_WAREHOUSE = new ErrorCode(1_060_200_005, "库区不属于入库仓库");
57 ErrorCode RECEIPT_ORDER_COMPLETED_CANNOT_DELETE = new ErrorCode(1_060_200_006, "入库单已完成,不能删除"); 57 ErrorCode RECEIPT_ORDER_COMPLETED_CANNOT_DELETE = new ErrorCode(1_060_200_006, "入库单已完成,不能删除");
  58 + ErrorCode RECEIPT_ORDER_DETAIL_NOT_EXISTS = new ErrorCode(1_060_200_007, "入库单明细不存在");
  59 + ErrorCode RECEIPT_ORDER_MERCHANT_NOT_SUPPLIER = new ErrorCode(1_060_200_008, "入库单供应商必须选择供应商或客户/供应商类型的往来企业");
58 60
59 } 61 }
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsReceiptOrderStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.enums.order;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * WMS 入库单状态枚举
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@Getter
  15 +@AllArgsConstructor
  16 +public enum WmsReceiptOrderStatusEnum implements ArrayValuable<Integer> {
  17 +
  18 + CANCELED(-1, "作废"),
  19 + PENDING(0, "暂存"),
  20 + COMPLETED(1, "完成入库");
  21 +
  22 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(WmsReceiptOrderStatusEnum::getStatus).toArray(Integer[]::new);
  23 +
  24 + /**
  25 + * 状态
  26 + */
  27 + private final Integer status;
  28 + /**
  29 + * 名称
  30 + */
  31 + private final String name;
  32 +
  33 + @Override
  34 + public Integer[] array() {
  35 + return ARRAYS;
  36 + }
  37 +
  38 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsReceiptOrderTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.enums.order;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * WMS 入库单类型枚举
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@Getter
  15 +@AllArgsConstructor
  16 +public enum WmsReceiptOrderTypeEnum implements ArrayValuable<Integer> {
  17 +
  18 + PURCHASE(1, "采购入库"),
  19 + OUTSOURCING(2, "外协入库"),
  20 + RETURN(3, "退货入库");
  21 +
  22 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(WmsReceiptOrderTypeEnum::getType).toArray(Integer[]::new);
  23 +
  24 + /**
  25 + * 类型
  26 + */
  27 + private final Integer type;
  28 + /**
  29 + * 名称
  30 + */
  31 + private final String name;
  32 +
  33 + @Override
  34 + public Integer[] array() {
  35 + return ARRAYS;
  36 + }
  37 +
  38 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/receipt/WmsReceiptOrderDetailService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.receipt;
  2 +
  3 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDetailDO;
  4 +
  5 +import java.util.Collection;
  6 +import java.util.List;
  7 +
  8 +/**
  9 + * WMS 入库单明细 Service 接口
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +public interface WmsReceiptOrderDetailService {
  14 +
  15 + /**
  16 + * 创建入库单明细列表
  17 + *
  18 + * @param orderId 入库单编号
  19 + * @param list 明细列表
  20 + */
  21 + void createReceiptOrderDetailList(Long orderId, List<WmsReceiptOrderDetailDO> list);
  22 +
  23 + /**
  24 + * 更新入库单明细列表
  25 + *
  26 + * @param orderId 入库单编号
  27 + * @param list 明细列表
  28 + */
  29 + void updateReceiptOrderDetailList(Long orderId, List<WmsReceiptOrderDetailDO> list);
  30 +
  31 + /**
  32 + * 按入库单编号删除明细列表
  33 + *
  34 + * @param orderId 入库单编号
  35 + */
  36 + void deleteReceiptOrderDetailListByOrderId(Long orderId);
  37 +
  38 + /**
  39 + * 按入库单编号获得明细列表
  40 + *
  41 + * @param orderId 入库单编号
  42 + * @return 明细列表
  43 + */
  44 + List<WmsReceiptOrderDetailDO> getReceiptOrderDetailList(Long orderId);
  45 +
  46 + /**
  47 + * 按入库单编号集合获得明细列表
  48 + *
  49 + * @param orderIds 入库单编号集合
  50 + * @return 明细列表
  51 + */
  52 + List<WmsReceiptOrderDetailDO> getReceiptOrderDetailList(Collection<Long> orderIds);
  53 +
  54 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/receipt/WmsReceiptOrderDetailServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.receipt;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.collection.ListUtil;
  5 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDetailDO;
  6 +import cn.iocoder.yudao.module.wms.dal.mysql.order.receipt.WmsReceiptOrderDetailMapper;
  7 +import jakarta.annotation.Resource;
  8 +import org.springframework.stereotype.Service;
  9 +import org.springframework.transaction.annotation.Transactional;
  10 +import org.springframework.validation.annotation.Validated;
  11 +
  12 +import java.util.Collection;
  13 +import java.util.List;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  16 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  17 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
  18 +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.RECEIPT_ORDER_DETAIL_NOT_EXISTS;
  19 +
  20 +/**
  21 + * WMS 入库单明细 Service 实现类
  22 + *
  23 + * @author 芋道源码
  24 + */
  25 +@Service
  26 +@Validated
  27 +public class WmsReceiptOrderDetailServiceImpl implements WmsReceiptOrderDetailService {
  28 +
  29 + @Resource
  30 + private WmsReceiptOrderDetailMapper receiptOrderDetailMapper;
  31 +
  32 + @Override
  33 + @Transactional(rollbackFor = Exception.class)
  34 + public void createReceiptOrderDetailList(Long orderId, List<WmsReceiptOrderDetailDO> list) {
  35 + if (CollUtil.isEmpty(list)) {
  36 + return;
  37 + }
  38 + if (CollUtil.isNotEmpty(convertList(list, WmsReceiptOrderDetailDO::getId))) {
  39 + throw exception(RECEIPT_ORDER_DETAIL_NOT_EXISTS);
  40 + }
  41 + list.forEach(detail -> detail.setOrderId(orderId));
  42 + receiptOrderDetailMapper.insertBatch(list);
  43 + }
  44 +
  45 + @Override
  46 + @Transactional(rollbackFor = Exception.class)
  47 + public void updateReceiptOrderDetailList(Long orderId, List<WmsReceiptOrderDetailDO> list) {
  48 + // 第一步,对比新老数据,获得添加、修改、删除的列表
  49 + List<WmsReceiptOrderDetailDO> oldList = receiptOrderDetailMapper.selectListByOrderId(orderId);
  50 + List<WmsReceiptOrderDetailDO> newList = CollUtil.isEmpty(list) ? ListUtil.of() : list;
  51 + List<List<WmsReceiptOrderDetailDO>> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录
  52 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId()));
  53 +
  54 + // 第二步,批量添加、修改、删除
  55 + if (CollUtil.isNotEmpty(diffList.get(0))) {
  56 + if (CollUtil.isNotEmpty(convertList(diffList.get(0), WmsReceiptOrderDetailDO::getId))) {
  57 + throw exception(RECEIPT_ORDER_DETAIL_NOT_EXISTS);
  58 + }
  59 + diffList.get(0).forEach(detail -> detail.setOrderId(orderId));
  60 + receiptOrderDetailMapper.insertBatch(diffList.get(0));
  61 + }
  62 + if (CollUtil.isNotEmpty(diffList.get(1))) {
  63 + diffList.get(1).forEach(detail -> detail.setOrderId(orderId));
  64 + receiptOrderDetailMapper.updateBatch(diffList.get(1));
  65 + }
  66 + if (CollUtil.isNotEmpty(diffList.get(2))) {
  67 + receiptOrderDetailMapper.deleteByIds(convertList(diffList.get(2), WmsReceiptOrderDetailDO::getId));
  68 + }
  69 + }
  70 +
  71 + @Override
  72 + public void deleteReceiptOrderDetailListByOrderId(Long orderId) {
  73 + receiptOrderDetailMapper.deleteByOrderId(orderId);
  74 + }
  75 +
  76 + @Override
  77 + public List<WmsReceiptOrderDetailDO> getReceiptOrderDetailList(Long orderId) {
  78 + return receiptOrderDetailMapper.selectListByOrderId(orderId);
  79 + }
  80 +
  81 + @Override
  82 + public List<WmsReceiptOrderDetailDO> getReceiptOrderDetailList(Collection<Long> orderIds) {
  83 + if (CollUtil.isEmpty(orderIds)) {
  84 + return ListUtil.of();
  85 + }
  86 + return receiptOrderDetailMapper.selectListByOrderIds(orderIds);
  87 + }
  88 +
  89 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/receipt/WmsReceiptOrderService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.receipt;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order.WmsReceiptOrderPageReqVO;
  5 +import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order.WmsReceiptOrderSaveReqVO;
  6 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDO;
  7 +import jakarta.validation.Valid;
  8 +
  9 +/**
  10 + * WMS 入库单 Service 接口
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +public interface WmsReceiptOrderService {
  15 +
  16 + /**
  17 + * 创建入库单
  18 + *
  19 + * @param createReqVO 创建信息
  20 + * @return 编号
  21 + */
  22 + Long createReceiptOrder(@Valid WmsReceiptOrderSaveReqVO createReqVO);
  23 +
  24 + /**
  25 + * 更新入库单
  26 + *
  27 + * @param updateReqVO 更新信息
  28 + */
  29 + void updateReceiptOrder(@Valid WmsReceiptOrderSaveReqVO updateReqVO);
  30 +
  31 + /**
  32 + * 删除入库单
  33 + *
  34 + * @param id 编号
  35 + */
  36 + void deleteReceiptOrder(Long id);
  37 +
  38 + /**
  39 + * 完成入库
  40 + *
  41 + * @param id 编号
  42 + */
  43 + void completeReceiptOrder(Long id);
  44 +
  45 + /**
  46 + * 作废入库单
  47 + *
  48 + * @param id 编号
  49 + */
  50 + void cancelReceiptOrder(Long id);
  51 +
  52 + /**
  53 + * 获得入库单
  54 + *
  55 + * @param id 编号
  56 + * @return 入库单
  57 + */
  58 + WmsReceiptOrderDO getReceiptOrder(Long id);
  59 +
  60 + /**
  61 + * 获得入库单分页
  62 + *
  63 + * @param pageReqVO 分页查询
  64 + * @return 入库单分页
  65 + */
  66 + PageResult<WmsReceiptOrderDO> getReceiptOrderPage(WmsReceiptOrderPageReqVO pageReqVO);
  67 +
  68 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/receipt/WmsReceiptOrderServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.receipt;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.collection.ListUtil;
  5 +import cn.hutool.core.util.ObjectUtil;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  8 +import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order.WmsReceiptOrderPageReqVO;
  9 +import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order.WmsReceiptOrderSaveReqVO;
  10 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.merchant.WmsMerchantDO;
  11 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO;
  12 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDO;
  13 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDetailDO;
  14 +import cn.iocoder.yudao.module.wms.dal.mysql.order.receipt.WmsReceiptOrderMapper;
  15 +import cn.iocoder.yudao.module.wms.enums.inventory.WmsInventoryOrderTypeEnum;
  16 +import cn.iocoder.yudao.module.wms.enums.md.WmsMerchantTypeEnum;
  17 +import cn.iocoder.yudao.module.wms.enums.order.WmsReceiptOrderStatusEnum;
  18 +import cn.iocoder.yudao.module.wms.framework.config.WmsProperties;
  19 +import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryService;
  20 +import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO;
  21 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
  22 +import cn.iocoder.yudao.module.wms.service.md.merchant.WmsMerchantService;
  23 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseAreaService;
  24 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
  25 +import jakarta.annotation.Resource;
  26 +import org.springframework.stereotype.Service;
  27 +import org.springframework.transaction.annotation.Transactional;
  28 +import org.springframework.validation.annotation.Validated;
  29 +
  30 +import java.math.BigDecimal;
  31 +import java.util.List;
  32 +
  33 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  34 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  35 +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;
  36 +
  37 +/**
  38 + * WMS 入库单 Service 实现类
  39 + *
  40 + * @author 芋道源码
  41 + */
  42 +@Service
  43 +@Validated
  44 +public class WmsReceiptOrderServiceImpl implements WmsReceiptOrderService {
  45 +
  46 + private static final Long EMPTY_AREA_ID = 0L;
  47 +
  48 + @Resource
  49 + private WmsReceiptOrderMapper receiptOrderMapper;
  50 + @Resource
  51 + private WmsReceiptOrderDetailService receiptOrderDetailService;
  52 + @Resource
  53 + private WmsWarehouseService warehouseService;
  54 + @Resource
  55 + private WmsWarehouseAreaService warehouseAreaService;
  56 + @Resource
  57 + private WmsMerchantService merchantService;
  58 + @Resource
  59 + private WmsItemSkuService itemSkuService;
  60 + @Resource
  61 + private WmsInventoryService inventoryService;
  62 + @Resource
  63 + private WmsProperties wmsProperties;
  64 +
  65 + @Override
  66 + @Transactional(rollbackFor = Exception.class)
  67 + public Long createReceiptOrder(WmsReceiptOrderSaveReqVO createReqVO) {
  68 + return createReceiptOrder(createReqVO, false).getId();
  69 + }
  70 +
  71 + // TODO @AI:不需要 detailRequired 参数呀。。。(对齐 mes 的做法)
  72 + private WmsReceiptOrderDO createReceiptOrder(WmsReceiptOrderSaveReqVO createReqVO, boolean detailRequired) {
  73 + // 1. 校验入库单保存数据
  74 + validateReceiptOrderSaveData(createReqVO);
  75 + // TODO @AI:是不是(对齐 mes 的做法)
  76 + List<WmsReceiptOrderDetailDO> details = buildReceiptOrderDetailList(createReqVO, detailRequired);
  77 +
  78 + // 2.1 插入入库单
  79 + WmsReceiptOrderDO order = BeanUtils.toBean(createReqVO, WmsReceiptOrderDO.class);
  80 + order.setStatus(WmsReceiptOrderStatusEnum.PENDING.getStatus());
  81 + fillReceiptOrderTotal(order, details);
  82 + receiptOrderMapper.insert(order);
  83 + // 2.2 插入入库单明细
  84 + receiptOrderDetailService.createReceiptOrderDetailList(order.getId(), details);
  85 + return order;
  86 + }
  87 +
  88 + @Override
  89 + @Transactional(rollbackFor = Exception.class)
  90 + public void updateReceiptOrder(WmsReceiptOrderSaveReqVO updateReqVO) {
  91 + updateReceiptOrder(updateReqVO, false);
  92 + }
  93 +
  94 + @Override
  95 + @Transactional(rollbackFor = Exception.class)
  96 + public void deleteReceiptOrder(Long id) {
  97 + // 1. 校验存在,且暂存
  98 + WmsReceiptOrderDO order = validateReceiptOrderExists(id);
  99 + // TODO @AI:只有未“COMPLETED”不允许删除。
  100 + validateReceiptOrderPending(order);
  101 +
  102 + // 2.1 删除入库单
  103 + receiptOrderMapper.deleteById(id);
  104 + // 2.1 删除入库单明细
  105 + receiptOrderDetailService.deleteReceiptOrderDetailListByOrderId(id);
  106 + }
  107 +
  108 + @Override
  109 + @Transactional(rollbackFor = Exception.class)
  110 + public void completeReceiptOrder(Long id) {
  111 + // 1.1 校验存在,且未完成
  112 + WmsReceiptOrderDO order = validateReceiptOrderExists(id);
  113 + validateReceiptOrderPending(order);
  114 + // 1.2 校验入库单明细存在
  115 + List<WmsReceiptOrderDetailDO> details = validateReceiptOrderDetailExists(id);
  116 +
  117 + // 2.1 完成入库单
  118 + WmsReceiptOrderDO updateObj = new WmsReceiptOrderDO().setId(id).setStatus(WmsReceiptOrderStatusEnum.COMPLETED.getStatus());
  119 + receiptOrderMapper.updateById(updateObj);
  120 + // 2.2 写入库存
  121 + createInventory(order, details);
  122 + }
  123 +
  124 + @Override
  125 + @Transactional(rollbackFor = Exception.class)
  126 + public void cancelReceiptOrder(Long id) {
  127 + // 1. 校验存在,且未完成
  128 + WmsReceiptOrderDO order = validateReceiptOrderExists(id);
  129 + validateReceiptOrderPending(order);
  130 +
  131 + // 2. 作废入库单
  132 + receiptOrderMapper.updateById(new WmsReceiptOrderDO().setId(id)
  133 + .setStatus(WmsReceiptOrderStatusEnum.CANCELED.getStatus()));
  134 + }
  135 +
  136 + @Override
  137 + public WmsReceiptOrderDO getReceiptOrder(Long id) {
  138 + return receiptOrderMapper.selectById(id);
  139 + }
  140 +
  141 + @Override
  142 + public PageResult<WmsReceiptOrderDO> getReceiptOrderPage(WmsReceiptOrderPageReqVO pageReqVO) {
  143 + return receiptOrderMapper.selectPage(pageReqVO);
  144 + }
  145 +
  146 + private WmsReceiptOrderDO updateReceiptOrder(WmsReceiptOrderSaveReqVO updateReqVO, boolean detailRequired) {
  147 + // 1. 校验入库单保存数据
  148 + WmsReceiptOrderDO oldOrder = validateReceiptOrderExists(updateReqVO.getId());
  149 + validateReceiptOrderPending(oldOrder);
  150 + validateReceiptOrderSaveData(updateReqVO);
  151 + List<WmsReceiptOrderDetailDO> details = buildReceiptOrderDetailList(updateReqVO, detailRequired);
  152 +
  153 + // 2.1 更新入库单
  154 + WmsReceiptOrderDO updateObj = BeanUtils.toBean(updateReqVO, WmsReceiptOrderDO.class)
  155 + .setStatus(WmsReceiptOrderStatusEnum.PENDING.getStatus());
  156 + fillReceiptOrderTotal(updateObj, details);
  157 + receiptOrderMapper.updateById(updateObj);
  158 + // 2.2 更新入库单明细
  159 + receiptOrderDetailService.updateReceiptOrderDetailList(updateReqVO.getId(), details);
  160 + return updateObj;
  161 + }
  162 +
  163 + private void validateReceiptOrderSaveData(WmsReceiptOrderSaveReqVO reqVO) {
  164 + validateReceiptOrderNoUnique(reqVO.getId(), reqVO.getNo());
  165 + warehouseService.validateWarehouseExists(reqVO.getWarehouseId());
  166 + validateReceiptOrderMerchant(reqVO.getMerchantId());
  167 + reqVO.setAreaId(normalizeAreaId(reqVO.getAreaId(), reqVO.getWarehouseId(), false));
  168 + }
  169 +
  170 + private void validateReceiptOrderNoUnique(Long id, String no) {
  171 + WmsReceiptOrderDO order = receiptOrderMapper.selectByNo(no);
  172 + if (order == null) {
  173 + return;
  174 + }
  175 + if (id == null || ObjectUtil.notEqual(order.getId(), id)) {
  176 + throw exception(RECEIPT_ORDER_NO_DUPLICATE);
  177 + }
  178 + }
  179 +
  180 + private WmsReceiptOrderDO validateReceiptOrderExists(Long id) {
  181 + WmsReceiptOrderDO order = id == null ? null : receiptOrderMapper.selectById(id);
  182 + if (order == null) {
  183 + throw exception(RECEIPT_ORDER_NOT_EXISTS);
  184 + }
  185 + return order;
  186 + }
  187 +
  188 + private void validateReceiptOrderPending(WmsReceiptOrderDO order) {
  189 + if (ObjectUtil.notEqual(order.getStatus(), WmsReceiptOrderStatusEnum.PENDING.getStatus())) {
  190 + throw exception(RECEIPT_ORDER_STATUS_NOT_PENDING);
  191 + }
  192 + }
  193 +
  194 + private List<WmsReceiptOrderDetailDO> validateReceiptOrderDetailExists(Long id) {
  195 + List<WmsReceiptOrderDetailDO> details = receiptOrderDetailService.getReceiptOrderDetailList(id);
  196 + if (CollUtil.isEmpty(details)) {
  197 + throw exception(RECEIPT_ORDER_DETAIL_REQUIRED);
  198 + }
  199 + return details;
  200 + }
  201 +
  202 + private void validateReceiptOrderMerchant(Long merchantId) {
  203 + if (merchantId == null) {
  204 + return;
  205 + }
  206 + WmsMerchantDO merchant = merchantService.validateMerchantExists(merchantId);
  207 + if (ObjectUtil.notEqual(merchant.getType(), WmsMerchantTypeEnum.SUPPLIER.getType())
  208 + && ObjectUtil.notEqual(merchant.getType(), WmsMerchantTypeEnum.CUSTOMER_SUPPLIER.getType())) {
  209 + throw exception(RECEIPT_ORDER_MERCHANT_NOT_SUPPLIER);
  210 + }
  211 + }
  212 +
  213 + private List<WmsReceiptOrderDetailDO> buildReceiptOrderDetailList(WmsReceiptOrderSaveReqVO reqVO, boolean required) {
  214 + if (CollUtil.isEmpty(reqVO.getDetails())) {
  215 + if (required) {
  216 + throw exception(RECEIPT_ORDER_DETAIL_REQUIRED);
  217 + }
  218 + return ListUtil.of();
  219 + }
  220 + return convertList(reqVO.getDetails(), detail -> {
  221 + itemSkuService.validateItemSkuExists(detail.getSkuId());
  222 + WmsReceiptOrderDetailDO detailDO = BeanUtils.toBean(detail, WmsReceiptOrderDetailDO.class);
  223 + detailDO.setWarehouseId(reqVO.getWarehouseId());
  224 + detailDO.setAreaId(normalizeAreaId(detail.getAreaId() == null ? reqVO.getAreaId() : detail.getAreaId(),
  225 + reqVO.getWarehouseId(), required));
  226 + return detailDO;
  227 + });
  228 + }
  229 +
  230 + private Long normalizeAreaId(Long areaId, Long warehouseId, boolean required) {
  231 + if (!wmsProperties.isAreaEnabled()) {
  232 + return EMPTY_AREA_ID;
  233 + }
  234 + if (areaId == null || ObjectUtil.equal(areaId, EMPTY_AREA_ID)) {
  235 + if (required) {
  236 + throw exception(RECEIPT_ORDER_AREA_REQUIRED);
  237 + }
  238 + return EMPTY_AREA_ID;
  239 + }
  240 + WmsWarehouseAreaDO area = warehouseAreaService.validateWarehouseAreaExists(areaId);
  241 + if (ObjectUtil.notEqual(area.getWarehouseId(), warehouseId)) {
  242 + throw exception(RECEIPT_ORDER_AREA_NOT_MATCH_WAREHOUSE);
  243 + }
  244 + return areaId;
  245 + }
  246 +
  247 + // DONE @AI:保留手工总金额优先;未填写时按明细金额汇总回填。
  248 + // TODO @AI:前端自动计算。
  249 + private void fillReceiptOrderTotal(WmsReceiptOrderDO order, List<WmsReceiptOrderDetailDO> details) {
  250 + BigDecimal totalQuantity = BigDecimal.ZERO;
  251 + BigDecimal totalAmount = BigDecimal.ZERO;
  252 + for (WmsReceiptOrderDetailDO detail : details) {
  253 + totalQuantity = totalQuantity.add(detail.getQuantity());
  254 + totalAmount = totalAmount.add(detail.getAmount() == null ? BigDecimal.ZERO : detail.getAmount());
  255 + }
  256 + order.setTotalQuantity(totalQuantity);
  257 + if (order.getTotalAmount() == null) {
  258 + order.setTotalAmount(totalAmount);
  259 + }
  260 + }
  261 +
  262 + private void createInventory(WmsReceiptOrderDO order, List<WmsReceiptOrderDetailDO> details) {
  263 + List<WmsInventoryChangeReqDTO.Item> items = convertList(details, detail -> new WmsInventoryChangeReqDTO.Item()
  264 + .setSkuId(detail.getSkuId()).setWarehouseId(detail.getWarehouseId()).setAreaId(detail.getAreaId())
  265 + .setQuantity(detail.getQuantity()).setBatchNo(detail.getBatchNo())
  266 + .setProductionDate(detail.getProductionDate()).setExpirationDate(detail.getExpirationDate())
  267 + .setAmount(detail.getAmount()).setRemark(detail.getRemark()));
  268 + inventoryService.changeInventory(new WmsInventoryChangeReqDTO()
  269 + .setOrderId(order.getId()).setOrderNo(order.getNo())
  270 + .setOrderType(WmsInventoryOrderTypeEnum.RECEIPT.getType()).setItems(items));
  271 + }
  272 +
  273 +}
yudao-module-wms/src/test/java/cn/iocoder/yudao/module/wms/service/order/receipt/WmsReceiptOrderDetailServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.receipt;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  4 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDetailDO;
  5 +import cn.iocoder.yudao.module.wms.dal.mysql.order.receipt.WmsReceiptOrderDetailMapper;
  6 +import jakarta.annotation.Resource;
  7 +import org.junit.jupiter.api.Test;
  8 +import org.springframework.context.annotation.Import;
  9 +
  10 +import java.math.BigDecimal;
  11 +import java.util.List;
  12 +
  13 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  14 +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.RECEIPT_ORDER_DETAIL_NOT_EXISTS;
  15 +import static org.junit.jupiter.api.Assertions.assertEquals;
  16 +import static org.junit.jupiter.api.Assertions.assertNotNull;
  17 +import static org.junit.jupiter.api.Assertions.assertNull;
  18 +
  19 +@Import(WmsReceiptOrderDetailServiceImpl.class)
  20 +public class WmsReceiptOrderDetailServiceImplTest extends BaseDbUnitTest {
  21 +
  22 + @Resource
  23 + private WmsReceiptOrderDetailServiceImpl receiptOrderDetailService;
  24 +
  25 + @Resource
  26 + private WmsReceiptOrderDetailMapper receiptOrderDetailMapper;
  27 +
  28 + @Test
  29 + public void testCreateReceiptOrderDetailList_success() {
  30 + // mock 数据
  31 + Long orderId = 10L;
  32 + WmsReceiptOrderDetailDO detail01 = createReceiptOrderDetail(null, 1001L, "1.00");
  33 + WmsReceiptOrderDetailDO detail02 = createReceiptOrderDetail(null, 1002L, "2.00");
  34 +
  35 + // 调用
  36 + receiptOrderDetailService.createReceiptOrderDetailList(orderId, List.of(detail01, detail02));
  37 +
  38 + // 断言
  39 + List<WmsReceiptOrderDetailDO> details = receiptOrderDetailMapper.selectListByOrderId(orderId);
  40 + assertEquals(2, details.size());
  41 + assertEquals(orderId, details.get(0).getOrderId());
  42 + assertEquals(orderId, details.get(1).getOrderId());
  43 + }
  44 +
  45 + @Test
  46 + public void testCreateReceiptOrderDetailList_detailNotExists() {
  47 + // mock 数据
  48 + WmsReceiptOrderDetailDO detail = createReceiptOrderDetail(null, 1001L, "1.00");
  49 + detail.setId(999L);
  50 +
  51 + // 调用,并断言
  52 + assertServiceException(() -> receiptOrderDetailService.createReceiptOrderDetailList(10L, List.of(detail)),
  53 + RECEIPT_ORDER_DETAIL_NOT_EXISTS);
  54 + }
  55 +
  56 + @Test
  57 + public void testUpdateReceiptOrderDetailList_diff() {
  58 + // mock 数据
  59 + Long orderId = 10L;
  60 + WmsReceiptOrderDetailDO detail01 = createReceiptOrderDetail(orderId, 1001L, "1.00");
  61 + WmsReceiptOrderDetailDO detail02 = createReceiptOrderDetail(orderId, 1002L, "2.00");
  62 + receiptOrderDetailMapper.insert(detail01);
  63 + receiptOrderDetailMapper.insert(detail02);
  64 + WmsReceiptOrderDetailDO updateDetail = createReceiptOrderDetail(999L, 2001L, "11.00");
  65 + updateDetail.setId(detail01.getId());
  66 + WmsReceiptOrderDetailDO createDetail = createReceiptOrderDetail(null, 2002L, "22.00");
  67 +
  68 + // 调用
  69 + receiptOrderDetailService.updateReceiptOrderDetailList(orderId, List.of(updateDetail, createDetail));
  70 +
  71 + // 断言:修改
  72 + WmsReceiptOrderDetailDO dbUpdateDetail = receiptOrderDetailMapper.selectById(detail01.getId());
  73 + assertNotNull(dbUpdateDetail);
  74 + assertEquals(orderId, dbUpdateDetail.getOrderId());
  75 + assertEquals(2001L, dbUpdateDetail.getSkuId());
  76 + assertEquals(0, new BigDecimal("11.00").compareTo(dbUpdateDetail.getQuantity()));
  77 + // 断言:新增
  78 + List<WmsReceiptOrderDetailDO> details = receiptOrderDetailMapper.selectListByOrderId(orderId);
  79 + assertEquals(2, details.size());
  80 + WmsReceiptOrderDetailDO dbCreateDetail = details.stream()
  81 + .filter(detail -> Long.valueOf(2002L).equals(detail.getSkuId()))
  82 + .findFirst().orElse(null);
  83 + assertNotNull(dbCreateDetail);
  84 + assertEquals(orderId, dbCreateDetail.getOrderId());
  85 + assertEquals(0, new BigDecimal("22.00").compareTo(dbCreateDetail.getQuantity()));
  86 + // 断言:删除
  87 + assertNull(receiptOrderDetailMapper.selectById(detail02.getId()));
  88 + }
  89 +
  90 + @Test
  91 + public void testUpdateReceiptOrderDetailList_detailNotExists() {
  92 + // mock 数据
  93 + WmsReceiptOrderDetailDO detail = createReceiptOrderDetail(10L, 1001L, "1.00");
  94 + detail.setId(999L);
  95 +
  96 + // 调用,并断言
  97 + assertServiceException(() -> receiptOrderDetailService.updateReceiptOrderDetailList(10L, List.of(detail)),
  98 + RECEIPT_ORDER_DETAIL_NOT_EXISTS);
  99 + }
  100 +
  101 + private static WmsReceiptOrderDetailDO createReceiptOrderDetail(Long orderId, Long skuId, String quantity) {
  102 + return WmsReceiptOrderDetailDO.builder()
  103 + .orderId(orderId)
  104 + .skuId(skuId)
  105 + .warehouseId(100L)
  106 + .areaId(0L)
  107 + .quantity(new BigDecimal(quantity))
  108 + .amount(new BigDecimal("100.00"))
  109 + .build();
  110 + }
  111 +
  112 +}
yudao-module-wms/src/test/java/cn/iocoder/yudao/module/wms/service/order/receipt/WmsReceiptOrderServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.order.receipt;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  4 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDO;
  5 +import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDetailDO;
  6 +import cn.iocoder.yudao.module.wms.dal.mysql.order.receipt.WmsReceiptOrderDetailMapper;
  7 +import cn.iocoder.yudao.module.wms.dal.mysql.order.receipt.WmsReceiptOrderMapper;
  8 +import cn.iocoder.yudao.module.wms.enums.inventory.WmsInventoryOrderTypeEnum;
  9 +import cn.iocoder.yudao.module.wms.enums.order.WmsReceiptOrderStatusEnum;
  10 +import cn.iocoder.yudao.module.wms.enums.order.WmsReceiptOrderTypeEnum;
  11 +import cn.iocoder.yudao.module.wms.framework.config.WmsProperties;
  12 +import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryService;
  13 +import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO;
  14 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
  15 +import cn.iocoder.yudao.module.wms.service.md.merchant.WmsMerchantService;
  16 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseAreaService;
  17 +import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
  18 +import jakarta.annotation.Resource;
  19 +import org.junit.jupiter.api.Test;
  20 +import org.mockito.ArgumentCaptor;
  21 +import org.springframework.context.annotation.Import;
  22 +import org.springframework.test.context.bean.override.mockito.MockitoBean;
  23 +
  24 +import java.math.BigDecimal;
  25 +
  26 +import static org.junit.jupiter.api.Assertions.assertEquals;
  27 +import static org.junit.jupiter.api.Assertions.assertNotNull;
  28 +import static org.mockito.ArgumentMatchers.any;
  29 +import static org.mockito.Mockito.never;
  30 +import static org.mockito.Mockito.verify;
  31 +
  32 +@Import({WmsReceiptOrderServiceImpl.class, WmsReceiptOrderDetailServiceImpl.class, WmsProperties.class})
  33 +public class WmsReceiptOrderServiceImplTest extends BaseDbUnitTest {
  34 +
  35 + @Resource
  36 + private WmsReceiptOrderServiceImpl receiptOrderService;
  37 +
  38 + @Resource
  39 + private WmsReceiptOrderMapper receiptOrderMapper;
  40 + @Resource
  41 + private WmsReceiptOrderDetailMapper receiptOrderDetailMapper;
  42 +
  43 + @MockitoBean
  44 + private WmsWarehouseService warehouseService;
  45 + @MockitoBean
  46 + private WmsWarehouseAreaService warehouseAreaService;
  47 + @MockitoBean
  48 + private WmsMerchantService merchantService;
  49 + @MockitoBean
  50 + private WmsItemSkuService itemSkuService;
  51 + @MockitoBean
  52 + private WmsInventoryService inventoryService;
  53 +
  54 + @Test
  55 + public void testCompleteReceiptOrder_success() {
  56 + // mock 数据
  57 + Long warehouseId = 100L;
  58 + Long skuId = 200L;
  59 + WmsReceiptOrderDO order = createReceiptOrder(warehouseId);
  60 + receiptOrderMapper.insert(order);
  61 + receiptOrderDetailMapper.insert(createReceiptOrderDetail(order.getId(), skuId, warehouseId));
  62 +
  63 + // 调用
  64 + receiptOrderService.completeReceiptOrder(order.getId());
  65 +
  66 + // 断言:入库单
  67 + WmsReceiptOrderDO dbOrder = receiptOrderMapper.selectById(order.getId());
  68 + assertNotNull(dbOrder);
  69 + assertEquals(WmsReceiptOrderStatusEnum.COMPLETED.getStatus(), dbOrder.getStatus());
  70 + // 断言:库存变更
  71 + ArgumentCaptor<WmsInventoryChangeReqDTO> captor = ArgumentCaptor.forClass(WmsInventoryChangeReqDTO.class);
  72 + verify(inventoryService).changeInventory(captor.capture());
  73 + WmsInventoryChangeReqDTO inventoryReqDTO = captor.getValue();
  74 + assertEquals(order.getId(), inventoryReqDTO.getOrderId());
  75 + assertEquals(order.getNo(), inventoryReqDTO.getOrderNo());
  76 + assertEquals(WmsInventoryOrderTypeEnum.RECEIPT.getType(), inventoryReqDTO.getOrderType());
  77 + assertEquals(1, inventoryReqDTO.getItems().size());
  78 + assertEquals(skuId, inventoryReqDTO.getItems().get(0).getSkuId());
  79 + assertEquals(warehouseId, inventoryReqDTO.getItems().get(0).getWarehouseId());
  80 + assertEquals(0, new BigDecimal("2.00").compareTo(inventoryReqDTO.getItems().get(0).getQuantity()));
  81 + }
  82 +
  83 + @Test
  84 + public void testCancelReceiptOrder_success() {
  85 + // mock 数据
  86 + WmsReceiptOrderDO order = createReceiptOrder(100L);
  87 + receiptOrderMapper.insert(order);
  88 +
  89 + // 调用
  90 + receiptOrderService.cancelReceiptOrder(order.getId());
  91 +
  92 + // 断言
  93 + WmsReceiptOrderDO dbOrder = receiptOrderMapper.selectById(order.getId());
  94 + assertNotNull(dbOrder);
  95 + assertEquals(WmsReceiptOrderStatusEnum.CANCELED.getStatus(), dbOrder.getStatus());
  96 + verify(inventoryService, never()).changeInventory(any());
  97 + }
  98 +
  99 + private static WmsReceiptOrderDO createReceiptOrder(Long warehouseId) {
  100 + return new WmsReceiptOrderDO()
  101 + .setNo("RK202605120001")
  102 + .setType(WmsReceiptOrderTypeEnum.PURCHASE.getType())
  103 + .setStatus(WmsReceiptOrderStatusEnum.PENDING.getStatus())
  104 + .setWarehouseId(warehouseId)
  105 + .setAreaId(0L)
  106 + .setTotalQuantity(new BigDecimal("2.00"))
  107 + .setTotalAmount(new BigDecimal("20.00"));
  108 + }
  109 +
  110 + private static WmsReceiptOrderDetailDO createReceiptOrderDetail(Long orderId, Long skuId, Long warehouseId) {
  111 + return WmsReceiptOrderDetailDO.builder()
  112 + .orderId(orderId)
  113 + .skuId(skuId)
  114 + .warehouseId(warehouseId)
  115 + .areaId(0L)
  116 + .quantity(new BigDecimal("2.00"))
  117 + .amount(new BigDecimal("20.00"))
  118 + .build();
  119 + }
  120 +
  121 +}