✨ ERP:增加库存变更记录
This commit is contained in:
parent
3479ef8123
commit
dbc6134f80
|
@ -27,6 +27,12 @@ public interface ErrorCodeConstants {
|
|||
ErrorCode STOCK_IN_APPROVE_FAIL = new ErrorCode(1_030_401_003, "审核失败,只有未审核的入库单才能审核");
|
||||
ErrorCode STOCK_IN_NO_EXISTS = new ErrorCode(1_030_401_004, "生成入库单失败,请重新提交");
|
||||
|
||||
// ========== ERP 其它出库单 1-030-402-000 ==========
|
||||
|
||||
// ========== ERP 产品库存 1-030-403-000 ==========
|
||||
ErrorCode STOCK_COUNT_NEGATIVE = new ErrorCode(1_030_403_000, "操作失败,产品当前库存:{},小于变更数量:{}");
|
||||
ErrorCode STOCK_COUNT_NEGATIVE2 = new ErrorCode(1_030_403_000, "操作失败,库存不足");
|
||||
|
||||
// ========== ERP 产品 1-030-500-000 ==========
|
||||
ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在");
|
||||
ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_030_500_001, "产品({})未启用");
|
||||
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.erp.dal.dataobject.stock;
|
|||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
|
||||
import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
@ -56,25 +57,25 @@ public class ErpStockRecordDO extends BaseDO {
|
|||
/**
|
||||
* 业务类型
|
||||
*
|
||||
* 枚举 {@link cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum}
|
||||
* 枚举 {@link ErpStockRecordBizTypeEnum}
|
||||
*/
|
||||
private Integer bizType;
|
||||
/**
|
||||
* 业务编号
|
||||
*
|
||||
* 例如说:TODO
|
||||
* 例如说:{@link ErpStockInDO#getId()}
|
||||
*/
|
||||
private Long bizId;
|
||||
/**
|
||||
* 业务项编号
|
||||
*
|
||||
* 例如说:TODO
|
||||
* 例如说:{@link ErpStockInItemDO#getId()}
|
||||
*/
|
||||
private Long bizItemId;
|
||||
/**
|
||||
* 业务单号
|
||||
*
|
||||
* 例如说:TODO
|
||||
* 例如说:{@link ErpStockInDO#getNo()}
|
||||
*/
|
||||
private String bizNo;
|
||||
|
||||
|
|
|
@ -5,8 +5,11 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
|||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO;
|
||||
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* ERP 产品库存 Mapper
|
||||
*
|
||||
|
@ -27,4 +30,18 @@ public interface ErpStockMapper extends BaseMapperX<ErpStockDO> {
|
|||
ErpStockDO::getWarehouseId, warehouseId);
|
||||
}
|
||||
|
||||
default int updateCountIncrement(Long id, BigDecimal count, boolean negativeEnable) {
|
||||
LambdaUpdateWrapper<ErpStockDO> updateWrapper = new LambdaUpdateWrapper<ErpStockDO>()
|
||||
.eq(ErpStockDO::getId, id);
|
||||
if (count.compareTo(BigDecimal.ZERO) > 0) {
|
||||
updateWrapper.setSql("count = count + " + count);
|
||||
} else if (count.compareTo(BigDecimal.ZERO) < 0) {
|
||||
if (!negativeEnable) {
|
||||
updateWrapper.gt(ErpStockDO::getCount, count.abs());
|
||||
}
|
||||
updateWrapper.setSql("count = count - " + count.abs());
|
||||
}
|
||||
return update(null, updateWrapper);
|
||||
}
|
||||
|
||||
}
|
|
@ -13,8 +13,10 @@ import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInItemMapper;
|
|||
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInMapper;
|
||||
import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO;
|
||||
import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus;
|
||||
import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum;
|
||||
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
|
||||
import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService;
|
||||
import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockInCreateReqBO;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
@ -54,6 +56,8 @@ public class ErpStockInServiceImpl implements ErpStockInService {
|
|||
private ErpWarehouseService warehouseService;
|
||||
@Resource
|
||||
private ErpSupplierService supplierService;
|
||||
@Resource
|
||||
private ErpStockRecordService stockRecordService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
|
@ -102,23 +106,31 @@ public class ErpStockInServiceImpl implements ErpStockInService {
|
|||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateStockInStatus(Long id, Integer status) {
|
||||
boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status);
|
||||
// 1.1 校验存在
|
||||
ErpStockInDO stockIn = validateStockInExists(id);
|
||||
// 1.2 校验状态
|
||||
if (stockIn.getStatus().equals(status)) {
|
||||
throw exception(ErpAuditStatus.PROCESS.getStatus().equals(status) ?
|
||||
STOCK_IN_PROCESS_FAIL : STOCK_IN_APPROVE_FAIL);
|
||||
throw exception(approve ? STOCK_IN_APPROVE_FAIL : STOCK_IN_PROCESS_FAIL);
|
||||
}
|
||||
|
||||
// 2. 更新状态
|
||||
int updateCount = stockInMapper.updateByIdAndStatus(id, stockIn.getStatus(),
|
||||
new ErpStockInDO().setStatus(status));
|
||||
if (updateCount == 0) {
|
||||
throw exception(ErpAuditStatus.PROCESS.getStatus().equals(status) ?
|
||||
STOCK_IN_PROCESS_FAIL : STOCK_IN_APPROVE_FAIL);
|
||||
throw exception(approve ? STOCK_IN_APPROVE_FAIL : STOCK_IN_PROCESS_FAIL);
|
||||
}
|
||||
|
||||
// 3. TODO 芋艿:调整库存记录
|
||||
// 3. 变更库存
|
||||
List<ErpStockInItemDO> stockInItems = stockInItemMapper.selectListByInId(id);
|
||||
Integer bizType = approve ? ErpStockRecordBizTypeEnum.OTHER_IN.getType()
|
||||
: ErpStockRecordBizTypeEnum.OTHER_IN_CANCEL.getType();
|
||||
stockInItems.forEach(stockInItem -> {
|
||||
BigDecimal count = approve ? stockInItem.getCount() : stockInItem.getCount().negate();
|
||||
stockRecordService.createStockRecord(new ErpStockInCreateReqBO(
|
||||
stockInItem.getProductId(), stockInItem.getWarehouseId(), count,
|
||||
bizType, stockInItem.getInId(), stockInItem.getId(), stockIn.getNo()));
|
||||
});
|
||||
}
|
||||
|
||||
private List<ErpStockInItemDO> validateStockInItems(List<ErpStockInSaveReqVO.Item> list) {
|
||||
|
|
|
@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.erp.service.stock;
|
|||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO;
|
||||
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO;
|
||||
import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockInCreateReqBO;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
/**
|
||||
* ERP 产品库存明细 Service 接口
|
||||
|
@ -27,4 +29,11 @@ public interface ErpStockRecordService {
|
|||
*/
|
||||
PageResult<ErpStockRecordDO> getStockRecordPage(ErpStockRecordPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 创建库存明细
|
||||
*
|
||||
* @param createReqBO 创建库存明细 BO
|
||||
*/
|
||||
void createStockRecord(@Valid ErpStockInCreateReqBO createReqBO);
|
||||
|
||||
}
|
|
@ -1,13 +1,18 @@
|
|||
package cn.iocoder.yudao.module.erp.service.stock;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO;
|
||||
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO;
|
||||
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockRecordMapper;
|
||||
import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockInCreateReqBO;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* ERP 产品库存明细 Service 实现类
|
||||
*
|
||||
|
@ -20,6 +25,9 @@ public class ErpStockRecordServiceImpl implements ErpStockRecordService {
|
|||
@Resource
|
||||
private ErpStockRecordMapper stockRecordMapper;
|
||||
|
||||
@Resource
|
||||
private ErpStockService stockService;
|
||||
|
||||
@Override
|
||||
public ErpStockRecordDO getStockRecord(Long id) {
|
||||
return stockRecordMapper.selectById(id);
|
||||
|
@ -30,4 +38,16 @@ public class ErpStockRecordServiceImpl implements ErpStockRecordService {
|
|||
return stockRecordMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void createStockRecord(ErpStockInCreateReqBO createReqBO) {
|
||||
// 1. 更新库存
|
||||
BigDecimal totalCount = stockService.updateStockCountIncrement(
|
||||
createReqBO.getProductId(), createReqBO.getWarehouseId(), createReqBO.getCount());
|
||||
// 2. 创建库存明细
|
||||
ErpStockRecordDO stockRecord = BeanUtils.toBean(createReqBO, ErpStockRecordDO.class)
|
||||
.setTotalCount(totalCount);
|
||||
stockRecordMapper.insert(stockRecord);
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|||
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO;
|
||||
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* ERP 产品库存 Service 接口
|
||||
*
|
||||
|
@ -36,4 +38,14 @@ public interface ErpStockService {
|
|||
*/
|
||||
PageResult<ErpStockDO> getStockPage(ErpStockPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 增量更新产品库存数量
|
||||
*
|
||||
* @param productId 产品编号
|
||||
* @param warehouseId 仓库编号
|
||||
* @param count 增量数量:正数,表示增加;负数,表示减少
|
||||
* @return 更新后的库存
|
||||
*/
|
||||
BigDecimal updateStockCountIncrement(Long productId, Long warehouseId, BigDecimal count);
|
||||
|
||||
}
|
|
@ -8,6 +8,12 @@ import jakarta.annotation.Resource;
|
|||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_COUNT_NEGATIVE;
|
||||
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_COUNT_NEGATIVE2;
|
||||
|
||||
/**
|
||||
* ERP 产品库存 Service 实现类
|
||||
*
|
||||
|
@ -17,6 +23,13 @@ import org.springframework.validation.annotation.Validated;
|
|||
@Validated
|
||||
public class ErpStockServiceImpl implements ErpStockService {
|
||||
|
||||
/**
|
||||
* 允许库存为负数
|
||||
*
|
||||
* TODO 芋艿:后续做成 db 配置
|
||||
*/
|
||||
private static final Boolean NEGATIVE_STOCK_COUNT_ENABLE = false;
|
||||
|
||||
@Resource
|
||||
private ErpStockMapper stockMapper;
|
||||
|
||||
|
@ -35,4 +48,27 @@ public class ErpStockServiceImpl implements ErpStockService {
|
|||
return stockMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal updateStockCountIncrement(Long productId, Long warehouseId, BigDecimal count) {
|
||||
// 1.1 查询当前库存
|
||||
ErpStockDO stock = stockMapper.selectByProductIdAndWarehouseId(productId, warehouseId);
|
||||
if (stock == null) {
|
||||
stock = new ErpStockDO().setProductId(productId).setWarehouseId(warehouseId).setCount(BigDecimal.ZERO);
|
||||
stockMapper.insert(stock);
|
||||
}
|
||||
// 1.2 校验库存是否充足
|
||||
if (!NEGATIVE_STOCK_COUNT_ENABLE && stock.getCount().add(count).compareTo(BigDecimal.ZERO) < 0) {
|
||||
throw exception(STOCK_COUNT_NEGATIVE, stock.getCount(), count);
|
||||
}
|
||||
|
||||
// 2. 库存变更
|
||||
int updateCount = stockMapper.updateCountIncrement(stock.getId(), count, NEGATIVE_STOCK_COUNT_ENABLE);
|
||||
if (updateCount == 0) {
|
||||
throw exception(STOCK_COUNT_NEGATIVE2); // 此时不好去查询最新库存,所以直接抛出该提示,不提供具体库存数字
|
||||
}
|
||||
|
||||
// 3. 返回最新库存
|
||||
return stock.getCount().add(count);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package cn.iocoder.yudao.module.erp.service.stock.bo;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 库存明细的创建 Request BO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ErpStockInCreateReqBO {
|
||||
|
||||
/**
|
||||
* 产品编号
|
||||
*/
|
||||
@NotNull(message = "产品编号不能为空")
|
||||
private Long productId;
|
||||
/**
|
||||
* 仓库编号
|
||||
*/
|
||||
@NotNull(message = "仓库编号不能为空")
|
||||
private Long warehouseId;
|
||||
/**
|
||||
* 出入库数量
|
||||
*
|
||||
* 正数,表示入库;负数,表示出库
|
||||
*/
|
||||
@NotNull(message = "出入库数量不能为空")
|
||||
private BigDecimal count;
|
||||
|
||||
/**
|
||||
* 业务类型
|
||||
*/
|
||||
@NotNull(message = "业务类型不能为空")
|
||||
private Integer bizType;
|
||||
/**
|
||||
* 业务编号
|
||||
*/
|
||||
@NotNull(message = "业务编号不能为空")
|
||||
private Long bizId;
|
||||
/**
|
||||
* 业务项编号
|
||||
*/
|
||||
@NotNull(message = "业务项编号不能为空")
|
||||
private Long bizItemId;
|
||||
/**
|
||||
* 业务单号
|
||||
*/
|
||||
@NotNull(message = "业务单号不能为空")
|
||||
private String bizNo;
|
||||
|
||||
}
|
Loading…
Reference in New Issue