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 3974d0a016..9c1332b5cb 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 @@ -10,5 +10,11 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; public interface ErrorCodeConstants { ErrorCode BOM_NOT_EXISTS = new ErrorCode(5_001, "产品BOM不存在"); + ErrorCode ORGANIZATION_NOT_EXISTS = new ErrorCode(5_0011, "产线工位不存在"); + ErrorCode ORGANIZATION_EXITS_CHILDREN = new ErrorCode(5_0012, "存在存在子产线工位,无法删除"); + ErrorCode ORGANIZATION_PARENT_NOT_EXITS = new ErrorCode(5_0013,"父级产线工位不存在"); + ErrorCode ORGANIZATION_PARENT_ERROR = new ErrorCode(5_0014, "不能设置自己为父产线工位"); + ErrorCode ORGANIZATION_NAME_DUPLICATE = new ErrorCode(5_0015, "已经存在该组织名称的产线工位"); + ErrorCode ORGANIZATION_PARENT_IS_CHILD = new ErrorCode(5_0016, "不能设置自己的子Organization为父Organization"); } diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/organization/OrganizationController.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/organization/OrganizationController.java new file mode 100644 index 0000000000..a9b76b7793 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/organization/OrganizationController.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.mes.controller.admin.organization; + +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.organization.vo.*; +import cn.iocoder.yudao.module.mes.dal.dataobject.organization.OrganizationDO; +import cn.iocoder.yudao.module.mes.service.organization.OrganizationService; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; + +@Tag(name = "管理后台 - 产线工位") +@RestController +@RequestMapping("/mes/organization") +@Validated +public class OrganizationController { + + @Resource + private OrganizationService organizationService; + + @PostMapping("/create") + @Operation(summary = "创建产线工位") + @PreAuthorize("@ss.hasPermission('mes:organization:create')") + public CommonResult createOrganization(@Valid @RequestBody OrganizationSaveReqVO createReqVO) { + return success(organizationService.createOrganization(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产线工位") + @PreAuthorize("@ss.hasPermission('mes:organization:update')") + public CommonResult updateOrganization(@Valid @RequestBody OrganizationSaveReqVO updateReqVO) { + organizationService.updateOrganization(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产线工位") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:organization:delete')") + public CommonResult deleteOrganization(@RequestParam("id") Long id) { + organizationService.deleteOrganization(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产线工位") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:organization:query')") + public CommonResult getOrganization(@RequestParam("id") Long id) { + OrganizationDO organization = organizationService.getOrganization(id); + return success(BeanUtils.toBean(organization, OrganizationRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得产线工位列表") + @PreAuthorize("@ss.hasPermission('mes:organization:query')") + public CommonResult> getOrganizationList(@Valid OrganizationListReqVO listReqVO) { + List list = organizationService.getOrganizationList(listReqVO); + return success(BeanUtils.toBean(list, OrganizationRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出产线工位 Excel") + @PreAuthorize("@ss.hasPermission('mes:organization:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportOrganizationExcel(@Valid OrganizationListReqVO listReqVO, + HttpServletResponse response) throws IOException { + List list = organizationService.getOrganizationList(listReqVO); + // 导出 Excel + ExcelUtils.write(response, "产线工位.xls", "数据", OrganizationRespVO.class, + BeanUtils.toBean(list, OrganizationRespVO.class)); + } + +} \ 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/organization/vo/OrganizationListReqVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/organization/vo/OrganizationListReqVO.java new file mode 100644 index 0000000000..b0ad7ab67a --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/organization/vo/OrganizationListReqVO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.mes.controller.admin.organization.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 产线工位列表 Request VO") +@Data +public class OrganizationListReqVO { + + @Schema(description = "组织名称", example = "赵六") + private String name; + + @Schema(description = "父组织id", example = "9482") + private Long parentId; + + @Schema(description = "显示顺序") + private Integer sort; + + @Schema(description = "负责人", example = "26059") + private Long workerUserId; + + @Schema(description = "对应机台id", example = "17654") + private Long machineId; + + @Schema(description = "联系电话") + private String phone; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "是否启用") + private Boolean isEnable; + + @Schema(description = "组织状态", example = "1") + private Integer status; + + @Schema(description = "组织等级") + private Integer orgClass; + + @Schema(description = "组织类型", example = "2") + private Integer orgType; + + @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/organization/vo/OrganizationRespVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/organization/vo/OrganizationRespVO.java new file mode 100644 index 0000000000..2c0f8de271 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/organization/vo/OrganizationRespVO.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.mes.controller.admin.organization.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +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 = "管理后台 - 产线工位 Response VO") +@Data +@ExcelIgnoreUnannotated +public class OrganizationRespVO { + + @Schema(description = "组织id", requiredMode = Schema.RequiredMode.REQUIRED, example = "9560") + @ExcelProperty("组织id") + private Long id; + + @Schema(description = "组织名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @ExcelProperty("组织名称") + private String name; + + @Schema(description = "父组织id", requiredMode = Schema.RequiredMode.REQUIRED, example = "9482") + @ExcelProperty("父组织id") + private Long parentId; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("显示顺序") + private Integer sort; + + @Schema(description = "负责人", example = "26059") + @ExcelProperty("负责人") + private Long workerUserId; + + @Schema(description = "对应机台id", example = "17654") + @ExcelProperty("对应机台id") + private Long machineId; + + @Schema(description = "联系电话") + @ExcelProperty("联系电话") + private String phone; + + @Schema(description = "邮箱") + @ExcelProperty("邮箱") + private String email; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty(value = "是否启用", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean isEnable; + + @Schema(description = "组织状态", example = "1") + @ExcelProperty(value = "组织状态", converter = DictConvert.class) + @DictFormat("mes_org_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer status; + + @Schema(description = "组织等级") + @ExcelProperty(value = "组织等级", converter = DictConvert.class) + @DictFormat("mes_org_class") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer orgClass; + + @Schema(description = "组织类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty(value = "组织类型", converter = DictConvert.class) + @DictFormat("mes_org_type") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer orgType; + + @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/organization/vo/OrganizationSaveReqVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/organization/vo/OrganizationSaveReqVO.java new file mode 100644 index 0000000000..c6c51aa383 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/organization/vo/OrganizationSaveReqVO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.mes.controller.admin.organization.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 产线工位新增/修改 Request VO") +@Data +public class OrganizationSaveReqVO { + + @Schema(description = "组织id", requiredMode = Schema.RequiredMode.REQUIRED, example = "9560") + private Long id; + + @Schema(description = "组织名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @NotEmpty(message = "组织名称不能为空") + private String name; + + @Schema(description = "父组织id", requiredMode = Schema.RequiredMode.REQUIRED, example = "9482") + @NotNull(message = "父组织id不能为空") + private Long parentId; + + @Schema(description = "显示顺序", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "显示顺序不能为空") + private Integer sort; + + @Schema(description = "负责人", example = "26059") + private Long workerUserId; + + @Schema(description = "对应机台id", example = "17654") + private Long machineId; + + @Schema(description = "联系电话") + private String phone; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "是否启用不能为空") + private Boolean isEnable; + + @Schema(description = "组织状态", example = "1") + private Integer status; + + @Schema(description = "组织等级") + private Integer orgClass; + + @Schema(description = "组织类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "组织类型不能为空") + private Integer orgType; + +} \ 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/organization/OrganizationDO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/organization/OrganizationDO.java new file mode 100644 index 0000000000..0e26ee0e6f --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/organization/OrganizationDO.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.organization; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 产线工位 DO + * + * @author 内蒙必硕 + */ +@TableName("mes_organization") +@KeySequence("mes_organization_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrganizationDO extends BaseDO { + + public static final Long PARENT_ID_ROOT = 0L; + + /** + * 组织id + */ + @TableId + private Long id; + /** + * 组织名称 + */ + private String name; + /** + * 父组织id + */ + private Long parentId; + /** + * 显示顺序 + */ + private Integer sort; + /** + * 负责人 + */ + private Long workerUserId; + /** + * 对应机台id + */ + private Long machineId; + /** + * 联系电话 + */ + private String phone; + /** + * 邮箱 + */ + private String email; + /** + * 是否启用 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean isEnable; + /** + * 组织状态 + * + * 枚举 {@link TODO mes_org_status 对应的类} + */ + private Integer status; + /** + * 组织等级 + * + * 枚举 {@link TODO mes_org_class 对应的类} + */ + private Integer orgClass; + /** + * 组织类型 + * + * 枚举 {@link TODO mes_org_type 对应的类} + */ + private Integer orgType; + +} \ 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/organization/OrganizationMapper.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/organization/OrganizationMapper.java new file mode 100644 index 0000000000..5e8da3ddad --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/organization/OrganizationMapper.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.organization; + +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.organization.OrganizationDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.*; + +/** + * 产线工位 Mapper + * + * @author 内蒙必硕 + */ +@Mapper +public interface OrganizationMapper extends BaseMapperX { + + default List selectList(OrganizationListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(OrganizationDO::getName, reqVO.getName()) + .eqIfPresent(OrganizationDO::getParentId, reqVO.getParentId()) + .eqIfPresent(OrganizationDO::getSort, reqVO.getSort()) + .eqIfPresent(OrganizationDO::getWorkerUserId, reqVO.getWorkerUserId()) + .eqIfPresent(OrganizationDO::getMachineId, reqVO.getMachineId()) + .eqIfPresent(OrganizationDO::getPhone, reqVO.getPhone()) + .eqIfPresent(OrganizationDO::getEmail, reqVO.getEmail()) + .eqIfPresent(OrganizationDO::getIsEnable, reqVO.getIsEnable()) + .eqIfPresent(OrganizationDO::getStatus, reqVO.getStatus()) + .eqIfPresent(OrganizationDO::getOrgClass, reqVO.getOrgClass()) + .eqIfPresent(OrganizationDO::getOrgType, reqVO.getOrgType()) + .betweenIfPresent(OrganizationDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(OrganizationDO::getId)); + } + + default OrganizationDO selectByParentIdAndName(Long parentId, String name) { + return selectOne(OrganizationDO::getParentId, parentId, OrganizationDO::getName, name); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(OrganizationDO::getParentId, parentId); + } + +} \ 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/organization/OrganizationService.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/organization/OrganizationService.java new file mode 100644 index 0000000000..08ab5ff34e --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/organization/OrganizationService.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.mes.service.organization; + +import java.util.*; +import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.*; +import cn.iocoder.yudao.module.mes.dal.dataobject.organization.OrganizationDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +import javax.validation.Valid; + +/** + * 产线工位 Service 接口 + * + * @author 内蒙必硕 + */ +public interface OrganizationService { + + /** + * 创建产线工位 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createOrganization(@Valid OrganizationSaveReqVO createReqVO); + + /** + * 更新产线工位 + * + * @param updateReqVO 更新信息 + */ + void updateOrganization(@Valid OrganizationSaveReqVO updateReqVO); + + /** + * 删除产线工位 + * + * @param id 编号 + */ + void deleteOrganization(Long id); + + /** + * 获得产线工位 + * + * @param id 编号 + * @return 产线工位 + */ + OrganizationDO getOrganization(Long id); + + /** + * 获得产线工位列表 + * + * @param listReqVO 查询条件 + * @return 产线工位列表 + */ + List getOrganizationList(OrganizationListReqVO listReqVO); + +} \ 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/organization/OrganizationServiceImpl.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/organization/OrganizationServiceImpl.java new file mode 100644 index 0000000000..7912f7a3fc --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/organization/OrganizationServiceImpl.java @@ -0,0 +1,137 @@ +package cn.iocoder.yudao.module.mes.service.organization; + +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.organization.vo.*; +import cn.iocoder.yudao.module.mes.dal.dataobject.organization.OrganizationDO; +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.organization.OrganizationMapper; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; + +/** + * 产线工位 Service 实现类 + * + * @author 内蒙必硕 + */ +@Service +@Validated +public class OrganizationServiceImpl implements OrganizationService { + + @Resource + private OrganizationMapper organizationMapper; + + @Override + public Long createOrganization(OrganizationSaveReqVO createReqVO) { + // 校验父组织id的有效性 + validateParentOrganization(null, createReqVO.getParentId()); + // 校验组织名称的唯一性 + validateOrganizationNameUnique(null, createReqVO.getParentId(), createReqVO.getName()); + + // 插入 + OrganizationDO organization = BeanUtils.toBean(createReqVO, OrganizationDO.class); + organizationMapper.insert(organization); + // 返回 + return organization.getId(); + } + + @Override + public void updateOrganization(OrganizationSaveReqVO updateReqVO) { + // 校验存在 + validateOrganizationExists(updateReqVO.getId()); + // 校验父组织id的有效性 + validateParentOrganization(updateReqVO.getId(), updateReqVO.getParentId()); + // 校验组织名称的唯一性 + validateOrganizationNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName()); + + // 更新 + OrganizationDO updateObj = BeanUtils.toBean(updateReqVO, OrganizationDO.class); + organizationMapper.updateById(updateObj); + } + + @Override + public void deleteOrganization(Long id) { + // 校验存在 + validateOrganizationExists(id); + // 校验是否有子产线工位 + if (organizationMapper.selectCountByParentId(id) > 0) { + throw exception(ORGANIZATION_EXITS_CHILDREN); + } + // 删除 + organizationMapper.deleteById(id); + } + + private void validateOrganizationExists(Long id) { + if (organizationMapper.selectById(id) == null) { + throw exception(ORGANIZATION_NOT_EXISTS); + } + } + + private void validateParentOrganization(Long id, Long parentId) { + if (parentId == null || OrganizationDO.PARENT_ID_ROOT.equals(parentId)) { + return; + } + // 1. 不能设置自己为父产线工位 + if (Objects.equals(id, parentId)) { + throw exception(ORGANIZATION_PARENT_ERROR); + } + // 2. 父产线工位不存在 + OrganizationDO parentOrganization = organizationMapper.selectById(parentId); + if (parentOrganization == null) { + throw exception(ORGANIZATION_PARENT_NOT_EXITS); + } + // 3. 递归校验父产线工位,如果父产线工位是自己的子产线工位,则报错,避免形成环路 + if (id == null) { // id 为空,说明新增,不需要考虑环路 + return; + } + for (int i = 0; i < Short.MAX_VALUE; i++) { + // 3.1 校验环路 + parentId = parentOrganization.getParentId(); + if (Objects.equals(id, parentId)) { + throw exception(ORGANIZATION_PARENT_IS_CHILD); + } + // 3.2 继续递归下一级父产线工位 + if (parentId == null || OrganizationDO.PARENT_ID_ROOT.equals(parentId)) { + break; + } + parentOrganization = organizationMapper.selectById(parentId); + if (parentOrganization == null) { + break; + } + } + } + + private void validateOrganizationNameUnique(Long id, Long parentId, String name) { + OrganizationDO organization = organizationMapper.selectByParentIdAndName(parentId, name); + if (organization == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的产线工位 + if (id == null) { + throw exception(ORGANIZATION_NAME_DUPLICATE); + } + if (!Objects.equals(organization.getId(), id)) { + throw exception(ORGANIZATION_NAME_DUPLICATE); + } + } + + @Override + public OrganizationDO getOrganization(Long id) { + return organizationMapper.selectById(id); + } + + @Override + public List getOrganizationList(OrganizationListReqVO listReqVO) { + return organizationMapper.selectList(listReqVO); + } + +} \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/resources/mapper/organization/OrganizationMapper.xml b/yudao-module-mes/yudao-module-mes-biz/src/main/resources/mapper/organization/OrganizationMapper.xml new file mode 100644 index 0000000000..ffaec1bb54 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/resources/mapper/organization/OrganizationMapper.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/organization/OrganizationServiceImplTest.java b/yudao-module-mes/yudao-module-mes-biz/src/test/java/cn/iocoder/yudao/module/mes/service/organization/OrganizationServiceImplTest.java new file mode 100644 index 0000000000..38cd4cf218 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/test/java/cn/iocoder/yudao/module/mes/service/organization/OrganizationServiceImplTest.java @@ -0,0 +1,173 @@ +package cn.iocoder.yudao.module.mes.service.organization; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.mes.controller.admin.organization.vo.*; +import cn.iocoder.yudao.module.mes.dal.dataobject.organization.OrganizationDO; +import cn.iocoder.yudao.module.mes.dal.mysql.organization.OrganizationMapper; +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 OrganizationServiceImpl} 的单元测试类 + * + * @author 内蒙必硕 + */ +@Import(OrganizationServiceImpl.class) +public class OrganizationServiceImplTest extends BaseDbUnitTest { + + @Resource + private OrganizationServiceImpl organizationService; + + @Resource + private OrganizationMapper organizationMapper; + + @Test + public void testCreateOrganization_success() { + // 准备参数 + OrganizationSaveReqVO createReqVO = randomPojo(OrganizationSaveReqVO.class).setId(null); + createReqVO.setParentId(0L); + // 调用 + Long organizationId = organizationService.createOrganization(createReqVO); + // 断言 + assertNotNull(organizationId); + // 校验记录的属性是否正确 + OrganizationDO organization = organizationMapper.selectById(organizationId); + assertPojoEquals(createReqVO, organization, "id"); + } + + @Test + public void testUpdateOrganization_success() { + // mock 数据 + OrganizationDO dbOrganization = randomPojo(OrganizationDO.class); + organizationMapper.insert(dbOrganization);// @Sql: 先插入出一条存在的数据 + // 准备参数 + OrganizationSaveReqVO updateReqVO = randomPojo(OrganizationSaveReqVO.class, o -> { + o.setId(dbOrganization.getId()); // 设置更新的 ID + }); + updateReqVO.setParentId(0L); + // 调用 + organizationService.updateOrganization(updateReqVO); + // 校验是否更新正确 + OrganizationDO organization = organizationMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, organization); + } + + @Test + public void testUpdateOrganization_notExists() { + // 准备参数 + OrganizationSaveReqVO updateReqVO = randomPojo(OrganizationSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> organizationService.updateOrganization(updateReqVO), ORGANIZATION_NOT_EXISTS); + } + + @Test + public void testDeleteOrganization_success() { + // mock 数据 + OrganizationDO dbOrganization = randomPojo(OrganizationDO.class); + organizationMapper.insert(dbOrganization);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbOrganization.getId(); + + // 调用 + organizationService.deleteOrganization(id); + // 校验数据不存在了 + assertNull(organizationMapper.selectById(id)); + } + + @Test + public void testDeleteOrganization_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> organizationService.deleteOrganization(id), ORGANIZATION_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetOrganizationList() { + // mock 数据 + OrganizationDO dbOrganization = randomPojo(OrganizationDO.class, o -> { // 等会查询到 + o.setName(null); + o.setParentId(null); + o.setSort(null); + o.setWorkerUserId(null); + o.setMachineId(null); + o.setPhone(null); + o.setEmail(null); + o.setIsEnable(null); + o.setStatus(null); + o.setOrgClass(null); + o.setOrgType(null); + o.setCreateTime(null); + }); + organizationMapper.insert(dbOrganization); + // 测试 name 不匹配 + organizationMapper.insert(cloneIgnoreId(dbOrganization, o -> o.setName(null))); + // 测试 parentId 不匹配 + organizationMapper.insert(cloneIgnoreId(dbOrganization, o -> o.setParentId(null))); + // 测试 sort 不匹配 + organizationMapper.insert(cloneIgnoreId(dbOrganization, o -> o.setSort(null))); + // 测试 workerUserId 不匹配 + organizationMapper.insert(cloneIgnoreId(dbOrganization, o -> o.setWorkerUserId(null))); + // 测试 machineId 不匹配 + organizationMapper.insert(cloneIgnoreId(dbOrganization, o -> o.setMachineId(null))); + // 测试 phone 不匹配 + organizationMapper.insert(cloneIgnoreId(dbOrganization, o -> o.setPhone(null))); + // 测试 email 不匹配 + organizationMapper.insert(cloneIgnoreId(dbOrganization, o -> o.setEmail(null))); + // 测试 isEnable 不匹配 + organizationMapper.insert(cloneIgnoreId(dbOrganization, o -> o.setIsEnable(null))); + // 测试 status 不匹配 + organizationMapper.insert(cloneIgnoreId(dbOrganization, o -> o.setStatus(null))); + // 测试 orgClass 不匹配 + organizationMapper.insert(cloneIgnoreId(dbOrganization, o -> o.setOrgClass(null))); + // 测试 orgType 不匹配 + organizationMapper.insert(cloneIgnoreId(dbOrganization, o -> o.setOrgType(null))); + // 测试 createTime 不匹配 + organizationMapper.insert(cloneIgnoreId(dbOrganization, o -> o.setCreateTime(null))); + // 准备参数 + OrganizationListReqVO reqVO = new OrganizationListReqVO(); + reqVO.setName(null); + reqVO.setParentId(null); + reqVO.setSort(null); + reqVO.setWorkerUserId(null); + reqVO.setMachineId(null); + reqVO.setPhone(null); + reqVO.setEmail(null); + reqVO.setIsEnable(null); + reqVO.setStatus(null); + reqVO.setOrgClass(null); + reqVO.setOrgType(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + List list = organizationService.getOrganizationList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbOrganization, list.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 72244d5fe4..91348b4767 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 @@ -3,4 +3,8 @@ 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 +DELETE FROM "mes_bom_detail"; + + +-- 将该删表 SQL 语句,添加到 yudao-module-mes-biz 模块的 test/resources/sql/clean.sql 文件里 +DELETE FROM "mes_organization"; \ 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 7315d356bf..0eb900159f 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 @@ -19,20 +19,42 @@ CREATE TABLE IF NOT EXISTS "mes_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, + "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明细表'; +CREATE TABLE IF NOT EXISTS "mes_organization" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "parent_id" bigint NOT NULL, + "sort" int NOT NULL, + "worker_user_id" bigint, + "machine_id" bigint, + "phone" varchar, + "email" varchar, + "is_enable" bit NOT NULL, + "status" int, + "org_class" int, + "org_type" int 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 '工厂组织表';