mirror of
https://github.com/zccbbg/wms-ruoyi.git
synced 2024-09-20 11:05:54 +08:00
feat: 出库和查询库存
This commit is contained in:
parent
52274b589f
commit
5e3d048cfe
|
@ -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<Void> shipment(@Validated(AddGroup.class) @RequestBody ShipmentOrderBo bo) {
|
||||
bo.setShipmentOrderStatus(ServiceConstants.ShipmentOrderStatus.FINISH);
|
||||
shipmentOrderService.shipment(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除出库单
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -113,5 +113,7 @@ public class InventoryDetailBo extends BaseEntity {
|
|||
@NotNull(message = "剩余数量不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private BigDecimal remainQuantity;
|
||||
|
||||
/** 出库数量 */
|
||||
private BigDecimal shipmentQuantity;
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* 库存变化
|
||||
*/
|
||||
|
|
|
@ -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 {
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<InventoryDetailBo> shipmentInventoryDetailList;
|
||||
private List<InventoryBo> shipmentInventoryList;
|
||||
}
|
|
@ -67,6 +67,16 @@ public class ShipmentOrderBo extends BaseEntity {
|
|||
*/
|
||||
private Integer shipmentOrderStatus;
|
||||
|
||||
/**
|
||||
* 仓库id
|
||||
*/
|
||||
private Long warehouseId;
|
||||
|
||||
/**
|
||||
* 库区id
|
||||
*/
|
||||
private Long areaId;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
/**
|
||||
* 库存变化
|
||||
*/
|
||||
|
|
|
@ -56,6 +56,14 @@ public class ShipmentOrder extends BaseEntity {
|
|||
* 出库单状态
|
||||
*/
|
||||
private Integer shipmentOrderStatus;
|
||||
/**
|
||||
* 仓库id
|
||||
*/
|
||||
private Long warehouseId;
|
||||
/**
|
||||
* 库区id
|
||||
*/
|
||||
private Long areaId;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* 库存变化
|
||||
*/
|
||||
|
|
|
@ -60,5 +60,8 @@ public class InventoryVo implements Serializable {
|
|||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
private ItemSkuVo itemSku;
|
||||
|
||||
private ItemVo item;
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
|
|
|
@ -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<InventoryDetail, InventoryDetailVo> {
|
||||
|
||||
void updateRemainQuantity(@Param("list")List<InventoryDetailBo> list, @Param("updateBy") String updateBy, @Param("updateTime") LocalDateTime updateTime);
|
||||
}
|
||||
|
|
|
@ -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<Inventory, InventoryVo> {
|
||||
|
||||
Page<InventoryVo> selectVoPageByBo(Page<Object> page, @Param("bo") InventoryBo bo);
|
||||
}
|
||||
|
|
|
@ -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<InventoryDetailMapper, I
|
|||
public void deleteByIds(Collection<Long> ids) {
|
||||
inventoryDetailMapper.deleteBatchIds(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算出库数据
|
||||
* @param warehouseId
|
||||
* @param inventoryBoList
|
||||
*/
|
||||
public List<InventoryDetailBo> calcShipmentInventoryDetailData(@NotNull Long warehouseId, @NotEmpty List<InventoryBo> inventoryBoList) {
|
||||
LambdaQueryWrapper<InventoryDetail> 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<InventoryDetail> inventoryDetailList = inventoryDetailMapper.selectList(inventoryDetailLambdaQueryWrapper);
|
||||
if (CollUtil.isEmpty(inventoryDetailList)) {
|
||||
throw new BaseException("库存不足");
|
||||
}
|
||||
Set<String> inventoryDetailSizeGroupByKey = inventoryDetailList.stream().map(PlaceAndItem::getKey).collect(Collectors.toSet());
|
||||
if (inventoryDetailSizeGroupByKey.size() < inventoryBoList.size()) {
|
||||
throw new BaseException("库存不足");
|
||||
}
|
||||
// 计算得到的出库数据集合
|
||||
List<InventoryDetailBo> shipmentList = new LinkedList<>();
|
||||
// 本次需出库数map
|
||||
Map<String, BigDecimal> 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<String, BigDecimal> needMap, BigDecimal needQuantity, String currentKey, InventoryDetailBo detail, List<InventoryDetailBo> shipmentInventoryDetailDataBoList) {
|
||||
// 计算这条入库明细可出多少数量
|
||||
BigDecimal shipmentQuantity = needQuantity.compareTo(detail.getRemainQuantity()) > 0 ? detail.getRemainQuantity() : needQuantity;
|
||||
// 更新所需出库数据map
|
||||
needMap.put(currentKey, needQuantity.subtract(shipmentQuantity));
|
||||
// 放入最终出库数据集
|
||||
detail.setShipmentQuantity(shipmentQuantity);
|
||||
shipmentInventoryDetailDataBoList.add(detail);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<InventoryMapper, Inventory> {
|
||||
|
||||
private final InventoryMapper inventoryMapper;
|
||||
private final InventoryDetailService inventoryDetailService;
|
||||
|
||||
/**
|
||||
* 查询库存
|
||||
|
@ -45,8 +54,7 @@ public class InventoryService extends ServiceImpl<InventoryMapper, Inventory> {
|
|||
* 查询库存列表
|
||||
*/
|
||||
public TableDataInfo<InventoryVo> queryPageList(InventoryBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<Inventory> lqw = buildQueryWrapper(bo);
|
||||
Page<InventoryVo> result = inventoryMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
Page<InventoryVo> result = inventoryMapper.selectVoPageByBo(pageQuery.build(), bo);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
|
@ -145,4 +153,40 @@ public class InventoryService extends ServiceImpl<InventoryMapper, Inventory> {
|
|||
lqw.in(Inventory::getAreaId, areaIds);
|
||||
return inventoryMapper.exists(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验库存并计算出库数据
|
||||
* @param warehouseId
|
||||
* @param inventoryBoList
|
||||
*/
|
||||
public ShipmentDataBo validateInventoryAndCalcShipmentData(@NotNull Long warehouseId, @NotEmpty List<InventoryBo> inventoryBoList) {
|
||||
List<InventoryBo> shipmentInventoryList = validateInventoryAndCalcShipmentInventoryData(warehouseId, inventoryBoList);
|
||||
List<InventoryDetailBo> shipmentInventoryDetailList = inventoryDetailService.calcShipmentInventoryDetailData(warehouseId, inventoryBoList);
|
||||
ShipmentDataBo shipmentDataBo = new ShipmentDataBo(shipmentInventoryDetailList, shipmentInventoryList);
|
||||
return shipmentDataBo;
|
||||
}
|
||||
|
||||
public List<InventoryBo> validateInventoryAndCalcShipmentInventoryData(@NotNull Long warehouseId, @NotEmpty List<InventoryBo> inventoryBoList) {
|
||||
LambdaQueryWrapper<Inventory> inventoryLambdaQueryWrapper = Wrappers.lambdaQuery();
|
||||
inventoryLambdaQueryWrapper.eq(Inventory::getWarehouseId, warehouseId);
|
||||
inventoryLambdaQueryWrapper.in(Inventory::getAreaId, inventoryBoList.stream().map(InventoryBo::getAreaId).toList());
|
||||
inventoryLambdaQueryWrapper.gt(Inventory::getQuantity, 0);
|
||||
List<Inventory> inventoryList = inventoryMapper.selectList(inventoryLambdaQueryWrapper);
|
||||
if (CollUtil.isEmpty(inventoryList)) {
|
||||
throw new BaseException("库存不足");
|
||||
}
|
||||
Map<String, Inventory> inventoryMap = inventoryList.stream().collect(Collectors.toMap(PlaceAndItem::getKey, Function.identity()));
|
||||
List<InventoryBo> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<Long> 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<InventoryDetailBo> list, ShipmentOrderBo bo){
|
||||
List<InventoryHistory> 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("商品明细不能为空!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,5 +3,22 @@
|
|||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.wms.mapper.InventoryDetailMapper">
|
||||
|
||||
<update id="updateRemainQuantity">
|
||||
update wms_inventory_detail
|
||||
set remain_quantity = remain_quantity -
|
||||
(
|
||||
case
|
||||
<foreach collection="list" item="it">
|
||||
when id = #{it.id} then #{it.shipmentQuantity}
|
||||
</foreach>
|
||||
end
|
||||
)
|
||||
,
|
||||
update_time = #{updateTime},
|
||||
update_by = #{updateBy}
|
||||
where id in
|
||||
<foreach collection="list" open="(" separator="," close=")" item="it">
|
||||
#{it.id}
|
||||
</foreach>
|
||||
</update>
|
||||
</mapper>
|
||||
|
|
|
@ -4,4 +4,45 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.wms.mapper.InventoryMapper">
|
||||
|
||||
<resultMap id="inventoryVoMap" type="com.ruoyi.wms.domain.vo.InventoryVo">
|
||||
<association property="itemSku" javaType="com.ruoyi.wms.domain.vo.ItemSkuVo" />
|
||||
<association property="item" javaType="com.ruoyi.wms.domain.vo.ItemVo" />
|
||||
</resultMap>
|
||||
|
||||
<select id="selectVoPageByBo" resultMap="inventoryVoMap">
|
||||
select
|
||||
inventory.*,
|
||||
sku.*,
|
||||
item.*
|
||||
from wms_inventory inventory
|
||||
inner join wms_item_sku sku on inventory.sku_id=sku.id
|
||||
inner join wms_item item on sku.item_id=item.id
|
||||
<where>
|
||||
<if test="bo.itemName != null and bo.itemName != ''">
|
||||
item.item_name like concat('%', #{bo.itemName}, '%')
|
||||
</if>
|
||||
<if test="bo.itemCode != null and bo.itemCode != ''">
|
||||
and item.item_code like concat('%', #{bo.itemCode}, '%')
|
||||
</if>
|
||||
<if test="bo.skuName != null and bo.skuName != ''">
|
||||
and sku.sku_name like concat('%', #{bo.skuName}, '%')
|
||||
</if>
|
||||
<if test="bo.skuCode != null and bo.skuCode != ''">
|
||||
and sku.sku_code like concat('%', #{bo.skuCode}, '%')
|
||||
</if>
|
||||
<if test="bo.itemCategory != null">
|
||||
and item.item_category=#{bo.itemCategory}
|
||||
</if>
|
||||
<if test="bo.warehouseId != null">
|
||||
and inventory.warehouse_id=#{bo.warehouseId}
|
||||
</if>
|
||||
<if test="bo.areaId != null">
|
||||
and inventory.area_id=#{bo.areaId}
|
||||
</if>
|
||||
<if test="bo.minQuantity != null">
|
||||
and inventory.quantity>=#{bo.minQuantity}
|
||||
</if>
|
||||
</where>
|
||||
order by inventory.warehouse_id,inventory.area_id,sku.item_id
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue