master
ljw 2026-01-17 16:30:00 +08:00
parent f0e5dda619
commit 84afc4c0e2
5 changed files with 253 additions and 7 deletions

View File

@ -3,6 +3,8 @@ package com.njzscloud.dispose.mfg.bom.controller;
import com.njzscloud.common.core.utils.R;
import com.njzscloud.common.mp.support.PageParam;
import com.njzscloud.common.mp.support.PageResult;
import com.njzscloud.dispose.mfg.bom.pojo.dto.BomAddDto;
import com.njzscloud.dispose.mfg.bom.pojo.dto.BomQueryDto;
import com.njzscloud.dispose.mfg.bom.pojo.entity.BomEntity;
import com.njzscloud.dispose.mfg.bom.service.BomService;
import lombok.RequiredArgsConstructor;
@ -13,6 +15,8 @@ import java.util.List;
/**
*
*
* @author ljw
*/
@Slf4j
@RestController
@ -25,8 +29,8 @@ public class BomController {
*
*/
@PostMapping("/add")
public R<?> add(@RequestBody BomEntity bomEntity) {
bomService.add(bomEntity);
public R<?> add(@RequestBody BomAddDto bomAddDTO) {
bomService.add(bomAddDTO);
return R.success();
}
@ -60,7 +64,7 @@ public class BomController {
*
*/
@GetMapping("/paging")
public R<PageResult<BomEntity>> paging(PageParam pageParam, BomEntity bomEntity) {
return R.success(bomService.paging(pageParam, bomEntity));
public R<PageResult<BomEntity>> paging(PageParam pageParam, BomQueryDto queryDto) {
return R.success(bomService.paging(pageParam, queryDto));
}
}

View File

@ -0,0 +1,44 @@
package com.njzscloud.dispose.mfg.bom.pojo.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.List;
/**
* BOMDTO
* BOM
* @author ljw
*/
@Getter
@Setter
@ToString
public class BomAddDto {
/**
* Idgds_goods.id
*/
private Long goodId;
/**
*
*/
private String bomVer;
/**
* 0-->1-->
*/
private Boolean canuse;
/**
*
*/
private String memo;
/**
* BOM
*/
private List<BomDetailAddDto> details;
}

View File

@ -0,0 +1,46 @@
package com.njzscloud.dispose.mfg.bom.pojo.dto;
import com.njzscloud.dispose.mfg.bom.constant.MtlType;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
/**
*
* @author ljw
*/
@Getter
@Setter
@ToString
@Accessors(chain = true)
public class BomDetailAddDto {
/**
* Idgds_goods.id
*/
private Long goodsId;
/**
* YuanLiao-->FuChanPin-->ZhuChanPin-->
*/
private MtlType mtlType;
/**
* 0-->1-->
*/
private Boolean chu;
/**
* / 1
*/
private BigDecimal quantity;
/**
* 0-->1-->
*/
private Boolean mandatory;
}

View File

@ -0,0 +1,32 @@
package com.njzscloud.dispose.mfg.bom.pojo.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* BOMDTO
*
* @author ljw
*/
@Getter
@Setter
@ToString
public class BomQueryDto {
/**
*
*/
private String sn;
/**
* Idgds_goods.id
*/
private Long goodId;
/**
* 0-->1-->
*/
private Boolean canuse;
}

View File

@ -1,32 +1,65 @@
package com.njzscloud.dispose.mfg.bom.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.common.mp.support.PageParam;
import com.njzscloud.common.mp.support.PageResult;
import com.njzscloud.common.sn.support.SnUtil;
import com.njzscloud.dispose.mfg.bom.constant.MtlType;
import com.njzscloud.dispose.mfg.bom.mapper.BomMapper;
import com.njzscloud.dispose.mfg.bom.pojo.dto.BomAddDto;
import com.njzscloud.dispose.mfg.bom.pojo.dto.BomDetailAddDto;
import com.njzscloud.dispose.mfg.bom.pojo.dto.BomQueryDto;
import com.njzscloud.dispose.mfg.bom.pojo.entity.BomDetailEntity;
import com.njzscloud.dispose.mfg.bom.pojo.entity.BomEntity;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List;
/**
*
*
* @author ljw
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class BomService extends ServiceImpl<BomMapper, BomEntity> implements IService<BomEntity> {
private final BomDetailService bomDetailService;
/**
*
*/
public void add(BomEntity bomEntity) {
@Transactional(rollbackFor = Exception.class)
public void add(BomAddDto bomAddDTO) {
BomEntity bomEntity = BeanUtil.copyProperties(bomAddDTO, BomEntity.class).setSn(this.generateSn());
// 校验版本号唯一性
validateBomVersionUniqueness(bomEntity.getGoodId(), bomEntity.getBomVer(), null);
// 校验可用性同一主产品ID只能有一个可用的BOM
validateBomAvailability(bomEntity.getGoodId(), null);
// 预校验明细数据
validateBomDetails(bomAddDTO.getDetails(), bomEntity.getGoodId());
// 保存BOM主表
this.save(bomEntity);
// 保存BOM明细
for (BomDetailAddDto detail : bomAddDTO.getDetails()) {
// 直接保存不使用BomDetailService的add方法避免重复校验
BomDetailEntity detailEntity = BeanUtil.copyProperties(detail, BomDetailEntity.class).setBomId(bomEntity.getId());
bomDetailService.save(detailEntity);
}
}
/**
@ -54,7 +87,94 @@ public class BomService extends ServiceImpl<BomMapper, BomEntity> implements ISe
/**
*
*/
public PageResult<BomEntity> paging(PageParam pageParam, BomEntity bomEntity) {
return PageResult.of(this.page(pageParam.toPage(), Wrappers.<BomEntity>query(bomEntity)));
public PageResult<BomEntity> paging(PageParam pageParam, BomQueryDto queryDto) {
return PageResult.of(this.page(pageParam.toPage(), Wrappers.<BomEntity>lambdaQuery()
.like(StrUtil.isNotBlank(queryDto.getSn()), BomEntity::getSn, queryDto.getSn())
.eq(queryDto.getGoodId() != null, BomEntity::getGoodId, queryDto.getGoodId())
.eq(queryDto.getCanuse() != null, BomEntity::getCanuse, queryDto.getCanuse())));
}
/**
* BOM
*
* @param goodId ID
* @param bomVer
* @param excludeId ID
*/
private void validateBomVersionUniqueness(Long goodId, String bomVer, Long excludeId) {
long count = this.count(Wrappers.<BomEntity>lambdaQuery()
.eq(BomEntity::getGoodId, goodId)
.eq(BomEntity::getBomVer, bomVer)
.ne(excludeId != null, BomEntity::getId, excludeId));
if (count > 0) {
throw Exceptions.clierr("同一主产品的BOM版本号必须唯一");
}
}
/**
* BOMIDBOM
*
* @param goodId ID
* @param excludeId ID
*/
private void validateBomAvailability(Long goodId, Long excludeId) {
long count = this.count(Wrappers.<BomEntity>lambdaQuery()
.eq(BomEntity::getGoodId, goodId)
.eq(BomEntity::getCanuse, Boolean.TRUE)
.ne(excludeId != null, BomEntity::getId, excludeId));
if (count > 0) {
throw Exceptions.clierr("同一主产品只能有一个可用的BOM");
}
}
/**
* BOM
*
* @param details
* @param mainProductId ID
*/
private void validateBomDetails(List<BomDetailAddDto> details, Long mainProductId) {
if (details == null || details.isEmpty()) {
throw Exceptions.clierr("必须包含至少一个明细");
}
boolean hasMainProduct = false;
for (BomDetailAddDto detail : details) {
// 校验产出物料数量必须为1
if (Boolean.TRUE.equals(detail.getChu()) && (detail.getQuantity() == null || detail.getQuantity().compareTo(BigDecimal.ONE) != 0)) {
throw Exceptions.clierr("产出物料的数量必须为1");
}
// 检查是否包含主产品明细
if (detail.getGoodsId() != null && detail.getGoodsId().equals(mainProductId)) {
if (detail.getMtlType() == MtlType.ZhuChanPin) {
hasMainProduct = true;
} else {
throw Exceptions.clierr("与主产品ID相同的产品必须是主产品类型");
}
}
}
if (!hasMainProduct) {
throw Exceptions.clierr("明细中必须包含与主产品ID相同且类型为主产品的记录");
}
}
/**
*
*
* @return sn
*/
public String generateSn() {
String sn = SnUtil.next("Bom-SN");
if (this.exists(Wrappers.<BomEntity>lambdaQuery().eq(BomEntity::getSn, sn).eq(BomEntity::getDeleted, Boolean.FALSE))) {
this.generateSn();
}
return sn;
}
}