diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/controller/ShipmentOrderController.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/controller/ShipmentOrderController.java index 65ce48c..daf5d15 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/controller/ShipmentOrderController.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/controller/ShipmentOrderController.java @@ -96,6 +96,19 @@ public class ShipmentOrderController extends BaseController { return R.ok(); } + /** + * 出库 + */ + @SaCheckPermission("wms:shipmentOrder:shipment") + @Log(title = "出库单", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/shipment") + public R shipment(@Validated(AddGroup.class) @RequestBody ShipmentOrderBo bo) { + bo.setShipmentOrderStatus(ServiceConstants.ShipmentOrderStatus.FINISH); + shipmentOrderService.shipment(bo); + return R.ok(); + } + /** * 删除出库单 * diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/InventoryBo.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/InventoryBo.java index 9751ee6..c73459c 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/InventoryBo.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/InventoryBo.java @@ -3,6 +3,7 @@ package com.ruoyi.wms.domain.bo; import com.ruoyi.common.core.validate.AddGroup; import com.ruoyi.common.core.validate.EditGroup; import com.ruoyi.common.mybatis.core.domain.BaseEntity; +import com.ruoyi.common.mybatis.core.domain.PlaceAndItem; import com.ruoyi.wms.domain.entity.Inventory; import io.github.linpeilie.annotations.AutoMapper; import jakarta.validation.constraints.NotBlank; @@ -22,7 +23,7 @@ import java.math.BigDecimal; @Data @EqualsAndHashCode(callSuper = true) @AutoMapper(target = Inventory.class, reverseConvertGenerate = false) -public class InventoryBo extends BaseEntity { +public class InventoryBo extends BaseEntity implements PlaceAndItem { /** * @@ -59,5 +60,15 @@ public class InventoryBo extends BaseEntity { */ private String remark; + /** + * 最小数量 + */ + private BigDecimal minQuantity; + + private String itemName; + private String itemCode; + private String skuName; + private String skuCode; + private Long itemCategory; } diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/InventoryDetailBo.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/InventoryDetailBo.java index dd152bc..cf7e227 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/InventoryDetailBo.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/InventoryDetailBo.java @@ -113,5 +113,7 @@ public class InventoryDetailBo extends BaseEntity { @NotNull(message = "剩余数量不能为空", groups = { AddGroup.class, EditGroup.class }) private BigDecimal remainQuantity; + /** 出库数量 */ + private BigDecimal shipmentQuantity; } diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/InventoryHistoryBo.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/InventoryHistoryBo.java index ec3d776..13ffe21 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/InventoryHistoryBo.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/InventoryHistoryBo.java @@ -11,6 +11,7 @@ import lombok.EqualsAndHashCode; import com.ruoyi.wms.domain.entity.InventoryHistory; import java.math.BigDecimal; +import java.time.LocalDateTime; /** * 库存记录业务对象 wms_inventory_history @@ -48,6 +49,26 @@ public class InventoryHistoryBo extends BaseEntity { @NotNull(message = "物料ID不能为空", groups = { AddGroup.class, EditGroup.class }) private Long skuId; + /** + * 批号 + */ + private String batchNumber; + + /** + * 生产日期 + */ + private LocalDateTime productionDate; + + /** + * 过期时间 + */ + private LocalDateTime expirationTime; + + /** + * 金额 + */ + private BigDecimal amount; + /** * 库存变化 */ diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ReceiptOrderDetailBo.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ReceiptOrderDetailBo.java index b68c534..c90f467 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ReceiptOrderDetailBo.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ReceiptOrderDetailBo.java @@ -3,7 +3,9 @@ package com.ruoyi.wms.domain.bo; import com.ruoyi.common.core.validate.AddGroup; import com.ruoyi.common.core.validate.EditGroup; import com.ruoyi.common.mybatis.core.domain.BaseEntity; +import com.ruoyi.wms.domain.entity.InventoryDetail; import io.github.linpeilie.annotations.AutoMapper; +import io.github.linpeilie.annotations.AutoMappers; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -22,7 +24,10 @@ import java.time.LocalDateTime; @Data @EqualsAndHashCode(callSuper = true) -@AutoMapper(target = ReceiptOrderDetail.class, reverseConvertGenerate = false) +@AutoMappers({ + @AutoMapper(target = ReceiptOrderDetail.class, reverseConvertGenerate = false), + @AutoMapper(target = InventoryDetail.class, reverseConvertGenerate = false) +}) public class ReceiptOrderDetailBo extends BaseEntity { /** diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ShipmentDataBo.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ShipmentDataBo.java new file mode 100644 index 0000000..e3922cf --- /dev/null +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ShipmentDataBo.java @@ -0,0 +1,15 @@ +package com.ruoyi.wms.domain.bo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ShipmentDataBo { + private List shipmentInventoryDetailList; + private List shipmentInventoryList; +} diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ShipmentOrderBo.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ShipmentOrderBo.java index 35ea98e..5d1868e 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ShipmentOrderBo.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ShipmentOrderBo.java @@ -67,6 +67,16 @@ public class ShipmentOrderBo extends BaseEntity { */ private Integer shipmentOrderStatus; + /** + * 仓库id + */ + private Long warehouseId; + + /** + * 库区id + */ + private Long areaId; + /** * 备注 */ diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ShipmentOrderDetailBo.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ShipmentOrderDetailBo.java index 6f3d32d..baa783a 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ShipmentOrderDetailBo.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/bo/ShipmentOrderDetailBo.java @@ -4,6 +4,7 @@ import com.ruoyi.wms.domain.entity.ShipmentOrderDetail; import com.ruoyi.common.core.validate.AddGroup; import com.ruoyi.common.core.validate.EditGroup; import com.ruoyi.common.mybatis.core.domain.BaseEntity; +import io.github.linpeilie.annotations.AutoMappers; import lombok.Data; import lombok.EqualsAndHashCode; import jakarta.validation.constraints.*; @@ -20,11 +21,14 @@ import java.math.BigDecimal; @Data @EqualsAndHashCode(callSuper = true) -@AutoMapper(target = ShipmentOrderDetail.class, reverseConvertGenerate = false) +@AutoMappers({ + @AutoMapper(target = ShipmentOrderDetail.class, reverseConvertGenerate = false), + @AutoMapper(target = InventoryBo.class, reverseConvertGenerate = false) +}) public class ShipmentOrderDetailBo extends BaseEntity { /** - * + * */ @NotNull(message = "不能为空", groups = { EditGroup.class }) private Long id; @@ -68,7 +72,6 @@ public class ShipmentOrderDetailBo extends BaseEntity { /** * 备注 */ - @NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class }) private String remark; diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/Inventory.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/Inventory.java index fdcf719..63a9d79 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/Inventory.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/Inventory.java @@ -3,6 +3,7 @@ package com.ruoyi.wms.domain.entity; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.ruoyi.common.mybatis.core.domain.BaseEntity; +import com.ruoyi.common.mybatis.core.domain.PlaceAndItem; import lombok.Data; import lombok.EqualsAndHashCode; @@ -18,7 +19,7 @@ import java.math.BigDecimal; @Data @EqualsAndHashCode(callSuper = true) @TableName("wms_inventory") -public class Inventory extends BaseEntity { +public class Inventory extends BaseEntity implements PlaceAndItem { @Serial private static final long serialVersionUID=1L; diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/InventoryDetail.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/InventoryDetail.java index 96bb7c6..2d25ae3 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/InventoryDetail.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/InventoryDetail.java @@ -3,6 +3,9 @@ package com.ruoyi.wms.domain.entity; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.ruoyi.common.mybatis.core.domain.BaseEntity; +import com.ruoyi.common.mybatis.core.domain.PlaceAndItem; +import com.ruoyi.wms.domain.bo.InventoryDetailBo; +import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; import lombok.EqualsAndHashCode; @@ -19,7 +22,8 @@ import java.time.LocalDateTime; @Data @EqualsAndHashCode(callSuper = true) @TableName("wms_inventory_detail") -public class InventoryDetail extends BaseEntity { +@AutoMapper(target = InventoryDetailBo.class, reverseConvertGenerate = false) +public class InventoryDetail extends BaseEntity implements PlaceAndItem { @Serial private static final long serialVersionUID=1L; diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/InventoryHistory.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/InventoryHistory.java index 75dfd79..86de69f 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/InventoryHistory.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/InventoryHistory.java @@ -8,6 +8,7 @@ import lombok.EqualsAndHashCode; import java.io.Serial; import java.math.BigDecimal; +import java.time.LocalDateTime; /** * 库存记录对象 wms_inventory_history @@ -40,6 +41,22 @@ public class InventoryHistory extends BaseEntity { * 物料ID */ private Long skuId; + /** + * 批号 + */ + private String batchNumber; + /** + * 生产日期 + */ + private LocalDateTime productionDate; + /** + * 过期时间 + */ + private LocalDateTime expirationTime; + /** + * 金额 + */ + private BigDecimal amount; /** * 库存变化 */ diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/ShipmentOrder.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/ShipmentOrder.java index bb5917d..67625b8 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/ShipmentOrder.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/entity/ShipmentOrder.java @@ -56,6 +56,14 @@ public class ShipmentOrder extends BaseEntity { * 出库单状态 */ private Integer shipmentOrderStatus; + /** + * 仓库id + */ + private Long warehouseId; + /** + * 库区id + */ + private Long areaId; /** * 备注 */ diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/vo/InventoryHistoryVo.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/vo/InventoryHistoryVo.java index 5ca39e9..4840c26 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/vo/InventoryHistoryVo.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/vo/InventoryHistoryVo.java @@ -11,6 +11,7 @@ import lombok.Data; import java.io.Serial; import java.io.Serializable; import java.math.BigDecimal; +import java.time.LocalDateTime; /** * 库存记录视图对象 wms_inventory_history @@ -51,6 +52,30 @@ public class InventoryHistoryVo implements Serializable { @ExcelProperty(value = "物料ID") private Long skuId; + /** + * 批号 + */ + @ExcelProperty(value = "批号") + private String batchNumber; + + /** + * 生产日期 + */ + @ExcelProperty(value = "生产日期") + private LocalDateTime productionDate; + + /** + * 过期时间 + */ + @ExcelProperty(value = "过期时间") + private LocalDateTime expirationTime; + + /** + * 金额 + */ + @ExcelProperty(value = "金额") + private BigDecimal amount; + /** * 库存变化 */ diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/vo/InventoryVo.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/vo/InventoryVo.java index 8def68e..3ee494d 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/vo/InventoryVo.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/vo/InventoryVo.java @@ -60,5 +60,8 @@ public class InventoryVo implements Serializable { @ExcelProperty(value = "备注") private String remark; + private ItemSkuVo itemSku; + + private ItemVo item; } diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/vo/ShipmentOrderVo.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/vo/ShipmentOrderVo.java index 4cd0c5f..ad4101e 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/vo/ShipmentOrderVo.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/domain/vo/ShipmentOrderVo.java @@ -1,6 +1,8 @@ package com.ruoyi.wms.domain.vo; import java.math.BigDecimal; + +import com.ruoyi.common.mybatis.core.domain.BaseEntity; import com.ruoyi.wms.domain.entity.ShipmentOrder; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; @@ -21,13 +23,13 @@ import java.io.Serial; @Data @ExcelIgnoreUnannotated @AutoMapper(target = ShipmentOrder.class) -public class ShipmentOrderVo implements Serializable { +public class ShipmentOrderVo extends BaseEntity implements Serializable { @Serial private static final long serialVersionUID = 1L; /** - * + * */ @ExcelProperty(value = "") private Long id; @@ -74,6 +76,18 @@ public class ShipmentOrderVo implements Serializable { @ExcelProperty(value = "出库单状态") private Integer shipmentOrderStatus; + /** + * 仓库id + */ + @ExcelProperty(value = "仓库id") + private Long warehouseId; + + /** + * 库区id + */ + @ExcelProperty(value = "库区id") + private Long areaId; + /** * 备注 */ diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/mapper/InventoryDetailMapper.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/mapper/InventoryDetailMapper.java index 79d5eca..0fb7474 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/mapper/InventoryDetailMapper.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/mapper/InventoryDetailMapper.java @@ -1,8 +1,13 @@ package com.ruoyi.wms.mapper; import com.ruoyi.common.mybatis.core.mapper.BaseMapperPlus; +import com.ruoyi.wms.domain.bo.InventoryDetailBo; import com.ruoyi.wms.domain.entity.InventoryDetail; import com.ruoyi.wms.domain.vo.InventoryDetailVo; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.List; /** * 库存详情Mapper接口 @@ -11,5 +16,5 @@ import com.ruoyi.wms.domain.vo.InventoryDetailVo; * @date 2024-07-22 */ public interface InventoryDetailMapper extends BaseMapperPlus { - + void updateRemainQuantity(@Param("list")List list, @Param("updateBy") String updateBy, @Param("updateTime") LocalDateTime updateTime); } diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/mapper/InventoryMapper.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/mapper/InventoryMapper.java index 20059bf..2d83e13 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/mapper/InventoryMapper.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/mapper/InventoryMapper.java @@ -1,6 +1,8 @@ package com.ruoyi.wms.mapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.common.mybatis.core.mapper.BaseMapperPlus; +import com.ruoyi.wms.domain.bo.InventoryBo; import com.ruoyi.wms.domain.entity.Inventory; import org.apache.ibatis.annotations.Param; import com.ruoyi.wms.domain.vo.InventoryVo; @@ -16,4 +18,5 @@ import java.util.List; */ public interface InventoryMapper extends BaseMapperPlus { + Page selectVoPageByBo(Page page, @Param("bo") InventoryBo bo); } diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/InventoryDetailService.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/InventoryDetailService.java index 491e9a3..a3b3ff6 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/InventoryDetailService.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/InventoryDetailService.java @@ -1,13 +1,20 @@ package com.ruoyi.wms.service; +import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.common.core.exception.base.BaseException; import com.ruoyi.common.core.utils.MapstructUtils; import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.mybatis.core.domain.BaseEntity; +import com.ruoyi.common.mybatis.core.domain.PlaceAndItem; import com.ruoyi.common.mybatis.core.page.PageQuery; import com.ruoyi.common.mybatis.core.page.TableDataInfo; +import com.ruoyi.wms.domain.bo.InventoryBo; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import com.ruoyi.wms.domain.bo.InventoryDetailBo; @@ -15,9 +22,9 @@ import com.ruoyi.wms.domain.entity.InventoryDetail; import com.ruoyi.wms.domain.vo.InventoryDetailVo; import com.ruoyi.wms.mapper.InventoryDetailMapper; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; /** * 库存详情Service业务层处理 @@ -94,4 +101,68 @@ public class InventoryDetailService extends ServiceImpl ids) { inventoryDetailMapper.deleteBatchIds(ids); } + + /** + * 计算出库数据 + * @param warehouseId + * @param inventoryBoList + */ + public List calcShipmentInventoryDetailData(@NotNull Long warehouseId, @NotEmpty List inventoryBoList) { + LambdaQueryWrapper inventoryDetailLambdaQueryWrapper = Wrappers.lambdaQuery(); + inventoryDetailLambdaQueryWrapper.eq(InventoryDetail::getWarehouseId, warehouseId); + inventoryDetailLambdaQueryWrapper.in(InventoryDetail::getAreaId, inventoryBoList.stream().map(InventoryBo::getAreaId).toList()); + inventoryDetailLambdaQueryWrapper.gt(InventoryDetail::getRemainQuantity, 0); + inventoryDetailLambdaQueryWrapper.orderByAsc(InventoryDetail::getSkuId, InventoryDetail::getWarehouseId, InventoryDetail::getAreaId, BaseEntity::getCreateTime); + List inventoryDetailList = inventoryDetailMapper.selectList(inventoryDetailLambdaQueryWrapper); + if (CollUtil.isEmpty(inventoryDetailList)) { + throw new BaseException("库存不足"); + } + Set inventoryDetailSizeGroupByKey = inventoryDetailList.stream().map(PlaceAndItem::getKey).collect(Collectors.toSet()); + if (inventoryDetailSizeGroupByKey.size() < inventoryBoList.size()) { + throw new BaseException("库存不足"); + } + // 计算得到的出库数据集合 + List shipmentList = new LinkedList<>(); + // 本次需出库数map + Map needMap = inventoryBoList.stream().collect(Collectors.toMap(PlaceAndItem::getKey, InventoryBo::getQuantity)); + String lastKey = ""; + for (InventoryDetail detail : inventoryDetailList) { + String currentKey = detail.getKey(); + if (!needMap.containsKey(currentKey)) { + continue; + } + BigDecimal needQuantity = needMap.get(currentKey); + if (lastKey.equals(currentKey) && needQuantity.compareTo(BigDecimal.ZERO) > 0) { + // 该位置下商品还有入库明细,看下需要出库的数量是否为0,大于0继续出,小于等于0直接跳过 + allocateShipmentData(needMap, needQuantity, currentKey, MapstructUtils.convert(detail, InventoryDetailBo.class), shipmentList); + } else if (!lastKey.equals(currentKey)) { + // 如果不一样,看下上一个位置下的商品剩余数是否为0,不为0则库存不足了 + if (!"".equals(lastKey) && needMap.get(lastKey).compareTo(BigDecimal.ZERO) > 0) { + throw new BaseException("库存不足"); + } + // 上一个足够,继续下一个 + allocateShipmentData(needMap, needQuantity, currentKey, MapstructUtils.convert(detail, InventoryDetailBo.class), shipmentList); + } + lastKey = currentKey; + } + return shipmentList; + } + + /** + * 分配出库的inventoryDetail + * @param needMap 所需出库数据map + * @param needQuantity 所需出库数 + * @param currentKey 当前key + * @param detail 当前入库记录 + * @param shipmentInventoryDetailDataBoList 最终分配数据集 + */ + private void allocateShipmentData(Map needMap, BigDecimal needQuantity, String currentKey, InventoryDetailBo detail, List shipmentInventoryDetailDataBoList) { + // 计算这条入库明细可出多少数量 + BigDecimal shipmentQuantity = needQuantity.compareTo(detail.getRemainQuantity()) > 0 ? detail.getRemainQuantity() : needQuantity; + // 更新所需出库数据map + needMap.put(currentKey, needQuantity.subtract(shipmentQuantity)); + // 放入最终出库数据集 + detail.setShipmentQuantity(shipmentQuantity); + shipmentInventoryDetailDataBoList.add(detail); + } } diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/InventoryService.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/InventoryService.java index 6209303..9e7d905 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/InventoryService.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/InventoryService.java @@ -1,26 +1,34 @@ package com.ruoyi.wms.service; +import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.common.core.exception.base.BaseException; import com.ruoyi.common.core.utils.MapstructUtils; import com.ruoyi.common.core.utils.ValidatorUtils; import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.mybatis.core.domain.PlaceAndItem; import com.ruoyi.common.mybatis.core.page.PageQuery; import com.ruoyi.common.mybatis.core.page.TableDataInfo; -import com.ruoyi.wms.domain.bo.InventoryBo; +import com.ruoyi.wms.domain.bo.*; import com.ruoyi.wms.domain.entity.Inventory; import com.ruoyi.wms.domain.vo.InventoryVo; import com.ruoyi.wms.mapper.InventoryMapper; import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; +import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Collection; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; /** * 库存Service业务层处理 @@ -33,6 +41,7 @@ import java.util.List; public class InventoryService extends ServiceImpl { private final InventoryMapper inventoryMapper; + private final InventoryDetailService inventoryDetailService; /** * 查询库存 @@ -45,8 +54,7 @@ public class InventoryService extends ServiceImpl { * 查询库存列表 */ public TableDataInfo queryPageList(InventoryBo bo, PageQuery pageQuery) { - LambdaQueryWrapper lqw = buildQueryWrapper(bo); - Page result = inventoryMapper.selectVoPage(pageQuery.build(), lqw); + Page result = inventoryMapper.selectVoPageByBo(pageQuery.build(), bo); return TableDataInfo.build(result); } @@ -145,4 +153,40 @@ public class InventoryService extends ServiceImpl { lqw.in(Inventory::getAreaId, areaIds); return inventoryMapper.exists(lqw); } + + /** + * 校验库存并计算出库数据 + * @param warehouseId + * @param inventoryBoList + */ + public ShipmentDataBo validateInventoryAndCalcShipmentData(@NotNull Long warehouseId, @NotEmpty List inventoryBoList) { + List shipmentInventoryList = validateInventoryAndCalcShipmentInventoryData(warehouseId, inventoryBoList); + List shipmentInventoryDetailList = inventoryDetailService.calcShipmentInventoryDetailData(warehouseId, inventoryBoList); + ShipmentDataBo shipmentDataBo = new ShipmentDataBo(shipmentInventoryDetailList, shipmentInventoryList); + return shipmentDataBo; + } + + public List validateInventoryAndCalcShipmentInventoryData(@NotNull Long warehouseId, @NotEmpty List inventoryBoList) { + LambdaQueryWrapper inventoryLambdaQueryWrapper = Wrappers.lambdaQuery(); + inventoryLambdaQueryWrapper.eq(Inventory::getWarehouseId, warehouseId); + inventoryLambdaQueryWrapper.in(Inventory::getAreaId, inventoryBoList.stream().map(InventoryBo::getAreaId).toList()); + inventoryLambdaQueryWrapper.gt(Inventory::getQuantity, 0); + List inventoryList = inventoryMapper.selectList(inventoryLambdaQueryWrapper); + if (CollUtil.isEmpty(inventoryList)) { + throw new BaseException("库存不足"); + } + Map inventoryMap = inventoryList.stream().collect(Collectors.toMap(PlaceAndItem::getKey, Function.identity())); + List shipmentData = new LinkedList<>(); + for (InventoryBo bo : inventoryBoList) { + Inventory inventory = inventoryMap.get(bo.getKey()); + if (inventory == null || inventory.getQuantity().compareTo(bo.getQuantity()) < 0) { + throw new BaseException("库存不足"); + } + InventoryBo addData = new InventoryBo(); + BeanUtils.copyProperties(bo, addData); + addData.setQuantity(bo.getQuantity().negate()); + shipmentData.add(addData); + } + return shipmentData; + } } diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/ReceiptOrderService.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/ReceiptOrderService.java index ab86c24..abf00fa 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/ReceiptOrderService.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/ReceiptOrderService.java @@ -171,6 +171,7 @@ public class ReceiptOrderService { inventoryDetail.setReceiptOrderId(bo.getId()); inventoryDetail.setOrderNo(bo.getOrderNo()); inventoryDetail.setType(ServiceConstants.InventoryDetailType.RECEIPT); + inventoryDetail.setRemainQuantity(inventoryDetail.getQuantity()); }); inventoryDetailService.saveBatch(inventoryDetailList); } diff --git a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/ShipmentOrderService.java b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/ShipmentOrderService.java index d660357..12cae35 100644 --- a/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/ShipmentOrderService.java +++ b/ruoyi-admin-wms/src/main/java/com/ruoyi/wms/service/ShipmentOrderService.java @@ -1,26 +1,30 @@ package com.ruoyi.wms.service; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.common.core.constant.ServiceConstants; +import com.ruoyi.common.core.exception.base.BaseException; import com.ruoyi.common.core.utils.MapstructUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.mybatis.core.page.PageQuery; import com.ruoyi.common.mybatis.core.page.TableDataInfo; -import com.ruoyi.wms.domain.bo.ShipmentOrderBo; -import com.ruoyi.wms.domain.bo.ShipmentOrderDetailBo; +import com.ruoyi.common.satoken.utils.LoginHelper; +import com.ruoyi.wms.domain.bo.*; +import com.ruoyi.wms.domain.entity.InventoryHistory; import com.ruoyi.wms.domain.entity.ShipmentOrder; import com.ruoyi.wms.domain.entity.ShipmentOrderDetail; import com.ruoyi.wms.domain.vo.ShipmentOrderVo; +import com.ruoyi.wms.mapper.InventoryDetailMapper; import com.ruoyi.wms.mapper.ShipmentOrderMapper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.time.LocalDateTime; +import java.util.*; /** * 出库单Service业务层处理 @@ -34,6 +38,9 @@ public class ShipmentOrderService { private final ShipmentOrderMapper shipmentOrderMapper; private final ShipmentOrderDetailService shipmentOrderDetailService; + private final InventoryService inventoryService; + private final InventoryDetailMapper inventoryDetailMapper; + private final InventoryHistoryService inventoryHistoryService; /** * 查询出库单 @@ -117,4 +124,53 @@ public class ShipmentOrderService { public void deleteByIds(Collection ids) { shipmentOrderMapper.deleteBatchIds(ids); } + + /** + * 出库 + * @param bo + */ + @Transactional + public void shipment(ShipmentOrderBo bo) { + // 1.校验 + validateBeforeShipment(bo); + // 2. 保存入库单和入库单明细 + if (Objects.isNull(bo.getId())) { + insertByBo(bo); + } else { + updateByBo(bo); + } + // 3.计算出库数据 + ShipmentDataBo shipmentDataBo = inventoryService.validateInventoryAndCalcShipmentData(bo.getWarehouseId(), MapstructUtils.convert(bo.getDetails(), InventoryBo.class)); + // 4.更新库存 + inventoryService.updateInventoryQuantity(shipmentDataBo.getShipmentInventoryList()); + // 5.更新入库记录剩余数 + inventoryDetailMapper.updateRemainQuantity(shipmentDataBo.getShipmentInventoryDetailList(), LoginHelper.getUsername(), LocalDateTime.now()); + // 6.创建出库记录 + saveInventoryHistory(shipmentDataBo.getShipmentInventoryDetailList(), bo); + } + + private void saveInventoryHistory(List list, ShipmentOrderBo bo){ + List inventoryHistoryList = new LinkedList<>(); + list.forEach(detail -> { + InventoryHistory inventoryHistory = new InventoryHistory(); + inventoryHistory.setFormId(bo.getId()); + inventoryHistory.setFormType(bo.getShipmentOrderType()); + inventoryHistory.setSkuId(detail.getSkuId()); + inventoryHistory.setQuantity(detail.getQuantity()); + inventoryHistory.setWarehouseId(detail.getWarehouseId()); + inventoryHistory.setAreaId(detail.getAreaId()); + inventoryHistory.setBatchNumber(detail.getBatchNumber()); + inventoryHistory.setProductionDate(detail.getProductionDate()); + inventoryHistory.setExpirationTime(detail.getExpirationTime()); + inventoryHistory.setAmount(detail.getAmount()); + inventoryHistoryList.add(inventoryHistory); + }); + inventoryHistoryService.saveBatch(inventoryHistoryList); + } + + private void validateBeforeShipment(ShipmentOrderBo bo) { + if (CollUtil.isEmpty(bo.getDetails())) { + throw new BaseException("商品明细不能为空!"); + } + } } diff --git a/ruoyi-admin-wms/src/main/resources/mapper/wms/InventoryDetailMapper.xml b/ruoyi-admin-wms/src/main/resources/mapper/wms/InventoryDetailMapper.xml index 274629d..ef74008 100644 --- a/ruoyi-admin-wms/src/main/resources/mapper/wms/InventoryDetailMapper.xml +++ b/ruoyi-admin-wms/src/main/resources/mapper/wms/InventoryDetailMapper.xml @@ -3,5 +3,22 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - + + update wms_inventory_detail + set remain_quantity = remain_quantity - + ( + case + + when id = #{it.id} then #{it.shipmentQuantity} + + end + ) + , + update_time = #{updateTime}, + update_by = #{updateBy} + where id in + + #{it.id} + + diff --git a/ruoyi-admin-wms/src/main/resources/mapper/wms/InventoryMapper.xml b/ruoyi-admin-wms/src/main/resources/mapper/wms/InventoryMapper.xml index 2d97bcd..2a3e51f 100644 --- a/ruoyi-admin-wms/src/main/resources/mapper/wms/InventoryMapper.xml +++ b/ruoyi-admin-wms/src/main/resources/mapper/wms/InventoryMapper.xml @@ -4,4 +4,45 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + + + + + + diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/ruoyi/common/mybatis/core/domain/PlaceAndItem.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/ruoyi/common/mybatis/core/domain/PlaceAndItem.java new file mode 100644 index 0000000..56a4655 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/ruoyi/common/mybatis/core/domain/PlaceAndItem.java @@ -0,0 +1,14 @@ +package com.ruoyi.common.mybatis.core.domain; + +public interface PlaceAndItem { + + Long getWarehouseId(); + + Long getAreaId(); + + Long getSkuId(); + + default String getKey() { + return getWarehouseId() + "_" + getAreaId() + "_" + getSkuId(); + } +}