✨ ERP:增加入库单的审批功能
This commit is contained in:
parent
bfe3dc95fe
commit
593e1fd59c
@ -288,11 +288,16 @@ public class CollectionUtils {
|
||||
|
||||
public static <T, V extends Comparable<? super V>> V getSumValue(List<T> from, Function<T, V> valueFunc,
|
||||
BinaryOperator<V> accumulator) {
|
||||
return getSumValue(from, valueFunc, accumulator, null);
|
||||
}
|
||||
|
||||
public static <T, V extends Comparable<? super V>> V getSumValue(List<T> from, Function<T, V> valueFunc,
|
||||
BinaryOperator<V> accumulator, V defaultValue) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return null;
|
||||
return defaultValue;
|
||||
}
|
||||
assert from.size() > 0; // 断言,避免告警
|
||||
return from.stream().map(valueFunc).reduce(accumulator).get();
|
||||
assert !from.isEmpty(); // 断言,避免告警
|
||||
return from.stream().map(valueFunc).filter(Objects::nonNull).reduce(accumulator).orElse(defaultValue);
|
||||
}
|
||||
|
||||
public static <T> void addIfNotNull(Collection<T> coll, T item) {
|
||||
@ -302,8 +307,8 @@ public class CollectionUtils {
|
||||
coll.add(item);
|
||||
}
|
||||
|
||||
public static <T> Collection<T> singleton(T deptId) {
|
||||
return deptId == null ? Collections.emptyList() : Collections.singleton(deptId);
|
||||
public static <T> Collection<T> singleton(T obj) {
|
||||
return obj == null ? Collections.emptyList() : Collections.singleton(obj);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
package cn.iocoder.yudao.framework.common.util.number;
|
||||
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 数字的工具类,补全 {@link cn.hutool.core.util.NumberUtil} 的功能
|
||||
*
|
||||
@ -37,4 +40,21 @@ public class NumberUtils {
|
||||
return distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供精确的乘法运算
|
||||
*
|
||||
* 和 hutool {@link NumberUtil#mul(BigDecimal...)} 的差别是,如果存在 null,则返回 null
|
||||
*
|
||||
* @param values 多个被乘值
|
||||
* @return 积
|
||||
*/
|
||||
public static BigDecimal mul(BigDecimal... values) {
|
||||
for (BigDecimal value : values) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return NumberUtil.mul(values);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode SUPPLIER_NOT_EXISTS = new ErrorCode(1_030_100_000, "供应商不存在");
|
||||
ErrorCode SUPPLIER_NOT_ENABLE = new ErrorCode(1_030_100_000, "供应商({})未启用");
|
||||
|
||||
// ========== 销售订单(1-030-200-000) ==========
|
||||
// ========== ERP 销售订单(1-030-200-000) ==========
|
||||
ErrorCode SALE_ORDER_NOT_EXISTS = new ErrorCode(1_020_200_000, "销售订单不存在");
|
||||
|
||||
// ========== ERP 仓库 1-030-400-000 ==========
|
||||
@ -22,6 +22,10 @@ public interface ErrorCodeConstants {
|
||||
|
||||
// ========== ERP 其它入库单 1-030-401-000 ==========
|
||||
ErrorCode STOCK_IN_NOT_EXISTS = new ErrorCode(1_030_401_000, "其它入库单不存在");
|
||||
ErrorCode STOCK_IN_DELETE_FAIL_APPROVE = new ErrorCode(1_030_401_001, "其它入库单({})已审核,无法删除");
|
||||
ErrorCode STOCK_IN_PROCESS_FAIL = new ErrorCode(1_030_401_002, "反审核失败,只有已审核的入库单才能反审核");
|
||||
ErrorCode STOCK_IN_APPROVE_FAIL = new ErrorCode(1_030_401_003, "审核失败,只有未审核的入库单才能审核");
|
||||
|
||||
|
||||
// ========== ERP 产品 1-030-500-000 ==========
|
||||
ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在");
|
||||
|
@ -75,12 +75,21 @@ public class ErpStockInController {
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update-status")
|
||||
@Operation(summary = "更新其它入库单的状态")
|
||||
@PreAuthorize("@ss.hasPermission('erp:stock-in:update')")
|
||||
public CommonResult<Boolean> updateStockInStatus(@RequestParam("id") Long id,
|
||||
@RequestParam("status") Integer status) {
|
||||
stockInService.updateStockInStatus(id, status);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除其它入库单")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@Parameter(name = "ids", description = "编号数组", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('erp:stock-in:delete')")
|
||||
public CommonResult<Boolean> deleteStockIn(@RequestParam("id") Long id) {
|
||||
stockInService.deleteStockIn(id);
|
||||
public CommonResult<Boolean> deleteStockIn(@RequestParam("ids") List<Long> ids) {
|
||||
stockInService.deleteStockIn(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@ -93,12 +102,15 @@ public class ErpStockInController {
|
||||
if (stockIn == null) {
|
||||
return success(null);
|
||||
}
|
||||
List<ErpStockInItemDO> stockInItems = stockInService.getStockInItemListByInId(id);
|
||||
// TODO 芋艿:有个锤子;
|
||||
List<ErpStockInItemDO> stockInItemList = stockInService.getStockInItemListByInId(id);
|
||||
Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(
|
||||
convertSet(stockInItemList, ErpStockInItemDO::getProductId));
|
||||
return success(BeanUtils.toBean(stockIn, ErpStockInRespVO.class, stockInVO ->
|
||||
stockInVO.setItems(BeanUtils.toBean(stockInItems, ErpStockInRespVO.Item.class, item -> {
|
||||
stockInVO.setItems(BeanUtils.toBean(stockInItemList, ErpStockInRespVO.Item.class, item -> {
|
||||
ErpStockDO stock = stockService.getStock(item.getProductId(), item.getWarehouseId());
|
||||
item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO);
|
||||
MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName())
|
||||
.setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName()));
|
||||
}))));
|
||||
}
|
||||
|
||||
@ -142,8 +154,8 @@ public class ErpStockInController {
|
||||
// 2. 开始拼接
|
||||
return BeanUtils.toBean(pageResult, ErpStockInRespVO.class, stockIn -> {
|
||||
stockIn.setItems(BeanUtils.toBean(stockInItemMap.get(stockIn.getId()), ErpStockInRespVO.Item.class,
|
||||
item -> MapUtils.findAndThen(productMap, item.getProductId(),
|
||||
product -> item.setProductName(product.getName()).setProductUnitName(product.getUnitName()))));
|
||||
item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName())
|
||||
.setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName()))));
|
||||
stockIn.setProductNames(CollUtil.join(stockIn.getItems(), ",", ErpStockInRespVO.Item::getProductName));
|
||||
MapUtils.findAndThen(supplierMap, stockIn.getSupplierId(), supplier -> stockIn.setSupplierName(supplier.getName()));
|
||||
MapUtils.findAndThen(userMap, Long.parseLong(stockIn.getCreator()), user -> stockIn.setCreatorName(user.getNickname()));
|
||||
|
@ -97,6 +97,8 @@ public class ErpStockInRespVO {
|
||||
|
||||
@Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力")
|
||||
private String productName;
|
||||
@Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985")
|
||||
private String productBarCode;
|
||||
@Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "盒")
|
||||
private String productUnitName;
|
||||
|
||||
|
@ -53,8 +53,7 @@ public class ErpStockInSaveReqVO {
|
||||
@NotNull(message = "产品编号不能为空")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
|
||||
@NotNull(message = "产品单价不能为空")
|
||||
@Schema(description = "产品单价", example = "100.00")
|
||||
private BigDecimal productPrice;
|
||||
|
||||
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
|
||||
|
@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
|
||||
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO;
|
||||
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO;
|
||||
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
@ -34,4 +35,9 @@ public interface ErpStockInMapper extends BaseMapperX<ErpStockInDO> {
|
||||
return selectJoinPage(reqVO, ErpStockInDO.class, query);
|
||||
}
|
||||
|
||||
default int updateByIdAndStatus(Long id, Integer status, ErpStockInDO updateObj) {
|
||||
return update(updateObj, new LambdaUpdateWrapper<ErpStockInDO>()
|
||||
.eq(ErpStockInDO::getId, id).eq(ErpStockInDO::getStatus, status));
|
||||
}
|
||||
|
||||
}
|
@ -33,11 +33,19 @@ public interface ErpStockInService {
|
||||
void updateStockIn(@Valid ErpStockInSaveReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 删除其它入库单
|
||||
* 更新其它入库单的状态
|
||||
*
|
||||
* @param id 编号
|
||||
* @param status 状态
|
||||
*/
|
||||
void deleteStockIn(Long id);
|
||||
void updateStockInStatus(Long id, Integer status);
|
||||
|
||||
/**
|
||||
* 删除其它入库单
|
||||
*
|
||||
* @param ids 编号数组
|
||||
*/
|
||||
void deleteStockIn(List<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得其它入库单
|
||||
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.erp.service.stock;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInPageReqVO;
|
||||
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.in.ErpStockInSaveReqVO;
|
||||
@ -26,9 +27,9 @@ import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_IN_NOT_EXISTS;
|
||||
|
||||
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
|
||||
|
||||
// TODO 芋艿:记录操作日志
|
||||
/**
|
||||
* ERP 其它入库单 Service 实现类
|
||||
*
|
||||
@ -62,9 +63,9 @@ public class ErpStockInServiceImpl implements ErpStockInService {
|
||||
ErpStockInDO stockIn = BeanUtils.toBean(createReqVO, ErpStockInDO.class, in -> in
|
||||
.setStatus(ErpAuditStatus.PROCESS.getStatus())
|
||||
.setTotalCount(getSumValue(stockInItems, ErpStockInItemDO::getCount, BigDecimal::add))
|
||||
.setTotalPrice(getSumValue(stockInItems, ErpStockInItemDO::getTotalPrice, BigDecimal::add)));
|
||||
.setTotalPrice(getSumValue(stockInItems, ErpStockInItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)));
|
||||
stockInMapper.insert(stockIn);
|
||||
// 2. 插入子表
|
||||
// 2.2 插入入库单项
|
||||
stockInItems.forEach(o -> o.setInId(stockIn.getId()));
|
||||
stockInItemMapper.insertBatch(stockInItems);
|
||||
return stockIn.getId();
|
||||
@ -89,6 +90,28 @@ public class ErpStockInServiceImpl implements ErpStockInService {
|
||||
updateStockInItemList(updateReqVO.getId(), stockInItems);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateStockInStatus(Long id, Integer 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 3. TODO 芋艿:调整库存记录
|
||||
}
|
||||
|
||||
private List<ErpStockInItemDO> validateStockInItems(List<ErpStockInSaveReqVO.Item> list) {
|
||||
// 1.1 校验产品存在
|
||||
List<ErpProductDO> productList = productService.validProductList(convertSet(list, ErpStockInSaveReqVO.Item::getProductId));
|
||||
@ -98,7 +121,7 @@ public class ErpStockInServiceImpl implements ErpStockInService {
|
||||
// 2. 转化为 ErpStockInItemDO 列表
|
||||
return convertList(list, o -> BeanUtils.toBean(o, ErpStockInItemDO.class, item -> item
|
||||
.setProductUnitId(productMap.get(item.getProductId()).getUnitId())
|
||||
.setTotalPrice(item.getProductPrice().multiply(item.getCount()))));
|
||||
.setTotalPrice(NumberUtils.mul(item.getProductPrice(), item.getCount()))));
|
||||
}
|
||||
|
||||
private void updateStockInItemList(Long id, List<ErpStockInItemDO> newList) {
|
||||
@ -122,21 +145,33 @@ public class ErpStockInServiceImpl implements ErpStockInService {
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteStockIn(Long id) {
|
||||
// 1. 校验存在
|
||||
validateStockInExists(id);
|
||||
// TODO 芋艿:校验一下;
|
||||
public void deleteStockIn(List<Long> ids) {
|
||||
// 1. 校验不处于已审批
|
||||
List<ErpStockInDO> stockIns = stockInMapper.selectBatchIds(ids);
|
||||
if (CollUtil.isEmpty(stockIns)) {
|
||||
return;
|
||||
}
|
||||
stockIns.forEach(stockIn -> {
|
||||
if (ErpAuditStatus.APPROVE.getStatus().equals(stockIn.getStatus())) {
|
||||
throw exception(STOCK_IN_DELETE_FAIL_APPROVE, stockIn.getNo());
|
||||
}
|
||||
});
|
||||
|
||||
// 2.1 删除
|
||||
stockInMapper.deleteById(id);
|
||||
// 2.2 删除子表
|
||||
stockInItemMapper.deleteByInId(id);
|
||||
// 2. 遍历删除,并记录操作日志
|
||||
stockIns.forEach(stockIn -> {
|
||||
// 2.1 删除入库单
|
||||
stockInMapper.deleteById(stockIn.getId());
|
||||
// 2.2 删除入库单项
|
||||
stockInItemMapper.deleteByInId(stockIn.getId());
|
||||
});
|
||||
}
|
||||
|
||||
private void validateStockInExists(Long id) {
|
||||
if (stockInMapper.selectById(id) == null) {
|
||||
private ErpStockInDO validateStockInExists(Long id) {
|
||||
ErpStockInDO stockIn = stockInMapper.selectById(id);
|
||||
if (stockIn == null) {
|
||||
throw exception(STOCK_IN_NOT_EXISTS);
|
||||
}
|
||||
return stockIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -149,7 +184,7 @@ public class ErpStockInServiceImpl implements ErpStockInService {
|
||||
return stockInMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
// ==================== 子表(ERP 其它入库单项) ====================
|
||||
// ==================== 入库项 ====================
|
||||
|
||||
@Override
|
||||
public List<ErpStockInItemDO> getStockInItemListByInId(Long inId) {
|
||||
|
Loading…
Reference in New Issue
Block a user