diff --git a/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java index d6b27e5ecf..3974d0a016 100644 --- a/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java +++ b/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java @@ -3,13 +3,12 @@ package cn.iocoder.yudao.module.mes.enums; import cn.iocoder.yudao.framework.common.exception.ErrorCode; /** - * Report 错误码枚举类 + * mes 错误码枚举类 * * report 系统,使用 1-003-000-000 段 */ public interface ErrorCodeConstants { - // ========== GoView 模块 1-003-000-000 ========== - ErrorCode GO_VIEW_PROJECT_NOT_EXISTS = new ErrorCode(1_003_000_000, "GoView 项目不存在"); + ErrorCode BOM_NOT_EXISTS = new ErrorCode(5_001, "产品BOM不存在"); } diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/bom/BomController.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/bom/BomController.java new file mode 100644 index 0000000000..676da666d6 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/bom/BomController.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.mes.controller.admin.bom; + +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.mes.controller.admin.bom.vo.*; +import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDetailDO; +import cn.iocoder.yudao.module.mes.service.bom.BomService; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; + +@Tag(name = "管理后台 - 产品BOM") +@RestController +@RequestMapping("/mes/bom") +@Validated +public class BomController { + + @Resource + private BomService bomService; + + @PostMapping("/create") + @Operation(summary = "创建产品BOM") + @PreAuthorize("@ss.hasPermission('mes:bom:create')") + public CommonResult createBom(@Valid @RequestBody BomSaveReqVO createReqVO) { + return success(bomService.createBom(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产品BOM") + @PreAuthorize("@ss.hasPermission('mes:bom:update')") + public CommonResult updateBom(@Valid @RequestBody BomSaveReqVO updateReqVO) { + bomService.updateBom(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产品BOM") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:bom:delete')") + public CommonResult deleteBom(@RequestParam("id") Long id) { + bomService.deleteBom(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产品BOM") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:bom:query')") + public CommonResult getBom(@RequestParam("id") Long id) { + BomDO bom = bomService.getBom(id); + return success(BeanUtils.toBean(bom, BomRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品BOM分页") + @PreAuthorize("@ss.hasPermission('mes:bom:query')") + public CommonResult> getBomPage(@Valid BomPageReqVO pageReqVO) { + PageResult pageResult = bomService.getBomPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, BomRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出产品BOM Excel") + @PreAuthorize("@ss.hasPermission('mes:bom:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportBomExcel(@Valid BomPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = bomService.getBomPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "产品BOM.xls", "数据", BomRespVO.class, + BeanUtils.toBean(list, BomRespVO.class)); + } + + // ==================== 子表(产品BOM明细) ==================== + + @GetMapping("/bom-detail/list-by-bom-id") + @Operation(summary = "获得产品BOM明细列表") + @Parameter(name = "bomId", description = "BOM ID") + @PreAuthorize("@ss.hasPermission('mes:bom:query')") + public CommonResult> getBomDetailListByBomId(@RequestParam("bomId") Long bomId) { + return success(bomService.getBomDetailListByBomId(bomId)); + } + +} \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/bom/vo/BomPageReqVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/bom/vo/BomPageReqVO.java new file mode 100644 index 0000000000..d6bcbda176 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/bom/vo/BomPageReqVO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.mes.controller.admin.bom.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 产品BOM分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BomPageReqVO extends PageParam { + + @Schema(description = "BOM编码") + private String code; + + @Schema(description = "BOM版本") + private String version; + + @Schema(description = "产品ID", example = "5633") + private Long productId; + + @Schema(description = "单位ID", example = "24261") + private Long unitId; + + @Schema(description = "成品率%") + private BigDecimal yieldRate; + + @Schema(description = "备注", example = "你说的对") + private String remark; + + @Schema(description = "是否启用") + private Boolean isEnable; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/bom/vo/BomRespVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/bom/vo/BomRespVO.java new file mode 100644 index 0000000000..6b2706e926 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/bom/vo/BomRespVO.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.mes.controller.admin.bom.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 产品BOM Response VO") +@Data +@ExcelIgnoreUnannotated +public class BomRespVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "23849") + @ExcelProperty("ID") + private Long id; + + @Schema(description = "BOM编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("BOM编码") + private String code; + + @Schema(description = "BOM版本", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("BOM版本") + private String version; + + @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "5633") + @ExcelProperty("产品ID") + private Long productId; + + @Schema(description = "单位ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "24261") + @ExcelProperty("单位ID") + private Long unitId; + + @Schema(description = "成品率%") + @ExcelProperty("成品率%") + private BigDecimal yieldRate; + + @Schema(description = "备注", example = "你说的对") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty(value = "是否启用", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean isEnable; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/bom/vo/BomSaveReqVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/bom/vo/BomSaveReqVO.java new file mode 100644 index 0000000000..fbfcfe0919 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/bom/vo/BomSaveReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.mes.controller.admin.bom.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.math.BigDecimal; +import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDetailDO; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 产品BOM新增/修改 Request VO") +@Data +public class BomSaveReqVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "23849") + private Long id; + + @Schema(description = "BOM编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "BOM编码不能为空") + private String code; + + @Schema(description = "BOM版本", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "BOM版本不能为空") + private String version; + + @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "5633") + @NotNull(message = "产品ID不能为空") + private Long productId; + + @Schema(description = "单位ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "24261") + @NotNull(message = "单位ID不能为空") + private Long unitId; + + @Schema(description = "成品率%") + private BigDecimal yieldRate; + + @Schema(description = "备注", example = "你说的对") + private String remark; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "是否启用不能为空") + private Boolean isEnable; + + @Schema(description = "产品BOM明细列表") + private List bomDetails; + +} \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/bom/BomDO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/bom/BomDO.java new file mode 100644 index 0000000000..7b1720e17d --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/bom/BomDO.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.bom; + +import lombok.*; +import java.util.*; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 产品BOM DO + * + * @author 内蒙必硕 + */ +@TableName("mes_bom") +@KeySequence("mes_bom_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BomDO extends BaseDO { + + /** + * ID + */ + @TableId + private Long id; + /** + * BOM编码 + */ + private String code; + /** + * BOM版本 + */ + private String version; + /** + * 产品ID + */ + private Long productId; + /** + * 单位ID + */ + private Long unitId; + /** + * 成品率% + */ + private BigDecimal yieldRate; + /** + * 备注 + */ + private String remark; + /** + * 是否启用 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean isEnable; + +} \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/bom/BomDetailDO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/bom/BomDetailDO.java new file mode 100644 index 0000000000..bec90b2969 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/bom/BomDetailDO.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.bom; + +import lombok.*; + +import java.math.BigDecimal; + +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 产品BOM明细 DO + * + * @author 内蒙必硕 + */ +@TableName("mes_bom_detail") +@KeySequence("mes_bom_detail_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BomDetailDO extends BaseDO { + + /** + * ID + */ + @TableId + private Long id; + /** + * 产品ID + */ + private Long productId; + /** + * 单位ID + */ + private Long unitId; + /** + * BOM ID + */ + private Long bomId; + /** + * 用量 + */ + private BigDecimal usageNumber; + /** + * 损耗率% + */ + private BigDecimal yieldRate; + /** + * 备注 + */ + private String remark; + /** + * 是否启用 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean isEnable; + +} \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/bom/BomDetailMapper.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/bom/BomDetailMapper.java new file mode 100644 index 0000000000..03d5fb81b3 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/bom/BomDetailMapper.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.bom; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDetailDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 产品BOM明细 Mapper + * + * @author 内蒙必硕 + */ +@Mapper +public interface BomDetailMapper extends BaseMapperX { + + default List selectListByBomId(Long bomId) { + return selectList(BomDetailDO::getBomId, bomId); + } + + default int deleteByBomId(Long bomId) { + return delete(BomDetailDO::getBomId, bomId); + } + +} \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/bom/BomMapper.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/bom/BomMapper.java new file mode 100644 index 0000000000..175a755b81 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/bom/BomMapper.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.bom; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.mes.controller.admin.bom.vo.*; + +/** + * 产品BOM Mapper + * + * @author 内蒙必硕 + */ +@Mapper +public interface BomMapper extends BaseMapperX { + + default PageResult selectPage(BomPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(BomDO::getCode, reqVO.getCode()) + .eqIfPresent(BomDO::getVersion, reqVO.getVersion()) + .eqIfPresent(BomDO::getProductId, reqVO.getProductId()) + .eqIfPresent(BomDO::getUnitId, reqVO.getUnitId()) + .eqIfPresent(BomDO::getYieldRate, reqVO.getYieldRate()) + .eqIfPresent(BomDO::getRemark, reqVO.getRemark()) + .eqIfPresent(BomDO::getIsEnable, reqVO.getIsEnable()) + .betweenIfPresent(BomDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(BomDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/bom/BomService.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/bom/BomService.java new file mode 100644 index 0000000000..ebc3ac222f --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/bom/BomService.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.mes.service.bom; + +import java.util.*; +import cn.iocoder.yudao.module.mes.controller.admin.bom.vo.*; +import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDetailDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +import javax.validation.Valid; + +/** + * 产品BOM Service 接口 + * + * @author 内蒙必硕 + */ +public interface BomService { + + /** + * 创建产品BOM + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createBom(@Valid BomSaveReqVO createReqVO); + + /** + * 更新产品BOM + * + * @param updateReqVO 更新信息 + */ + void updateBom(@Valid BomSaveReqVO updateReqVO); + + /** + * 删除产品BOM + * + * @param id 编号 + */ + void deleteBom(Long id); + + /** + * 获得产品BOM + * + * @param id 编号 + * @return 产品BOM + */ + BomDO getBom(Long id); + + /** + * 获得产品BOM分页 + * + * @param pageReqVO 分页查询 + * @return 产品BOM分页 + */ + PageResult getBomPage(BomPageReqVO pageReqVO); + + // ==================== 子表(产品BOM明细) ==================== + + /** + * 获得产品BOM明细列表 + * + * @param bomId BOM ID + * @return 产品BOM明细列表 + */ + List getBomDetailListByBomId(Long bomId); + +} \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/bom/BomServiceImpl.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/bom/BomServiceImpl.java new file mode 100644 index 0000000000..635075451a --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/bom/BomServiceImpl.java @@ -0,0 +1,113 @@ +package cn.iocoder.yudao.module.mes.service.bom; + +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.iocoder.yudao.module.mes.controller.admin.bom.vo.*; +import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDetailDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.mes.dal.mysql.bom.BomMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.bom.BomDetailMapper; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; + +/** + * 产品BOM Service 实现类 + * + * @author 内蒙必硕 + */ +@Service +@Validated +public class BomServiceImpl implements BomService { + + @Resource + private BomMapper bomMapper; + @Resource + private BomDetailMapper bomDetailMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createBom(BomSaveReqVO createReqVO) { + // 插入 + BomDO bom = BeanUtils.toBean(createReqVO, BomDO.class); + bomMapper.insert(bom); + + // 插入子表 + createBomDetailList(bom.getId(), createReqVO.getBomDetails()); + // 返回 + return bom.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateBom(BomSaveReqVO updateReqVO) { + // 校验存在 + validateBomExists(updateReqVO.getId()); + // 更新 + BomDO updateObj = BeanUtils.toBean(updateReqVO, BomDO.class); + bomMapper.updateById(updateObj); + + // 更新子表 + updateBomDetailList(updateReqVO.getId(), updateReqVO.getBomDetails()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteBom(Long id) { + // 校验存在 + validateBomExists(id); + // 删除 + bomMapper.deleteById(id); + + // 删除子表 + deleteBomDetailByBomId(id); + } + + private void validateBomExists(Long id) { + if (bomMapper.selectById(id) == null) { + throw exception(BOM_NOT_EXISTS); + } + } + + @Override + public BomDO getBom(Long id) { + return bomMapper.selectById(id); + } + + @Override + public PageResult getBomPage(BomPageReqVO pageReqVO) { + return bomMapper.selectPage(pageReqVO); + } + + // ==================== 子表(产品BOM明细) ==================== + + @Override + public List getBomDetailListByBomId(Long bomId) { + return bomDetailMapper.selectListByBomId(bomId); + } + + private void createBomDetailList(Long bomId, List list) { + list.forEach(o -> o.setBomId(bomId)); + bomDetailMapper.insertBatch(list); + } + + private void updateBomDetailList(Long bomId, List list) { + deleteBomDetailByBomId(bomId); + list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新 + createBomDetailList(bomId, list); + } + + private void deleteBomDetailByBomId(Long bomId) { + bomDetailMapper.deleteByBomId(bomId); + } + +} \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/resources/mapper/bom/BomMapper.xml b/yudao-module-mes/yudao-module-mes-biz/src/main/resources/mapper/bom/BomMapper.xml new file mode 100644 index 0000000000..de0f198907 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/resources/mapper/bom/BomMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/test/java/cn/iocoder/yudao/module/mes/service/bom/BomServiceImplTest.java b/yudao-module-mes/yudao-module-mes-biz/src/test/java/cn/iocoder/yudao/module/mes/service/bom/BomServiceImplTest.java new file mode 100644 index 0000000000..c044d183ad --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/test/java/cn/iocoder/yudao/module/mes/service/bom/BomServiceImplTest.java @@ -0,0 +1,156 @@ +package cn.iocoder.yudao.module.mes.service.bom; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.mes.controller.admin.bom.vo.*; +import cn.iocoder.yudao.module.mes.dal.dataobject.bom.BomDO; +import cn.iocoder.yudao.module.mes.dal.mysql.bom.BomMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link BomServiceImpl} 的单元测试类 + * + * @author 内蒙必硕 + */ +@Import(BomServiceImpl.class) +public class BomServiceImplTest extends BaseDbUnitTest { + + @Resource + private BomServiceImpl bomService; + + @Resource + private BomMapper bomMapper; + + @Test + public void testCreateBom_success() { + // 准备参数 + BomSaveReqVO createReqVO = randomPojo(BomSaveReqVO.class).setId(null); + + // 调用 + Long bomId = bomService.createBom(createReqVO); + // 断言 + assertNotNull(bomId); + // 校验记录的属性是否正确 + BomDO bom = bomMapper.selectById(bomId); + assertPojoEquals(createReqVO, bom, "id"); + } + + @Test + public void testUpdateBom_success() { + // mock 数据 + BomDO dbBom = randomPojo(BomDO.class); + bomMapper.insert(dbBom);// @Sql: 先插入出一条存在的数据 + // 准备参数 + BomSaveReqVO updateReqVO = randomPojo(BomSaveReqVO.class, o -> { + o.setId(dbBom.getId()); // 设置更新的 ID + }); + + // 调用 + bomService.updateBom(updateReqVO); + // 校验是否更新正确 + BomDO bom = bomMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, bom); + } + + @Test + public void testUpdateBom_notExists() { + // 准备参数 + BomSaveReqVO updateReqVO = randomPojo(BomSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> bomService.updateBom(updateReqVO), BOM_NOT_EXISTS); + } + + @Test + public void testDeleteBom_success() { + // mock 数据 + BomDO dbBom = randomPojo(BomDO.class); + bomMapper.insert(dbBom);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbBom.getId(); + + // 调用 + bomService.deleteBom(id); + // 校验数据不存在了 + assertNull(bomMapper.selectById(id)); + } + + @Test + public void testDeleteBom_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> bomService.deleteBom(id), BOM_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetBomPage() { + // mock 数据 + BomDO dbBom = randomPojo(BomDO.class, o -> { // 等会查询到 + o.setCode(null); + o.setVersion(null); + o.setProductId(null); + o.setUnitId(null); + o.setYieldRate(null); + o.setRemark(null); + o.setIsEnable(null); + o.setCreateTime(null); + }); + bomMapper.insert(dbBom); + // 测试 code 不匹配 + bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setCode(null))); + // 测试 version 不匹配 + bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setVersion(null))); + // 测试 productId 不匹配 + bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setProductId(null))); + // 测试 unitId 不匹配 + bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setUnitId(null))); + // 测试 yieldRate 不匹配 + bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setYieldRate(null))); + // 测试 remark 不匹配 + bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setRemark(null))); + // 测试 isEnable 不匹配 + bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setIsEnable(null))); + // 测试 createTime 不匹配 + bomMapper.insert(cloneIgnoreId(dbBom, o -> o.setCreateTime(null))); + // 准备参数 + BomPageReqVO reqVO = new BomPageReqVO(); + reqVO.setCode(null); + reqVO.setVersion(null); + reqVO.setProductId(null); + reqVO.setUnitId(null); + reqVO.setYieldRate(null); + reqVO.setRemark(null); + reqVO.setIsEnable(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = bomService.getBomPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbBom, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/test/resources/sql/clean.sql b/yudao-module-mes/yudao-module-mes-biz/src/test/resources/sql/clean.sql index e69de29bb2..72244d5fe4 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/test/resources/sql/clean.sql +++ b/yudao-module-mes/yudao-module-mes-biz/src/test/resources/sql/clean.sql @@ -0,0 +1,6 @@ + +-- 将该删表 SQL 语句,添加到 yudao-module-mes-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "mes_bom"; + +-- 将该删表 SQL 语句,添加到 yudao-module-mes-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "mes_bom_detail"; \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/test/resources/sql/create_tables.sql b/yudao-module-mes/yudao-module-mes-biz/src/test/resources/sql/create_tables.sql index e69de29bb2..7315d356bf 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-mes/yudao-module-mes-biz/src/test/resources/sql/create_tables.sql @@ -0,0 +1,38 @@ +CREATE TABLE IF NOT EXISTS "mes_bom" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "code" varchar NOT NULL, + "version" varchar NOT NULL, + "product_id" bigint NOT NULL, + "unit_id" bigint NOT NULL, + "yield_rate" varchar, + "remark" varchar, + "is_enable" bit NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint, + PRIMARY KEY ("id") +) COMMENT '产品BOM表'; + +CREATE TABLE IF NOT EXISTS "mes_bom_detail" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "product_id" bigint NOT NULL, + "unit_id" bigint NOT NULL, + "bom_id" bigint NOT NULL, + "usage_number" varchar NOT NULL, + "yield_rate" varchar, + "remark" varchar, + "is_enable" bit, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint, + PRIMARY KEY ("id") +) COMMENT '产品BOM明细表'; +