Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
@@ -72,6 +72,8 @@ knife4j:
|
||||
|
||||
# MyBatis Plus 的配置项
|
||||
mybatis-plus:
|
||||
mapper-locations:
|
||||
- classpath*:mapper/**/*.xml
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
|
||||
global-config:
|
||||
|
||||
76
base-server/src/main/resources/logback-spring.xml
Normal file
76
base-server/src/main/resources/logback-spring.xml
Normal file
@@ -0,0 +1,76 @@
|
||||
<configuration>
|
||||
<!-- 引用 Spring Boot 的 logback 基础配置 -->
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
|
||||
<!-- 变量 zt.info.base-package,基础业务包 -->
|
||||
<springProperty scope="context" name="zt.info.base-package" source="zt.info.base-package"/>
|
||||
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
||||
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
||||
|
||||
<!-- 控制台 Appender -->
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
|
||||
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
|
||||
<pattern>${PATTERN_DEFAULT}</pattern>
|
||||
</layout>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 文件 Appender -->
|
||||
<!-- 参考 Spring Boot 的 file-appender.xml 编写 -->
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
|
||||
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
|
||||
<pattern>${PATTERN_DEFAULT}</pattern>
|
||||
</layout>
|
||||
</encoder>
|
||||
<!-- 日志文件名 -->
|
||||
<file>${LOG_FILE}</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<!-- 滚动后的日志文件名 -->
|
||||
<fileNamePattern>${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}</fileNamePattern>
|
||||
<!-- 启动服务时,是否清理历史日志,一般不建议清理 -->
|
||||
<cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>
|
||||
<!-- 日志文件,到达多少容量,进行滚动 -->
|
||||
<maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize>
|
||||
<!-- 日志文件的总大小,0 表示不限制 -->
|
||||
<totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap>
|
||||
<!-- 日志文件的保留天数 -->
|
||||
<maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30}</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
<!-- 异步写入日志,提升性能 -->
|
||||
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<!-- 不丢失日志。默认的,如果队列的 80% 已满,则会丢弃 TRACT、DEBUG、INFO 级别的日志 -->
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<!-- 更改默认的队列的深度,该值会影响性能。默认值为 256 -->
|
||||
<queueSize>256</queueSize>
|
||||
<appender-ref ref="FILE"/>
|
||||
</appender>
|
||||
|
||||
<!-- SkyWalking GRPC 日志收集,实现日志中心。注意:SkyWalking 8.4.0 版本开始支持 -->
|
||||
<appender name="GRPC" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
|
||||
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
|
||||
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
|
||||
<pattern>${PATTERN_DEFAULT}</pattern>
|
||||
</layout>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 本地环境 -->
|
||||
<springProfile name="local,dev">
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
|
||||
<appender-ref ref="ASYNC"/> <!-- 本地环境下,如果不想打印日志,可以注释掉本行 -->
|
||||
</root>
|
||||
</springProfile>
|
||||
<!-- 其它环境 -->
|
||||
<springProfile name="test,stage,prod,default">
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="ASYNC"/>
|
||||
<appender-ref ref="GRPC"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
</configuration>
|
||||
@@ -23,18 +23,21 @@ spec:
|
||||
containers:
|
||||
- name: base-server
|
||||
image: 172.16.46.66:10043/yudao/base-server:VERSION_PLACEHOLDER
|
||||
env:
|
||||
- name: TZ
|
||||
value: Asia/Shanghai
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 48100
|
||||
initialDelaySeconds: 10
|
||||
initialDelaySeconds: 50
|
||||
periodSeconds: 5
|
||||
failureThreshold: 3
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 48100
|
||||
initialDelaySeconds: 30
|
||||
initialDelaySeconds: 50
|
||||
periodSeconds: 10
|
||||
failureThreshold: 5
|
||||
resources:
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -19,7 +19,7 @@
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<properties>
|
||||
<revision>3.0.44</revision>
|
||||
<revision>3.0.45</revision>
|
||||
<!-- Maven 相关 -->
|
||||
<java.version>17</java.version>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.zt.plat.module.base.api.businessdictionarytype;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.base.api.businessdictionarytype.dto.BusinessDictionaryDataDTO;
|
||||
import com.zt.plat.module.base.api.businessdictionarytype.dto.BusinessDictionaryTypePageReqDTO;
|
||||
import com.zt.plat.module.base.api.businessdictionarytype.dto.BusinessDictionaryTypeRespDTO;
|
||||
import com.zt.plat.module.base.api.businessdictionarytype.dto.BusinessDictionaryTypeSaveReqDTO;
|
||||
import com.zt.plat.module.base.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME)
|
||||
@Tag(name = "RPC 服务 - 业务字典类型")
|
||||
public interface BusinessDictionaryTypeApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/business-dictionary-type";
|
||||
|
||||
@PostMapping(PREFIX + "/create")
|
||||
@Operation(summary = "创建业务字典类型")
|
||||
CommonResult<BusinessDictionaryTypeRespDTO> createBusinessDictionaryType(@Valid @RequestBody BusinessDictionaryTypeSaveReqDTO createReqDTO);
|
||||
|
||||
@PutMapping(PREFIX + "/update")
|
||||
@Operation(summary = "更新业务字典类型")
|
||||
CommonResult<Boolean> updateBusinessDictionaryType(@Valid @RequestBody BusinessDictionaryTypeSaveReqDTO updateReqDTO);
|
||||
|
||||
@DeleteMapping(PREFIX + "/delete")
|
||||
@Operation(summary = "删除业务字典类型")
|
||||
CommonResult<Boolean> deleteBusinessDictionaryType(@RequestParam("id") Long id);
|
||||
|
||||
@DeleteMapping(PREFIX + "/delete-list")
|
||||
@Operation(summary = "批量删除业务字典类型")
|
||||
CommonResult<Boolean> deleteBusinessDictionaryTypeList(@RequestBody List<Long> ids);
|
||||
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "获得业务字典类型")
|
||||
CommonResult<BusinessDictionaryTypeRespDTO> getBusinessDictionaryType(@RequestParam("id") Long id);
|
||||
|
||||
@GetMapping(PREFIX + "/page")
|
||||
@Operation(summary = "获得业务字典类型分页")
|
||||
CommonResult<PageResult<BusinessDictionaryTypeRespDTO>> getBusinessDictionaryTypePage(@Valid BusinessDictionaryTypePageReqDTO pageReqDTO);
|
||||
|
||||
@GetMapping(PREFIX + "/business-dictionary-data/list-by-dictionary-type-id")
|
||||
@Operation(summary = "获得业务字典数据列表")
|
||||
CommonResult<List<BusinessDictionaryDataDTO>> getBusinessDictionaryDataListByDictionaryTypeId(@RequestParam("dictionaryTypeId") Long dictionaryTypeId);
|
||||
|
||||
@GetMapping(PREFIX + "/business-dictionary-data/list-by-type")
|
||||
@Operation(summary = "根据字典类型编码获取业务字典数据列表")
|
||||
CommonResult<List<BusinessDictionaryDataDTO>> getBusinessDictionaryDataListByType(@RequestParam("type") String type);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.zt.plat.module.base.api.businessdictionarytype.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 业务字典数据 DTO
|
||||
*/
|
||||
@Data
|
||||
public class BusinessDictionaryDataDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "1001")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "上级字典", example = "2001")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "字典类型", example = "3001")
|
||||
private Long dictionaryTypeId;
|
||||
|
||||
@Schema(description = "排序号", example = "10")
|
||||
private Long sort;
|
||||
|
||||
@Schema(description = "字典标签", example = "状态")
|
||||
private String label;
|
||||
|
||||
@Schema(description = "字典值", example = "ENABLE")
|
||||
private String value;
|
||||
|
||||
@Schema(description = "状态(0正常 1停用)", example = "0")
|
||||
private Long status;
|
||||
|
||||
@Schema(description = "备注", example = "同义词")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.zt.plat.module.base.api.businessdictionarytype.dto;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 业务字典类型分页 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class BusinessDictionaryTypePageReqDTO extends PageParam {
|
||||
|
||||
@Schema(description = "字典名称", example = "物料状态")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "字典类型", example = "base_material_status")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "状态(0正常 1停用)", example = "0")
|
||||
private Long status;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.zt.plat.module.base.api.businessdictionarytype.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 业务字典类型 Response DTO
|
||||
*/
|
||||
@Data
|
||||
public class BusinessDictionaryTypeRespDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "11771")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "字典名称", example = "物料状态")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "字典类型", example = "base_material_status")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "状态(0正常 1停用)", example = "0")
|
||||
private Long status;
|
||||
|
||||
@Schema(description = "备注", example = "基础物料状态")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.zt.plat.module.base.api.businessdictionarytype.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 业务字典类型新增/修改 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class BusinessDictionaryTypeSaveReqDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "11771")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "物料状态")
|
||||
@NotEmpty(message = "字典名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "base_material_status")
|
||||
@NotEmpty(message = "字典类型不能为空")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "状态(0正常 1停用)", example = "0")
|
||||
private Long status;
|
||||
|
||||
@Schema(description = "备注", example = "基础物料状态")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "删除时间")
|
||||
private LocalDateTime delTime;
|
||||
|
||||
@Schema(description = "业务字典数据列表")
|
||||
private List<BusinessDictionaryDataDTO> businessDictionaryDatas;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.zt.plat.module.base.api.departmentmaterial;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.base.api.departmentmaterial.dto.DepartmentMaterialPageReqDTO;
|
||||
import com.zt.plat.module.base.api.departmentmaterial.dto.DepartmentMaterialRespDTO;
|
||||
import com.zt.plat.module.base.api.departmentmaterial.dto.DepartmentMaterialSaveReqDTO;
|
||||
import com.zt.plat.module.base.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME)
|
||||
@Tag(name = "RPC 服务 - 组织架构物料")
|
||||
public interface DepartmentMaterialApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/department-material";
|
||||
|
||||
@PostMapping(PREFIX + "/create")
|
||||
@Operation(summary = "创建组织架构物料")
|
||||
CommonResult<DepartmentMaterialRespDTO> createDepartmentMaterial(@Valid @RequestBody DepartmentMaterialSaveReqDTO createReqDTO);
|
||||
|
||||
@PutMapping(PREFIX + "/update")
|
||||
@Operation(summary = "更新组织架构物料")
|
||||
CommonResult<Boolean> updateDepartmentMaterial(@Valid @RequestBody DepartmentMaterialSaveReqDTO updateReqDTO);
|
||||
|
||||
@DeleteMapping(PREFIX + "/delete")
|
||||
@Operation(summary = "删除组织架构物料")
|
||||
CommonResult<Boolean> deleteDepartmentMaterial(@RequestParam("id") Long id);
|
||||
|
||||
@DeleteMapping(PREFIX + "/delete-list")
|
||||
@Operation(summary = "批量删除组织架构物料")
|
||||
CommonResult<Boolean> deleteDepartmentMaterialList(@RequestBody List<Long> ids);
|
||||
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "获得组织架构物料")
|
||||
CommonResult<DepartmentMaterialRespDTO> getDepartmentMaterial(@RequestParam("id") Long id);
|
||||
|
||||
@GetMapping(PREFIX + "/page")
|
||||
@Operation(summary = "获得组织架构物料分页")
|
||||
CommonResult<PageResult<DepartmentMaterialRespDTO>> getDepartmentMaterialPage(@Valid DepartmentMaterialPageReqDTO pageReqDTO);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.zt.plat.module.base.api.departmentmaterial.dto;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static com.zt.plat.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
/**
|
||||
* 组织架构物料分页 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class DepartmentMaterialPageReqDTO extends PageParam {
|
||||
|
||||
@Schema(description = "物料信息ID", example = "3923")
|
||||
private Long infomationId;
|
||||
|
||||
@Schema(description = "物料信息ID集合(内部使用)")
|
||||
private List<Long> infomationIds;
|
||||
|
||||
@Schema(description = "物料分类ID", example = "30114")
|
||||
private Long classesId;
|
||||
|
||||
@Schema(description = "部门ID", example = "1001")
|
||||
private Long deptId;
|
||||
|
||||
@Schema(description = "字典数据值-物料类型")
|
||||
private String dictionaryDataValue;
|
||||
|
||||
@Schema(description = "状态编码", example = "1")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "物料编码")
|
||||
private String materialNumber;
|
||||
|
||||
@Schema(description = "物料名称")
|
||||
private String materialName;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.zt.plat.module.base.api.departmentmaterial.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 组织架构物料 Response DTO
|
||||
*/
|
||||
@Data
|
||||
public class DepartmentMaterialRespDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "5674")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "物料信息ID", example = "3923")
|
||||
private Long infomationId;
|
||||
|
||||
@Schema(description = "物料分类ID", example = "30114")
|
||||
private Long classesId;
|
||||
|
||||
@Schema(description = "字典数据值-物料类型")
|
||||
private String dictionaryDataValue;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "部门ID")
|
||||
private Long deptId;
|
||||
|
||||
@Schema(description = "部门名称")
|
||||
private String deptName;
|
||||
|
||||
@Schema(description = "物料编码")
|
||||
private String materialNumber;
|
||||
|
||||
@Schema(description = "物料名称")
|
||||
private String materialName;
|
||||
|
||||
@Schema(description = "物料大类名称")
|
||||
private String categoryLargeName;
|
||||
|
||||
@Schema(description = "物料中类名称")
|
||||
private String categoryMediumName;
|
||||
|
||||
@Schema(description = "物料小类名称")
|
||||
private String categorySmallName;
|
||||
|
||||
@Schema(description = "物料分类路径")
|
||||
private String categoryPath;
|
||||
|
||||
@Schema(description = "组织物料类型名称")
|
||||
private String dictionaryDataLabel;
|
||||
|
||||
@Schema(description = "状态编码")
|
||||
private String status;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.zt.plat.module.base.api.departmentmaterial.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 组织架构物料新增/修改 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class DepartmentMaterialSaveReqDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "5674")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "部门ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1001")
|
||||
@NotNull(message = "部门ID不能为空")
|
||||
private Long deptId;
|
||||
|
||||
@Schema(description = "物料信息ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "3923")
|
||||
@NotNull(message = "物料信息ID不能为空")
|
||||
private Long infomationId;
|
||||
|
||||
@Schema(description = "物料分类ID", example = "30114")
|
||||
private Long classesId;
|
||||
|
||||
@Schema(description = "字典数据值-物料类型", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "字典数据值-物料类型不能为空")
|
||||
private String dictionaryDataValue;
|
||||
|
||||
@Schema(description = "状态编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotEmpty(message = "状态不能为空")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "备注不能为空")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.zt.plat.module.base.api.materialclasses;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesPageReqDTO;
|
||||
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesRespDTO;
|
||||
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesSaveReqDTO;
|
||||
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesTreeRespDTO;
|
||||
import com.zt.plat.module.base.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME)
|
||||
@Tag(name = "RPC 服务 - 物料分类")
|
||||
public interface MaterialClassesApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/material-classes";
|
||||
|
||||
@PostMapping(PREFIX + "/create")
|
||||
@Operation(summary = "创建物料分类")
|
||||
CommonResult<MaterialClassesRespDTO> createMaterialClasses(@Valid @RequestBody MaterialClassesSaveReqDTO createReqDTO);
|
||||
|
||||
@PutMapping(PREFIX + "/update")
|
||||
@Operation(summary = "更新物料分类")
|
||||
CommonResult<Boolean> updateMaterialClasses(@Valid @RequestBody MaterialClassesSaveReqDTO updateReqDTO);
|
||||
|
||||
@DeleteMapping(PREFIX + "/delete")
|
||||
@Operation(summary = "删除物料分类")
|
||||
CommonResult<Boolean> deleteMaterialClasses(@RequestParam("id") Long id);
|
||||
|
||||
@DeleteMapping(PREFIX + "/delete-list")
|
||||
@Operation(summary = "批量删除物料分类")
|
||||
CommonResult<Boolean> deleteMaterialClassesList(@RequestBody List<Long> ids);
|
||||
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "获得物料分类")
|
||||
CommonResult<MaterialClassesRespDTO> getMaterialClasses(@RequestParam("id") Long id);
|
||||
|
||||
@GetMapping(PREFIX + "/page")
|
||||
@Operation(summary = "获得物料分类分页")
|
||||
CommonResult<PageResult<MaterialClassesRespDTO>> getMaterialClassesPage(@Valid MaterialClassesPageReqDTO pageReqDTO);
|
||||
|
||||
@GetMapping(PREFIX + "/tree")
|
||||
@Operation(summary = "获得物料分类树")
|
||||
CommonResult<List<MaterialClassesTreeRespDTO>> getMaterialClassesTree();
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.zt.plat.module.base.api.materialclasses.dto;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.zt.plat.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
/**
|
||||
* 物料分类分页 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialClassesPageReqDTO extends PageParam {
|
||||
|
||||
@Schema(description = "父级ID", example = "20706")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "分类编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "分类名称", example = "原材料")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "分类级别-用于类别层级(大/中/小类)")
|
||||
private Long level;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.zt.plat.module.base.api.materialclasses.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 物料分类 Response DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialClassesRespDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "4051")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "父级ID", example = "20706")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "分类编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "分类名称", example = "原材料")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "分类级别-用于类别层级(大/中/小类)")
|
||||
private Long level;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.zt.plat.module.base.api.materialclasses.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 物料分类新增/修改 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialClassesSaveReqDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "4051")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "父级ID", example = "20706")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "分类编码", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "分类编码不能为空")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "原材料")
|
||||
@NotEmpty(message = "分类名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "分类级别-用于类别层级(大/中/小类)")
|
||||
private Long level;
|
||||
|
||||
@Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "备注不能为空")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.zt.plat.module.base.api.materialclasses.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 物料分类树 Response DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialClassesTreeRespDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "1001")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "父级ID", example = "0")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "分类编码", example = "CL-001")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "分类名称", example = "原材料")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "分类级别")
|
||||
private Long level;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "子节点")
|
||||
private List<MaterialClassesTreeRespDTO> children = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.zt.plat.module.base.api.materialhasclasses;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.base.api.materialhasclasses.dto.MaterialHasClassesPageReqDTO;
|
||||
import com.zt.plat.module.base.api.materialhasclasses.dto.MaterialHasClassesRespDTO;
|
||||
import com.zt.plat.module.base.api.materialhasclasses.dto.MaterialHasClassesSaveReqDTO;
|
||||
import com.zt.plat.module.base.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME)
|
||||
@Tag(name = "RPC 服务 - 物料持有分类")
|
||||
public interface MaterialHasClassesApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/material-has-classes";
|
||||
|
||||
@PostMapping(PREFIX + "/create")
|
||||
@Operation(summary = "创建物料持有分类")
|
||||
CommonResult<MaterialHasClassesRespDTO> createMaterialHasClasses(@Valid @RequestBody MaterialHasClassesSaveReqDTO createReqDTO);
|
||||
|
||||
@PutMapping(PREFIX + "/update")
|
||||
@Operation(summary = "更新物料持有分类")
|
||||
CommonResult<Boolean> updateMaterialHasClasses(@Valid @RequestBody MaterialHasClassesSaveReqDTO updateReqDTO);
|
||||
|
||||
@DeleteMapping(PREFIX + "/delete")
|
||||
@Operation(summary = "删除物料持有分类")
|
||||
CommonResult<Boolean> deleteMaterialHasClasses(@RequestParam("id") Long id);
|
||||
|
||||
@DeleteMapping(PREFIX + "/delete-list")
|
||||
@Operation(summary = "批量删除物料持有分类")
|
||||
CommonResult<Boolean> deleteMaterialHasClassesList(@RequestBody List<Long> ids);
|
||||
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "获得物料持有分类")
|
||||
CommonResult<MaterialHasClassesRespDTO> getMaterialHasClasses(@RequestParam("id") Long id);
|
||||
|
||||
@GetMapping(PREFIX + "/page")
|
||||
@Operation(summary = "获得物料持有分类分页")
|
||||
CommonResult<PageResult<MaterialHasClassesRespDTO>> getMaterialHasClassesPage(@Valid MaterialHasClassesPageReqDTO pageReqDTO);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.zt.plat.module.base.api.materialhasclasses.dto;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.zt.plat.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
/**
|
||||
* 物料持有分类分页 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialHasClassesPageReqDTO extends PageParam {
|
||||
|
||||
@Schema(description = "物料信息ID", example = "31031")
|
||||
private Long infomationId;
|
||||
|
||||
@Schema(description = "分类ID", example = "5914")
|
||||
private Long classesId;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.zt.plat.module.base.api.materialhasclasses.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 物料持有分类 Response DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialHasClassesRespDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "16228")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "物料信息ID", example = "31031")
|
||||
private Long infomationId;
|
||||
|
||||
@Schema(description = "分类ID", example = "5914")
|
||||
private Long classesId;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.zt.plat.module.base.api.materialhasclasses.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 物料持有分类新增/修改 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialHasClassesSaveReqDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "16228")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "物料信息ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "31031")
|
||||
@NotNull(message = "物料信息ID不能为空")
|
||||
private Long infomationId;
|
||||
|
||||
@Schema(description = "分类ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "5914")
|
||||
@NotNull(message = "分类ID不能为空")
|
||||
private Long classesId;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.zt.plat.module.base.api.materialhasproperties;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.base.api.materialhasproperties.dto.MaterialHasPropertiesPageReqDTO;
|
||||
import com.zt.plat.module.base.api.materialhasproperties.dto.MaterialHasPropertiesRespDTO;
|
||||
import com.zt.plat.module.base.api.materialhasproperties.dto.MaterialHasPropertiesSaveReqDTO;
|
||||
import com.zt.plat.module.base.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME)
|
||||
@Tag(name = "RPC 服务 - 物料持有属性")
|
||||
public interface MaterialHasPropertiesApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/material-has-properties";
|
||||
|
||||
@PostMapping(PREFIX + "/create")
|
||||
@Operation(summary = "创建物料持有属性")
|
||||
CommonResult<MaterialHasPropertiesRespDTO> createMaterialHasProperties(@Valid @RequestBody MaterialHasPropertiesSaveReqDTO createReqDTO);
|
||||
|
||||
@PutMapping(PREFIX + "/update")
|
||||
@Operation(summary = "更新物料持有属性")
|
||||
CommonResult<Boolean> updateMaterialHasProperties(@Valid @RequestBody MaterialHasPropertiesSaveReqDTO updateReqDTO);
|
||||
|
||||
@DeleteMapping(PREFIX + "/delete")
|
||||
@Operation(summary = "删除物料持有属性")
|
||||
CommonResult<Boolean> deleteMaterialHasProperties(@RequestParam("id") Long id);
|
||||
|
||||
@DeleteMapping(PREFIX + "/delete-list")
|
||||
@Operation(summary = "批量删除物料持有属性")
|
||||
CommonResult<Boolean> deleteMaterialHasPropertiesList(@RequestBody List<Long> ids);
|
||||
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "获得物料持有属性")
|
||||
CommonResult<MaterialHasPropertiesRespDTO> getMaterialHasProperties(@RequestParam("id") Long id);
|
||||
|
||||
@GetMapping(PREFIX + "/page")
|
||||
@Operation(summary = "获得物料持有属性分页")
|
||||
CommonResult<PageResult<MaterialHasPropertiesRespDTO>> getMaterialHasPropertiesPage(@Valid MaterialHasPropertiesPageReqDTO pageReqDTO);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.zt.plat.module.base.api.materialhasproperties.dto;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.zt.plat.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
/**
|
||||
* 物料持有属性分页 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialHasPropertiesPageReqDTO extends PageParam {
|
||||
|
||||
@Schema(description = "物料信息ID", example = "2614")
|
||||
private Long infomationId;
|
||||
|
||||
@Schema(description = "属性ID", example = "8607")
|
||||
private Long propertiesId;
|
||||
|
||||
@Schema(description = "计量单位ID-默认计量单位", example = "23731")
|
||||
private Long unitId;
|
||||
|
||||
@Schema(description = "属性值")
|
||||
private String value;
|
||||
|
||||
@Schema(description = "是否关键属性-关键属性表示物料唯一性")
|
||||
private Integer isKey;
|
||||
|
||||
@Schema(description = "是否计量定价")
|
||||
private Integer isMetering;
|
||||
|
||||
@Schema(description = "排序号")
|
||||
private Long sort;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.zt.plat.module.base.api.materialhasproperties.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 物料持有属性 Response DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialHasPropertiesRespDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "6800")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "物料信息ID", example = "2614")
|
||||
private Long infomationId;
|
||||
|
||||
@Schema(description = "属性ID", example = "8607")
|
||||
private Long propertiesId;
|
||||
|
||||
@Schema(description = "计量单位ID-默认计量单位", example = "23731")
|
||||
private Long unitId;
|
||||
|
||||
@Schema(description = "属性值")
|
||||
private String value;
|
||||
|
||||
@Schema(description = "是否关键属性-关键属性表示物料唯一性")
|
||||
private Integer isKey;
|
||||
|
||||
@Schema(description = "是否计量定价")
|
||||
private Integer isMetering;
|
||||
|
||||
@Schema(description = "排序号")
|
||||
private Long sort;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.zt.plat.module.base.api.materialhasproperties.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 物料持有属性新增/修改 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialHasPropertiesSaveReqDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "6800")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "物料信息ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2614")
|
||||
@NotNull(message = "物料信息ID不能为空")
|
||||
private Long infomationId;
|
||||
|
||||
@Schema(description = "属性ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "8607")
|
||||
@NotNull(message = "属性ID不能为空")
|
||||
private Long propertiesId;
|
||||
|
||||
@Schema(description = "计量单位ID-默认计量单位", example = "23731")
|
||||
private Long unitId;
|
||||
|
||||
@Schema(description = "属性值", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "属性值不能为空")
|
||||
private String value;
|
||||
|
||||
@Schema(description = "是否关键属性-关键属性表示物料唯一性")
|
||||
private Integer isKey;
|
||||
|
||||
@Schema(description = "是否计量定价")
|
||||
private Integer isMetering;
|
||||
|
||||
@Schema(description = "排序号")
|
||||
private Long sort;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.zt.plat.module.base.api.materialproperties;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.base.api.materialproperties.dto.MaterialPropertiesPageReqDTO;
|
||||
import com.zt.plat.module.base.api.materialproperties.dto.MaterialPropertiesRespDTO;
|
||||
import com.zt.plat.module.base.api.materialproperties.dto.MaterialPropertiesSaveReqDTO;
|
||||
import com.zt.plat.module.base.api.materialproperties.dto.MaterialPropertiesSimplePageReqDTO;
|
||||
import com.zt.plat.module.base.api.materialproperties.dto.MaterialPropertiesSimpleRespDTO;
|
||||
import com.zt.plat.module.base.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME)
|
||||
@Tag(name = "RPC 服务 - 物料属性")
|
||||
public interface MaterialPropertiesApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/material-properties";
|
||||
|
||||
@PostMapping(PREFIX + "/create")
|
||||
@Operation(summary = "创建物料属性")
|
||||
CommonResult<MaterialPropertiesRespDTO> createMaterialProperties(@Valid @RequestBody MaterialPropertiesSaveReqDTO createReqDTO);
|
||||
|
||||
@PutMapping(PREFIX + "/update")
|
||||
@Operation(summary = "更新物料属性")
|
||||
CommonResult<Boolean> updateMaterialProperties(@Valid @RequestBody MaterialPropertiesSaveReqDTO updateReqDTO);
|
||||
|
||||
@DeleteMapping(PREFIX + "/delete")
|
||||
@Operation(summary = "删除物料属性")
|
||||
CommonResult<Boolean> deleteMaterialProperties(@RequestParam("id") Long id);
|
||||
|
||||
@DeleteMapping(PREFIX + "/delete-list")
|
||||
@Operation(summary = "批量删除物料属性")
|
||||
CommonResult<Boolean> deleteMaterialPropertiesList(@RequestBody List<Long> ids);
|
||||
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "获得物料属性")
|
||||
CommonResult<MaterialPropertiesRespDTO> getMaterialProperties(@RequestParam("id") Long id);
|
||||
|
||||
@GetMapping(PREFIX + "/page")
|
||||
@Operation(summary = "获得物料属性分页")
|
||||
CommonResult<PageResult<MaterialPropertiesRespDTO>> getMaterialPropertiesPage(@Valid MaterialPropertiesPageReqDTO pageReqDTO);
|
||||
|
||||
@GetMapping(PREFIX + "/simple-page")
|
||||
@Operation(summary = "获得物料属性精简分页")
|
||||
CommonResult<PageResult<MaterialPropertiesSimpleRespDTO>> getMaterialPropertiesSimplePage(@Valid MaterialPropertiesSimplePageReqDTO pageReqDTO);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.zt.plat.module.base.api.materialproperties.dto;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.zt.plat.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
/**
|
||||
* 物料属性分页 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialPropertiesPageReqDTO extends PageParam {
|
||||
|
||||
@Schema(description = "属性编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "属性名称", example = "含量")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "关键字(编码/名称模糊匹配)")
|
||||
private String keyword;
|
||||
|
||||
@Schema(description = "计量单位量ID", example = "30468")
|
||||
private Long unitQuantityId;
|
||||
|
||||
@Schema(description = "属性类型")
|
||||
private String dictionaryDataValue;
|
||||
|
||||
@Schema(description = "数据类型", example = "1")
|
||||
private String dataType;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.zt.plat.module.base.api.materialproperties.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 物料属性 Response DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialPropertiesRespDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "10591")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "属性编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "属性名称", example = "含量")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "计量单位量ID", example = "30468")
|
||||
private Long unitQuantityId;
|
||||
|
||||
@Schema(description = "属性类型")
|
||||
private String dictionaryDataValue;
|
||||
|
||||
@Schema(description = "属性类型名称")
|
||||
private String dictionaryDataLabel;
|
||||
|
||||
@Schema(description = "数据类型", example = "1")
|
||||
private String dataType;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "量纲名称")
|
||||
private String unitQuantityName;
|
||||
|
||||
@Schema(description = "计量单位名称")
|
||||
private String unitName;
|
||||
|
||||
@Schema(description = "计量单位符号")
|
||||
private String unitSymbol;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.zt.plat.module.base.api.materialproperties.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 物料属性新增/修改 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialPropertiesSaveReqDTO {
|
||||
|
||||
@Schema(description = "主键ID", example = "10591")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "属性编码", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "属性编码不能为空")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "属性名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "含量")
|
||||
@NotEmpty(message = "属性名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "计量单位量ID", example = "30468")
|
||||
private Long unitQuantityId;
|
||||
|
||||
@Schema(description = "属性类型(业务字典数据值)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "属性类型不能为空")
|
||||
private String dictionaryDataValue;
|
||||
|
||||
@Schema(description = "数据类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotEmpty(message = "数据类型不能为空")
|
||||
private String dataType;
|
||||
|
||||
@Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "备注不能为空")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.zt.plat.module.base.api.materialproperties.dto;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 物料属性精简分页 Request DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialPropertiesSimplePageReqDTO extends PageParam {
|
||||
|
||||
@Schema(description = "关键字(编码/名称模糊匹配)")
|
||||
private String keyword;
|
||||
|
||||
@Schema(description = "属性类型")
|
||||
private String dictionaryDataValue;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.zt.plat.module.base.api.materialproperties.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 物料属性精简 Response DTO
|
||||
*/
|
||||
@Data
|
||||
public class MaterialPropertiesSimpleRespDTO {
|
||||
|
||||
@Schema(description = "物料属性ID", example = "1001")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "属性编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "属性名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "数据类型")
|
||||
private String dataType;
|
||||
|
||||
@Schema(description = "单位名称")
|
||||
private String unitName;
|
||||
|
||||
@Schema(description = "单位符号")
|
||||
private String unitSymbol;
|
||||
|
||||
@Schema(description = "属性类型")
|
||||
private String dictionaryDataValue;
|
||||
|
||||
@Schema(description = "属性类型名称")
|
||||
private String dictionaryDataLabel;
|
||||
}
|
||||
@@ -69,4 +69,7 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode PROCESSING_INFOMATION_OPERATION_NOT_EXISTS = new ErrorCode(1_027_101_006, "工艺工序不存在");
|
||||
ErrorCode PROCESSING_OPERATION_NOT_EXISTS = new ErrorCode(1_027_101_007, "工序不存在");
|
||||
ErrorCode PROCESSING_OPERATION_MATERIAL_NOT_EXISTS = new ErrorCode(1_027_101_008, "工艺工序物料不存在");
|
||||
|
||||
// ========== 主数据同步 ==========
|
||||
ErrorCode MASTER_DATA_SYNC_DISABLED = new ErrorCode(1_027_900_001, "主数据同步功能已禁用");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.zt.plat.module.base.api.businessdictionarytype;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.module.base.api.businessdictionarytype.dto.BusinessDictionaryDataDTO;
|
||||
import com.zt.plat.module.base.api.businessdictionarytype.dto.BusinessDictionaryTypePageReqDTO;
|
||||
import com.zt.plat.module.base.api.businessdictionarytype.dto.BusinessDictionaryTypeRespDTO;
|
||||
import com.zt.plat.module.base.api.businessdictionarytype.dto.BusinessDictionaryTypeSaveReqDTO;
|
||||
import com.zt.plat.module.base.controller.admin.businessdictionarytype.vo.BusinessDictionaryTypePageReqVO;
|
||||
import com.zt.plat.module.base.controller.admin.businessdictionarytype.vo.BusinessDictionaryTypeRespVO;
|
||||
import com.zt.plat.module.base.controller.admin.businessdictionarytype.vo.BusinessDictionaryTypeSaveReqVO;
|
||||
import com.zt.plat.module.base.dal.dataobject.businessdictionarytype.BusinessDictionaryDataDO;
|
||||
import com.zt.plat.module.base.dal.dataobject.businessdictionarytype.BusinessDictionaryTypeDO;
|
||||
import com.zt.plat.module.base.service.businessdictionarytype.BusinessDictionaryTypeService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController
|
||||
@Validated
|
||||
public class BusinessDictionaryTypeApiImpl implements BusinessDictionaryTypeApi {
|
||||
|
||||
@Resource
|
||||
private BusinessDictionaryTypeService businessDictionaryTypeService;
|
||||
|
||||
@Override
|
||||
public CommonResult<BusinessDictionaryTypeRespDTO> createBusinessDictionaryType(BusinessDictionaryTypeSaveReqDTO createReqDTO) {
|
||||
BusinessDictionaryTypeRespVO respVO = businessDictionaryTypeService.createBusinessDictionaryType(convertSaveReq(createReqDTO));
|
||||
return success(BeanUtils.toBean(respVO, BusinessDictionaryTypeRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> updateBusinessDictionaryType(BusinessDictionaryTypeSaveReqDTO updateReqDTO) {
|
||||
businessDictionaryTypeService.updateBusinessDictionaryType(convertSaveReq(updateReqDTO));
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> deleteBusinessDictionaryType(Long id) {
|
||||
businessDictionaryTypeService.deleteBusinessDictionaryType(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> deleteBusinessDictionaryTypeList(List<Long> ids) {
|
||||
businessDictionaryTypeService.deleteBusinessDictionaryTypeListByIds(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<BusinessDictionaryTypeRespDTO> getBusinessDictionaryType(Long id) {
|
||||
BusinessDictionaryTypeDO typeDO = businessDictionaryTypeService.getBusinessDictionaryType(id);
|
||||
return success(BeanUtils.toBean(typeDO, BusinessDictionaryTypeRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<PageResult<BusinessDictionaryTypeRespDTO>> getBusinessDictionaryTypePage(BusinessDictionaryTypePageReqDTO pageReqDTO) {
|
||||
BusinessDictionaryTypePageReqVO pageReqVO = BeanUtils.toBean(pageReqDTO, BusinessDictionaryTypePageReqVO.class);
|
||||
PageResult<BusinessDictionaryTypeDO> pageResult = businessDictionaryTypeService.getBusinessDictionaryTypePage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, BusinessDictionaryTypeRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<BusinessDictionaryDataDTO>> getBusinessDictionaryDataListByDictionaryTypeId(Long dictionaryTypeId) {
|
||||
List<BusinessDictionaryDataDO> list = businessDictionaryTypeService.getBusinessDictionaryDataListByDictionaryTypeId(dictionaryTypeId);
|
||||
return success(BeanUtils.toBean(list, BusinessDictionaryDataDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<BusinessDictionaryDataDTO>> getBusinessDictionaryDataListByType(String type) {
|
||||
List<BusinessDictionaryDataDO> list = businessDictionaryTypeService.getBusinessDictionaryDataListByType(type);
|
||||
return success(BeanUtils.toBean(list, BusinessDictionaryDataDTO.class));
|
||||
}
|
||||
|
||||
private BusinessDictionaryTypeSaveReqVO convertSaveReq(BusinessDictionaryTypeSaveReqDTO dto) {
|
||||
BusinessDictionaryTypeSaveReqVO reqVO = BeanUtils.toBean(dto, BusinessDictionaryTypeSaveReqVO.class);
|
||||
if (dto.getBusinessDictionaryDatas() != null && !dto.getBusinessDictionaryDatas().isEmpty()) {
|
||||
reqVO.setBusinessDictionaryDatas(BeanUtils.toBean(dto.getBusinessDictionaryDatas(), BusinessDictionaryDataDO.class));
|
||||
}
|
||||
return reqVO;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.zt.plat.module.base.api.departmentmaterial;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.module.base.api.departmentmaterial.dto.DepartmentMaterialPageReqDTO;
|
||||
import com.zt.plat.module.base.api.departmentmaterial.dto.DepartmentMaterialRespDTO;
|
||||
import com.zt.plat.module.base.api.departmentmaterial.dto.DepartmentMaterialSaveReqDTO;
|
||||
import com.zt.plat.module.base.controller.admin.departmentmaterial.vo.DepartmentMaterialPageReqVO;
|
||||
import com.zt.plat.module.base.controller.admin.departmentmaterial.vo.DepartmentMaterialRespVO;
|
||||
import com.zt.plat.module.base.controller.admin.departmentmaterial.vo.DepartmentMaterialSaveReqVO;
|
||||
import com.zt.plat.module.base.service.departmentmaterial.DepartmentMaterialService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController
|
||||
@Validated
|
||||
public class DepartmentMaterialApiImpl implements DepartmentMaterialApi {
|
||||
|
||||
@Resource
|
||||
private DepartmentMaterialService departmentMaterialService;
|
||||
|
||||
@Override
|
||||
public CommonResult<DepartmentMaterialRespDTO> createDepartmentMaterial(DepartmentMaterialSaveReqDTO createReqDTO) {
|
||||
DepartmentMaterialRespVO respVO = departmentMaterialService.createDepartmentMaterial(BeanUtils.toBean(createReqDTO, DepartmentMaterialSaveReqVO.class));
|
||||
return success(BeanUtils.toBean(respVO, DepartmentMaterialRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> updateDepartmentMaterial(DepartmentMaterialSaveReqDTO updateReqDTO) {
|
||||
departmentMaterialService.updateDepartmentMaterial(BeanUtils.toBean(updateReqDTO, DepartmentMaterialSaveReqVO.class));
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> deleteDepartmentMaterial(Long id) {
|
||||
departmentMaterialService.deleteDepartmentMaterial(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> deleteDepartmentMaterialList(List<Long> ids) {
|
||||
departmentMaterialService.deleteDepartmentMaterialListByIds(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<DepartmentMaterialRespDTO> getDepartmentMaterial(Long id) {
|
||||
DepartmentMaterialRespVO respVO = departmentMaterialService.getDepartmentMaterial(id);
|
||||
return success(BeanUtils.toBean(respVO, DepartmentMaterialRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<PageResult<DepartmentMaterialRespDTO>> getDepartmentMaterialPage(DepartmentMaterialPageReqDTO pageReqDTO) {
|
||||
DepartmentMaterialPageReqVO pageReqVO = BeanUtils.toBean(pageReqDTO, DepartmentMaterialPageReqVO.class);
|
||||
PageResult<DepartmentMaterialRespVO> pageResult = departmentMaterialService.getDepartmentMaterialPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, DepartmentMaterialRespDTO.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.zt.plat.module.base.api.materialclasses;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesPageReqDTO;
|
||||
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesRespDTO;
|
||||
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesSaveReqDTO;
|
||||
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesTreeRespDTO;
|
||||
import com.zt.plat.module.base.controller.admin.materialclasses.vo.MaterialClassesPageReqVO;
|
||||
import com.zt.plat.module.base.controller.admin.materialclasses.vo.MaterialClassesRespVO;
|
||||
import com.zt.plat.module.base.controller.admin.materialclasses.vo.MaterialClassesSaveReqVO;
|
||||
import com.zt.plat.module.base.dal.dataobject.materialclasses.MaterialClassesDO;
|
||||
import com.zt.plat.module.base.service.materialclasses.MaterialClassesService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@RestController
|
||||
@Validated
|
||||
public class MaterialClassesApiImpl implements MaterialClassesApi {
|
||||
|
||||
@Resource
|
||||
private MaterialClassesService materialClassesService;
|
||||
|
||||
@Override
|
||||
public CommonResult<MaterialClassesRespDTO> createMaterialClasses(MaterialClassesSaveReqDTO createReqDTO) {
|
||||
MaterialClassesRespVO respVO = materialClassesService.createMaterialClasses(BeanUtils.toBean(createReqDTO, MaterialClassesSaveReqVO.class));
|
||||
return success(BeanUtils.toBean(respVO, MaterialClassesRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> updateMaterialClasses(MaterialClassesSaveReqDTO updateReqDTO) {
|
||||
materialClassesService.updateMaterialClasses(BeanUtils.toBean(updateReqDTO, MaterialClassesSaveReqVO.class));
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> deleteMaterialClasses(Long id) {
|
||||
materialClassesService.deleteMaterialClasses(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> deleteMaterialClassesList(List<Long> ids) {
|
||||
materialClassesService.deleteMaterialClassesListByIds(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<MaterialClassesRespDTO> getMaterialClasses(Long id) {
|
||||
MaterialClassesDO classesDO = materialClassesService.getMaterialClasses(id);
|
||||
return success(BeanUtils.toBean(classesDO, MaterialClassesRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<PageResult<MaterialClassesRespDTO>> getMaterialClassesPage(MaterialClassesPageReqDTO pageReqDTO) {
|
||||
MaterialClassesPageReqVO pageReqVO = BeanUtils.toBean(pageReqDTO, MaterialClassesPageReqVO.class);
|
||||
PageResult<MaterialClassesDO> pageResult = materialClassesService.getMaterialClassesPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, MaterialClassesRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<MaterialClassesTreeRespDTO>> getMaterialClassesTree() {
|
||||
List<MaterialClassesDO> list = materialClassesService.getMaterialClassesList();
|
||||
return success(buildTree(list));
|
||||
}
|
||||
|
||||
private List<MaterialClassesTreeRespDTO> buildTree(List<MaterialClassesDO> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Map<Long, MaterialClassesTreeRespDTO> nodeMap = new LinkedHashMap<>();
|
||||
list.stream()
|
||||
.sorted(Comparator.comparing(MaterialClassesDO::getId))
|
||||
.forEach(item -> nodeMap.put(item.getId(), BeanUtils.toBean(item, MaterialClassesTreeRespDTO.class)));
|
||||
List<MaterialClassesTreeRespDTO> roots = new ArrayList<>();
|
||||
nodeMap.values().forEach(node -> {
|
||||
Long parentId = node.getParentId();
|
||||
if (parentId == null || parentId == 0 || !nodeMap.containsKey(parentId)) {
|
||||
roots.add(node);
|
||||
} else {
|
||||
nodeMap.get(parentId).getChildren().add(node);
|
||||
}
|
||||
});
|
||||
return roots;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.zt.plat.module.base.controller.admin.base;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.module.base.controller.admin.base.vo.MasterDataSyncReqVO;
|
||||
import com.zt.plat.module.base.service.masterdatasync.MasterDataCategorySyncService;
|
||||
import com.zt.plat.module.base.service.masterdatasync.MasterDataSyncService;
|
||||
import com.zt.plat.module.base.service.masterdatasync.dto.MasterDataSyncCommand;
|
||||
import com.zt.plat.module.base.service.masterdatasync.dto.MasterDataSyncReport;
|
||||
import com.zt.plat.module.base.service.masterdatasync.dto.MasterDataCategorySyncReport;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 主数据同步")
|
||||
@RestController
|
||||
@RequestMapping("/base/master-data-sync")
|
||||
@Validated
|
||||
public class MasterDataSyncController {
|
||||
|
||||
@Resource
|
||||
private MasterDataSyncService masterDataSyncService;
|
||||
@Resource
|
||||
private MasterDataCategorySyncService masterDataCategorySyncService;
|
||||
|
||||
@PostMapping("/execute")
|
||||
@Operation(summary = "执行主数据同步")
|
||||
@PreAuthorize("@ss.hasPermission('base:master-data-sync:execute')")
|
||||
public CommonResult<MasterDataSyncReport> execute(@Valid @RequestBody MasterDataSyncReqVO reqVO) {
|
||||
MasterDataSyncCommand command = BeanUtils.toBean(reqVO, MasterDataSyncCommand.class);
|
||||
MasterDataSyncReport report = masterDataSyncService.sync(command);
|
||||
return success(report);
|
||||
}
|
||||
|
||||
@PostMapping("/categories")
|
||||
@Operation(summary = "同步物料分类")
|
||||
@PreAuthorize("@ss.hasPermission('base:master-data-sync:categories')")
|
||||
public CommonResult<MasterDataCategorySyncReport> syncCategories() {
|
||||
MasterDataCategorySyncReport report = masterDataCategorySyncService.syncAll();
|
||||
return success(report);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.zt.plat.module.base.controller.admin.base.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "主数据同步请求参数")
|
||||
public class MasterDataSyncReqVO {
|
||||
|
||||
@Schema(description = "增量同步的起始记录时间,留空执行全量")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime since;
|
||||
|
||||
@Schema(description = "拉取批大小,不填写则使用配置默认值")
|
||||
@Positive(message = "batchSize 必须为正数")
|
||||
private Integer batchSize;
|
||||
|
||||
@Schema(description = "指定要刷新同步的物料编码列表")
|
||||
private List<String> materialCodes;
|
||||
|
||||
@Schema(description = "可选的本次同步记录数上限,未填写表示不限制")
|
||||
@Positive(message = "recordLimit 必须为正数")
|
||||
private Long recordLimit;
|
||||
}
|
||||
@@ -28,4 +28,12 @@ public interface MaterialClassesMapper extends BaseMapperX<MaterialClassesDO> {
|
||||
.orderByDesc(MaterialClassesDO::getId));
|
||||
}
|
||||
|
||||
default List<MaterialClassesDO> selectByCodes(Collection<String> codes) {
|
||||
if (codes == null || codes.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return selectList(new LambdaQueryWrapperX<MaterialClassesDO>()
|
||||
.in(MaterialClassesDO::getCode, codes));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,4 +25,12 @@ public interface MaterialHasClassesMapper extends BaseMapperX<MaterialHasClasses
|
||||
.orderByDesc(MaterialHasClassesDO::getId));
|
||||
}
|
||||
|
||||
default List<MaterialHasClassesDO> selectByInfoIds(Collection<Long> infoIds) {
|
||||
if (infoIds == null || infoIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return selectList(new LambdaQueryWrapperX<MaterialHasClassesDO>()
|
||||
.in(MaterialHasClassesDO::getInfomationId, infoIds));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,4 +30,13 @@ public interface MaterialHasPropertiesMapper extends BaseMapperX<MaterialHasProp
|
||||
.orderByDesc(MaterialHasPropertiesDO::getId));
|
||||
}
|
||||
|
||||
default List<MaterialHasPropertiesDO> selectByInfoIdsAndPropertyIds(Collection<Long> infoIds, Collection<Long> propertyIds) {
|
||||
if (infoIds == null || infoIds.isEmpty() || propertyIds == null || propertyIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return selectList(new LambdaQueryWrapperX<MaterialHasPropertiesDO>()
|
||||
.in(MaterialHasPropertiesDO::getInfomationId, infoIds)
|
||||
.in(MaterialHasPropertiesDO::getPropertiesId, propertyIds));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,10 @@ import com.zt.plat.module.base.controller.admin.materialproperties.vo.MaterialPr
|
||||
import com.zt.plat.module.base.dal.dataobject.materialproperties.MaterialPropertiesDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 物料属性 Mapper
|
||||
*
|
||||
@@ -47,4 +51,12 @@ public interface MaterialPropertiesMapper extends BaseMapperX<MaterialProperties
|
||||
return selectPage(reqVO, query);
|
||||
}
|
||||
|
||||
default List<MaterialPropertiesDO> selectByCodes(Collection<String> codes) {
|
||||
if (codes == null || codes.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return selectList(new LambdaQueryWrapperX<MaterialPropertiesDO>()
|
||||
.in(MaterialPropertiesDO::getCode, codes));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.zt.plat.module.base.dal.dataobject.masterdata;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 外部 MDM 分类视图的数据对象。
|
||||
*/
|
||||
@Data
|
||||
public class MdmMaterialCategoryDO {
|
||||
|
||||
/**
|
||||
* 分类主键 ID(CODEID)。
|
||||
*/
|
||||
private Long codeId;
|
||||
|
||||
/**
|
||||
* 分类编码,例如 01 / 0101 / 010101。
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 分类名称(DESC1)。
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 备注信息(DESC2)。
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 父级分类主键 ID(PARENTID)。
|
||||
*/
|
||||
private Long parentCodeId;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.zt.plat.module.base.dal.dataobject.masterdata;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 外部 MDM MySQL 物料视图的投影,用于承接同步字段。
|
||||
*/
|
||||
@Data
|
||||
public class MdmMaterialViewDO {
|
||||
|
||||
private Long codeId;
|
||||
private String materialCode;
|
||||
private String categoryCode;
|
||||
private String categoryName;
|
||||
private String materialName;
|
||||
private String baseUnitCode;
|
||||
private String baseUnitName;
|
||||
private String shortDescription;
|
||||
private String longDescription;
|
||||
private String chalcoCode;
|
||||
private String majorClassCode;
|
||||
private String majorClassName;
|
||||
private String specification;
|
||||
private String model;
|
||||
private String texture;
|
||||
private String drawingNumber;
|
||||
private String orderNumber;
|
||||
private String otherParameters;
|
||||
private String equipmentCategory;
|
||||
private String manufacturer;
|
||||
private String source;
|
||||
private LocalDateTime recordTime;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.zt.plat.module.base.dal.mysql.masterdata;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import com.zt.plat.module.base.dal.dataobject.masterdata.MdmMaterialCategoryDO;
|
||||
import com.zt.plat.module.base.framework.sync.constant.MasterDataSyncConstants;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 读取外部 MDM 分类视图的 Mapper。
|
||||
*/
|
||||
@Mapper
|
||||
@DS(MasterDataSyncConstants.DEFAULT_SOURCE_DATASOURCE)
|
||||
public interface MdmMaterialCategoryMapper {
|
||||
|
||||
/**
|
||||
* 拉取全部分类档案。
|
||||
*/
|
||||
List<MdmMaterialCategoryDO> selectAll();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.zt.plat.module.base.dal.mysql.masterdata;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import com.zt.plat.module.base.dal.dataobject.masterdata.MdmMaterialViewDO;
|
||||
import com.zt.plat.module.base.framework.sync.constant.MasterDataSyncConstants;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Mapper that exposes read-only access to the external MDM material view.
|
||||
*/
|
||||
@Mapper
|
||||
@DS(MasterDataSyncConstants.DEFAULT_SOURCE_DATASOURCE)
|
||||
public interface MdmMaterialViewMapper {
|
||||
|
||||
List<MdmMaterialViewDO> selectSlice(@Param("offset") long offset,
|
||||
@Param("limit") int limit,
|
||||
@Param("since") LocalDateTime since,
|
||||
@Param("codes") Collection<String> codes);
|
||||
|
||||
Long countEligible(@Param("since") LocalDateTime since,
|
||||
@Param("codes") Collection<String> codes);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.zt.plat.module.base.framework.sync.config;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 主数据同步用到的基础配置。
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(MasterDataSyncProperties.class)
|
||||
public class MasterDataSyncConfiguration {
|
||||
|
||||
@Bean
|
||||
public OkHttpClient masterDataSyncOkHttpClient(MasterDataSyncProperties properties) {
|
||||
MasterDataSyncProperties.HttpProperties http = properties.getHttp();
|
||||
return new OkHttpClient.Builder()
|
||||
.connectTimeout(http.getConnectTimeout())
|
||||
.readTimeout(http.getReadTimeout())
|
||||
.writeTimeout(http.getWriteTimeout())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.zt.plat.module.base.framework.sync.config;
|
||||
|
||||
import com.zt.plat.module.base.framework.sync.constant.MasterDataSyncConstants;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 主数据同步管道的配置项。
|
||||
*/
|
||||
@Data
|
||||
@Validated
|
||||
@ConfigurationProperties(prefix = "base.master-data-sync")
|
||||
public class MasterDataSyncProperties {
|
||||
|
||||
/**
|
||||
* 是否允许运行主数据同步。
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* 从外部数据源读取时的默认批量大小。
|
||||
*/
|
||||
@Min(1)
|
||||
private int batchSize = 500;
|
||||
|
||||
/**
|
||||
* 指向外部 MDM MySQL 的动态数据源名称。
|
||||
*/
|
||||
private String sourceDatasourceName = MasterDataSyncConstants.DEFAULT_SOURCE_DATASOURCE;
|
||||
|
||||
/**
|
||||
* 成功是否进行回调通知。
|
||||
*/
|
||||
private boolean notifyOnSuccess = true;
|
||||
|
||||
/**
|
||||
* 失败是否进行回调通知。
|
||||
*/
|
||||
private boolean notifyOnFailure = true;
|
||||
|
||||
/**
|
||||
* 可选的回调地址,用于推送同步结果。
|
||||
*/
|
||||
private String callbackUrl;
|
||||
|
||||
/**
|
||||
* 回调请求需要附加的静态请求头。
|
||||
*/
|
||||
private Map<String, String> callbackHeaders = new HashMap<>();
|
||||
|
||||
/**
|
||||
* HTTP 客户端的超时时间等参数。
|
||||
*/
|
||||
private final HttpProperties http = new HttpProperties();
|
||||
|
||||
@Data
|
||||
public static class HttpProperties {
|
||||
private Duration connectTimeout = Duration.ofSeconds(5);
|
||||
private Duration readTimeout = Duration.ofSeconds(30);
|
||||
private Duration writeTimeout = Duration.ofSeconds(30);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.zt.plat.module.base.framework.sync.constant;
|
||||
|
||||
/**
|
||||
* 主数据同步相关的通用常量。
|
||||
*/
|
||||
public final class MasterDataSyncConstants {
|
||||
|
||||
private MasterDataSyncConstants() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 指向外部 MDM MySQL 的默认数据源名称。
|
||||
*/
|
||||
public static final String DEFAULT_SOURCE_DATASOURCE = "mdm";
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.zt.plat.module.base.service.masterdatasync;
|
||||
|
||||
import com.zt.plat.module.base.service.masterdatasync.dto.MasterDataCategorySyncReport;
|
||||
|
||||
/**
|
||||
* 物料分类同步服务接口。
|
||||
*/
|
||||
public interface MasterDataCategorySyncService {
|
||||
|
||||
MasterDataCategorySyncReport syncAll();
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package com.zt.plat.module.base.service.masterdatasync;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.zt.plat.module.base.dal.dao.materialclasses.MaterialClassesMapper;
|
||||
import com.zt.plat.module.base.dal.dataobject.materialclasses.MaterialClassesDO;
|
||||
import com.zt.plat.module.base.dal.dataobject.masterdata.MdmMaterialCategoryDO;
|
||||
import com.zt.plat.module.base.dal.mysql.masterdata.MdmMaterialCategoryMapper;
|
||||
import com.zt.plat.module.base.enums.ErrorCodeConstants;
|
||||
import com.zt.plat.module.base.framework.sync.config.MasterDataSyncProperties;
|
||||
import com.zt.plat.module.base.service.masterdatasync.dto.MasterDataCategorySyncReport;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 物料分类同步实现。
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class MasterDataCategorySyncServiceImpl implements MasterDataCategorySyncService {
|
||||
|
||||
private static final long ROOT_CLASS_PARENT_ID = 0L;
|
||||
|
||||
@Resource
|
||||
private MdmMaterialCategoryMapper mdmMaterialCategoryMapper;
|
||||
@Resource
|
||||
private MaterialClassesMapper materialClassesMapper;
|
||||
@Resource
|
||||
private MasterDataSyncProperties properties;
|
||||
|
||||
@Override
|
||||
public MasterDataCategorySyncReport syncAll() {
|
||||
if (!properties.isEnabled()) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.MASTER_DATA_SYNC_DISABLED);
|
||||
}
|
||||
MasterDataCategorySyncReport report = MasterDataCategorySyncReport.start();
|
||||
try {
|
||||
List<MdmMaterialCategoryDO> categories = mdmMaterialCategoryMapper.selectAll();
|
||||
if (CollUtil.isEmpty(categories)) {
|
||||
report.markSuccess();
|
||||
return report;
|
||||
}
|
||||
categories.sort(Comparator.comparing(MdmMaterialCategoryDO::getCode));
|
||||
Map<String, MaterialClassesDO> classesByCode = loadExistingClasses(categories);
|
||||
Map<Long, MaterialClassesDO> classesById = classesByCode.values().stream()
|
||||
.filter(item -> item.getId() != null)
|
||||
.collect(Collectors.toMap(MaterialClassesDO::getId, item -> item, (a, b) -> a, LinkedHashMap::new));
|
||||
// 统一收集新增分类,批量写入提升性能
|
||||
List<MaterialClassesDO> pendingClassInserts = new ArrayList<>();
|
||||
for (MdmMaterialCategoryDO category : categories) {
|
||||
Long sourceId = category.getCodeId();
|
||||
if (sourceId == null) {
|
||||
log.warn("分类 {} 缺少主键 CODEID,已跳过", category.getCode());
|
||||
continue;
|
||||
}
|
||||
String code = normalizeCode(category.getCode());
|
||||
if (code == null) {
|
||||
continue;
|
||||
}
|
||||
report.incrementProcessed(1);
|
||||
long level = determineLevel(code);
|
||||
Long parentId = resolveParentId(category, classesByCode, classesById, report);
|
||||
if (parentId == null) {
|
||||
parentId = ROOT_CLASS_PARENT_ID;
|
||||
}
|
||||
String name = StrUtil.emptyIfNull(StrUtil.trim(category.getName()));
|
||||
String remark = StrUtil.emptyIfNull(StrUtil.trim(category.getRemark()));
|
||||
MaterialClassesDO current = classesByCode.get(code);
|
||||
if (current == null) {
|
||||
MaterialClassesDO created = MaterialClassesDO.builder()
|
||||
.id(sourceId)
|
||||
.code(code)
|
||||
.name(name)
|
||||
.level(level)
|
||||
.parentId(parentId)
|
||||
.remark(remark)
|
||||
.build();
|
||||
pendingClassInserts.add(created);
|
||||
classesByCode.put(code, created);
|
||||
if (created.getId() != null) {
|
||||
classesById.put(created.getId(), created);
|
||||
}
|
||||
report.incrementInserted();
|
||||
} else {
|
||||
if (current.getId() == null && sourceId != null) {
|
||||
current.setId(sourceId);
|
||||
classesById.put(sourceId, current);
|
||||
}
|
||||
boolean needUpdate = false;
|
||||
MaterialClassesDO update = new MaterialClassesDO();
|
||||
update.setId(current.getId());
|
||||
if (!Objects.equals(current.getParentId(), parentId)) {
|
||||
update.setParentId(parentId);
|
||||
current.setParentId(parentId);
|
||||
needUpdate = true;
|
||||
}
|
||||
if (StrUtil.isNotBlank(name) && !StrUtil.equals(current.getName(), name)) {
|
||||
update.setName(name);
|
||||
current.setName(name);
|
||||
needUpdate = true;
|
||||
}
|
||||
if (!Objects.equals(current.getLevel(), level)) {
|
||||
update.setLevel(level);
|
||||
current.setLevel(level);
|
||||
needUpdate = true;
|
||||
}
|
||||
if (!Objects.equals(StrUtil.emptyIfNull(current.getRemark()), remark)) {
|
||||
update.setRemark(remark);
|
||||
current.setRemark(remark);
|
||||
needUpdate = true;
|
||||
}
|
||||
if (needUpdate) {
|
||||
materialClassesMapper.updateById(update);
|
||||
report.incrementUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(pendingClassInserts)) {
|
||||
materialClassesMapper.insertBatch(pendingClassInserts);
|
||||
}
|
||||
report.markSuccess();
|
||||
return report;
|
||||
} catch (Throwable ex) {
|
||||
report.markFailure(ex.getMessage());
|
||||
throw ex;
|
||||
} finally {
|
||||
report.finish();
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, MaterialClassesDO> loadExistingClasses(List<MdmMaterialCategoryDO> categories) {
|
||||
Set<String> codes = categories.stream()
|
||||
.map(MdmMaterialCategoryDO::getCode)
|
||||
.map(this::normalizeCode)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
List<MaterialClassesDO> existing = materialClassesMapper.selectByCodes(codes);
|
||||
Map<String, MaterialClassesDO> result = new LinkedHashMap<>();
|
||||
if (existing != null) {
|
||||
existing.forEach(item -> {
|
||||
String key = normalizeCode(item.getCode());
|
||||
if (key != null) {
|
||||
result.put(key, item);
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Long resolveParentId(MdmMaterialCategoryDO category,
|
||||
Map<String, MaterialClassesDO> classesByCode,
|
||||
Map<Long, MaterialClassesDO> classesById,
|
||||
MasterDataCategorySyncReport report) {
|
||||
if (category.getParentCodeId() != null && category.getParentCodeId() > 0) {
|
||||
MaterialClassesDO parent = classesById.get(category.getParentCodeId());
|
||||
if (parent != null) {
|
||||
return parent.getId();
|
||||
}
|
||||
log.warn("分类 {} 指定父级 ID {} 不存在,将尝试按编码推断", category.getCode(), category.getParentCodeId());
|
||||
}
|
||||
String parentCode = resolveParentCode(normalizeCode(category.getCode()));
|
||||
if (parentCode == null) {
|
||||
return ROOT_CLASS_PARENT_ID;
|
||||
}
|
||||
MaterialClassesDO parent = classesByCode.get(parentCode);
|
||||
if (parent == null) {
|
||||
log.warn("分类 {} 缺失父级 {},将挂载到根节点", category.getCode(), parentCode);
|
||||
if (report != null) {
|
||||
report.incrementMissingParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return parent.getId();
|
||||
}
|
||||
|
||||
private String resolveParentCode(String code) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
if (code.length() <= 2) {
|
||||
return null;
|
||||
}
|
||||
if (code.length() <= 4) {
|
||||
return code.substring(0, 2);
|
||||
}
|
||||
return code.substring(0, 4);
|
||||
}
|
||||
|
||||
private long determineLevel(String code) {
|
||||
if (code.length() <= 2) {
|
||||
return 1L;
|
||||
}
|
||||
if (code.length() <= 4) {
|
||||
return 2L;
|
||||
}
|
||||
return 3L;
|
||||
}
|
||||
|
||||
private String normalizeCode(String code) {
|
||||
return StrUtil.isBlank(code) ? null : StrUtil.trim(code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.zt.plat.module.base.service.masterdatasync;
|
||||
|
||||
import com.zt.plat.module.base.service.masterdatasync.dto.MasterDataSyncCommand;
|
||||
import com.zt.plat.module.base.service.masterdatasync.dto.MasterDataSyncReport;
|
||||
|
||||
/**
|
||||
* 物料主数据同步的服务入口。
|
||||
*/
|
||||
public interface MasterDataSyncService {
|
||||
|
||||
MasterDataSyncReport sync(MasterDataSyncCommand command);
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
package com.zt.plat.module.base.service.masterdatasync;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.zt.plat.module.base.dal.dao.materialclasses.MaterialClassesMapper;
|
||||
import com.zt.plat.module.base.dal.dao.materialhasclasses.MaterialHasClassesMapper;
|
||||
import com.zt.plat.module.base.dal.dao.materialhasproperties.MaterialHasPropertiesMapper;
|
||||
import com.zt.plat.module.base.dal.dao.materialproperties.MaterialPropertiesMapper;
|
||||
import com.zt.plat.module.base.dal.dataobject.base.MaterialInfomationDO;
|
||||
import com.zt.plat.module.base.dal.dataobject.materialclasses.MaterialClassesDO;
|
||||
import com.zt.plat.module.base.dal.dataobject.materialhasclasses.MaterialHasClassesDO;
|
||||
import com.zt.plat.module.base.dal.dataobject.materialhasproperties.MaterialHasPropertiesDO;
|
||||
import com.zt.plat.module.base.dal.dataobject.materialproperties.MaterialPropertiesDO;
|
||||
import com.zt.plat.module.base.dal.dataobject.masterdata.MdmMaterialViewDO;
|
||||
import com.zt.plat.module.base.dal.mysql.base.MaterialInfomationMapper;
|
||||
import com.zt.plat.module.base.dal.mysql.masterdata.MdmMaterialViewMapper;
|
||||
import com.zt.plat.module.base.enums.ErrorCodeConstants;
|
||||
import com.zt.plat.module.base.framework.sync.config.MasterDataSyncProperties;
|
||||
import com.zt.plat.module.base.service.masterdatasync.dto.MasterDataSyncCommand;
|
||||
import com.zt.plat.module.base.service.masterdatasync.dto.MasterDataSyncReport;
|
||||
import com.zt.plat.module.base.service.masterdatasync.support.MasterDataPropertyDefinition;
|
||||
import com.zt.plat.module.base.service.masterdatasync.support.MasterDataSyncNotifier;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 主数据同步核心实现,负责从外部 MDM 视图读取数据并落库到本地 BSE 表。
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class MasterDataSyncServiceImpl implements MasterDataSyncService {
|
||||
|
||||
private static final long ROOT_CLASS_PARENT_ID = 0L;
|
||||
|
||||
@Resource
|
||||
private MdmMaterialViewMapper mdmMaterialViewMapper;
|
||||
@Resource
|
||||
private MaterialInfomationMapper materialInfomationMapper;
|
||||
@Resource
|
||||
private MaterialClassesMapper materialClassesMapper;
|
||||
@Resource
|
||||
private MaterialHasClassesMapper materialHasClassesMapper;
|
||||
@Resource
|
||||
private MaterialPropertiesMapper materialPropertiesMapper;
|
||||
@Resource
|
||||
private MaterialHasPropertiesMapper materialHasPropertiesMapper;
|
||||
@Resource
|
||||
private TransactionTemplate transactionTemplate;
|
||||
@Resource
|
||||
private MasterDataSyncProperties properties;
|
||||
@Resource
|
||||
private MasterDataSyncNotifier notifier;
|
||||
|
||||
@Override
|
||||
public MasterDataSyncReport sync(MasterDataSyncCommand command) {
|
||||
if (!properties.isEnabled()) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.MASTER_DATA_SYNC_DISABLED);
|
||||
}
|
||||
MasterDataSyncReport report = MasterDataSyncReport.start(command);
|
||||
List<String> materialCodes = sanitizeCodes(command.getMaterialCodes());
|
||||
report.setMaterialCodes(materialCodes);
|
||||
int batchSize = resolveBatchSize(command.getBatchSize());
|
||||
report.setBatchSize(batchSize);
|
||||
Long recordLimit = resolveRecordLimit(command.getRecordLimit());
|
||||
report.setRecordLimit(recordLimit);
|
||||
LocalDateTime since = command.getSince();
|
||||
Map<MasterDataPropertyDefinition, MaterialPropertiesDO> propertyDefinitions = ensurePropertyDefinitions(report);
|
||||
// 缓存已读取的物料与分类,避免批次间重复查询数据库
|
||||
Map<Long, MaterialInfomationDO> materialCacheById = new LinkedHashMap<>();
|
||||
Map<String, MaterialInfomationDO> materialCacheByCode = new LinkedHashMap<>();
|
||||
Map<String, MaterialClassesDO> categoryCacheByCode = new LinkedHashMap<>();
|
||||
|
||||
long offset = 0L;
|
||||
Throwable failure = null;
|
||||
try {
|
||||
while (true) {
|
||||
int fetchSize = batchSize;
|
||||
if (recordLimit != null) {
|
||||
long remaining = recordLimit - report.getProcessedRecords();
|
||||
if (remaining <= 0) {
|
||||
break;
|
||||
}
|
||||
if (remaining < fetchSize) {
|
||||
fetchSize = (int) remaining;
|
||||
}
|
||||
}
|
||||
List<MdmMaterialViewDO> slice = mdmMaterialViewMapper.selectSlice(offset, fetchSize, since, materialCodes);
|
||||
if (CollUtil.isEmpty(slice)) {
|
||||
break;
|
||||
}
|
||||
offset += slice.size();
|
||||
report.incrementProcessedRecords(slice.size());
|
||||
final List<MdmMaterialViewDO> batch = slice;
|
||||
transactionTemplate.executeWithoutResult(status -> processBatch(batch, propertyDefinitions, report,
|
||||
materialCacheById, materialCacheByCode, categoryCacheByCode));
|
||||
}
|
||||
report.markSuccess();
|
||||
return report;
|
||||
} catch (Throwable ex) {
|
||||
failure = ex;
|
||||
report.markFailure(ex.getMessage());
|
||||
throw ex;
|
||||
} finally {
|
||||
report.finish();
|
||||
notifier.dispatch(report, failure);
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> sanitizeCodes(List<String> codes) {
|
||||
if (CollUtil.isEmpty(codes)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return codes.stream()
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.map(code -> StrUtil.trim(code).toUpperCase())
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private int resolveBatchSize(Integer requested) {
|
||||
if (requested != null && requested > 0) {
|
||||
return requested;
|
||||
}
|
||||
return Math.max(1, properties.getBatchSize());
|
||||
}
|
||||
|
||||
private Long resolveRecordLimit(Long requested) {
|
||||
if (requested == null || requested <= 0) {
|
||||
return null;
|
||||
}
|
||||
return requested;
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保所有需要的属性定义已经存在,若缺失则自动创建。
|
||||
*/
|
||||
private Map<MasterDataPropertyDefinition, MaterialPropertiesDO> ensurePropertyDefinitions(MasterDataSyncReport report) {
|
||||
List<String> codes = Arrays.stream(MasterDataPropertyDefinition.values())
|
||||
.map(MasterDataPropertyDefinition::getCode)
|
||||
.toList();
|
||||
List<MaterialPropertiesDO> existing = materialPropertiesMapper.selectByCodes(codes);
|
||||
Map<String, MaterialPropertiesDO> existingMap = Optional.ofNullable(existing)
|
||||
.orElse(Collections.emptyList())
|
||||
.stream()
|
||||
.collect(Collectors.toMap(MaterialPropertiesDO::getCode, Function.identity()));
|
||||
|
||||
Map<MasterDataPropertyDefinition, MaterialPropertiesDO> mapping = new EnumMap<>(MasterDataPropertyDefinition.class);
|
||||
List<MaterialPropertiesDO> pendingInsertDefinitions = new ArrayList<>();
|
||||
for (MasterDataPropertyDefinition definition : MasterDataPropertyDefinition.values()) {
|
||||
MaterialPropertiesDO current = existingMap.get(definition.getCode());
|
||||
if (current == null) {
|
||||
current = MaterialPropertiesDO.builder()
|
||||
.id(IdWorker.getId())
|
||||
.code(definition.getCode())
|
||||
.name(definition.getDisplayName())
|
||||
.dataType(definition.getDataType())
|
||||
.remark("MDM同步自动创建")
|
||||
.build();
|
||||
pendingInsertDefinitions.add(current);
|
||||
report.incrementInsertedPropertyDefinitions();
|
||||
} else {
|
||||
boolean needUpdate = false;
|
||||
if (!StrUtil.equals(current.getName(), definition.getDisplayName())) {
|
||||
current.setName(definition.getDisplayName());
|
||||
needUpdate = true;
|
||||
}
|
||||
if (!StrUtil.equals(current.getDataType(), definition.getDataType())) {
|
||||
current.setDataType(definition.getDataType());
|
||||
needUpdate = true;
|
||||
}
|
||||
if (needUpdate) {
|
||||
MaterialPropertiesDO update = new MaterialPropertiesDO();
|
||||
update.setId(current.getId());
|
||||
update.setName(current.getName());
|
||||
update.setDataType(current.getDataType());
|
||||
materialPropertiesMapper.updateById(update);
|
||||
report.incrementUpdatedPropertyDefinitions();
|
||||
}
|
||||
}
|
||||
mapping.put(definition, current);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(pendingInsertDefinitions)) {
|
||||
materialPropertiesMapper.insertBatch(pendingInsertDefinitions);
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
private void processBatch(List<MdmMaterialViewDO> batch,
|
||||
Map<MasterDataPropertyDefinition, MaterialPropertiesDO> propertyDefinitions,
|
||||
MasterDataSyncReport report,
|
||||
Map<Long, MaterialInfomationDO> materialCacheById,
|
||||
Map<String, MaterialInfomationDO> materialCacheByCode,
|
||||
Map<String, MaterialClassesDO> categoryCacheByCode) {
|
||||
if (CollUtil.isEmpty(batch)) {
|
||||
return;
|
||||
}
|
||||
// 1. 落库物料主数据
|
||||
Map<String, MaterialInfomationDO> materials = upsertMaterials(batch, report, materialCacheById, materialCacheByCode);
|
||||
// 2. 读取已存在的分类信息
|
||||
Map<String, MaterialClassesDO> categoryClasses = loadCategoryClasses(batch, categoryCacheByCode);
|
||||
// 3. 建立物料与分类的关系
|
||||
bindMaterialClasses(batch, materials, categoryClasses, report);
|
||||
// 4. 写入物料属性及属性值
|
||||
upsertMaterialProperties(batch, materials, propertyDefinitions, report);
|
||||
}
|
||||
|
||||
private Map<String, MaterialClassesDO> loadCategoryClasses(List<MdmMaterialViewDO> batch,
|
||||
Map<String, MaterialClassesDO> categoryCacheByCode) {
|
||||
Set<String> requestedCodes = batch.stream()
|
||||
.map(MdmMaterialViewDO::getCategoryCode)
|
||||
.map(this::normalizeValue)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
if (requestedCodes.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, MaterialClassesDO> mapping = requestedCodes.stream()
|
||||
.map(code -> new Object[]{code, categoryCacheByCode.get(code)})
|
||||
.filter(pair -> pair[1] != null)
|
||||
.collect(Collectors.toMap(pair -> (String) pair[0], pair -> (MaterialClassesDO) pair[1], (a, b) -> a, LinkedHashMap::new));
|
||||
Set<String> missing = new LinkedHashSet<>(requestedCodes);
|
||||
missing.removeIf(mapping::containsKey);
|
||||
if (!missing.isEmpty()) {
|
||||
List<MaterialClassesDO> newlyLoaded = materialClassesMapper.selectByCodes(missing);
|
||||
Optional.ofNullable(newlyLoaded)
|
||||
.orElse(Collections.emptyList())
|
||||
.forEach(item -> {
|
||||
String code = normalizeValue(item.getCode());
|
||||
if (code != null) {
|
||||
categoryCacheByCode.put(code, item);
|
||||
mapping.put(code, item);
|
||||
}
|
||||
});
|
||||
missing.removeIf(mapping::containsKey);
|
||||
if (!missing.isEmpty()) {
|
||||
List<String> preview = missing.stream().limit(10).toList();
|
||||
log.warn("当前批次存在 {} 个分类未同步,示例: {}", missing.size(), preview);
|
||||
}
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
private Map<String, MaterialInfomationDO> upsertMaterials(List<MdmMaterialViewDO> batch,
|
||||
MasterDataSyncReport report,
|
||||
Map<Long, MaterialInfomationDO> materialCacheById,
|
||||
Map<String, MaterialInfomationDO> materialCacheByCode) {
|
||||
Set<Long> sourceIds = batch.stream()
|
||||
.map(MdmMaterialViewDO::getCodeId)
|
||||
.filter(Objects::nonNull)
|
||||
.filter(id -> id > 0)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
if (sourceIds.isEmpty()) {
|
||||
log.warn("本次批次缺少有效 CODEID,无法同步物料主数据");
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<Long, MaterialInfomationDO> existingById = sourceIds.stream()
|
||||
.map(materialCacheById::get)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(MaterialInfomationDO::getId, Function.identity(), (a, b) -> a, LinkedHashMap::new));
|
||||
Set<Long> missingIds = new LinkedHashSet<>(sourceIds);
|
||||
missingIds.removeIf(existingById::containsKey);
|
||||
if (!missingIds.isEmpty()) {
|
||||
List<MaterialInfomationDO> fetched = materialInfomationMapper.selectBatchIds(missingIds);
|
||||
Optional.ofNullable(fetched)
|
||||
.orElse(Collections.emptyList())
|
||||
.forEach(item -> {
|
||||
if (item.getId() != null) {
|
||||
existingById.put(item.getId(), item);
|
||||
materialCacheById.put(item.getId(), item);
|
||||
String normalizedCode = normalizeValue(item.getCode());
|
||||
if (normalizedCode != null) {
|
||||
materialCacheByCode.put(normalizedCode, item);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Map<String, MaterialInfomationDO> mapping = new LinkedHashMap<>();
|
||||
List<MaterialInfomationDO> pendingMaterialInserts = new ArrayList<>();
|
||||
for (MdmMaterialViewDO item : batch) {
|
||||
Long codeId = item.getCodeId();
|
||||
if (codeId == null || codeId <= 0) {
|
||||
log.warn("物料 {} 缺少主键 CODEID,已跳过", item.getMaterialCode());
|
||||
continue;
|
||||
}
|
||||
String code = normalizeValue(item.getMaterialCode());
|
||||
if (code == null) {
|
||||
continue;
|
||||
}
|
||||
MaterialInfomationDO current = existingById.get(codeId);
|
||||
String name = normalizeValue(item.getMaterialName());
|
||||
if (current == null) {
|
||||
MaterialInfomationDO created = MaterialInfomationDO.builder()
|
||||
.id(codeId)
|
||||
.code(code)
|
||||
.name(StrUtil.emptyIfNull(name))
|
||||
.remark(null)
|
||||
.build();
|
||||
pendingMaterialInserts.add(created);
|
||||
existingById.put(codeId, created);
|
||||
materialCacheById.put(codeId, created);
|
||||
materialCacheByCode.put(code, created);
|
||||
mapping.put(code, created);
|
||||
report.incrementInsertedMaterials();
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean needUpdate = false;
|
||||
MaterialInfomationDO update = null;
|
||||
if (!StrUtil.equals(current.getCode(), code)) {
|
||||
current.setCode(code);
|
||||
needUpdate = true;
|
||||
}
|
||||
if (name != null && !StrUtil.equals(current.getName(), name)) {
|
||||
current.setName(name);
|
||||
needUpdate = true;
|
||||
}
|
||||
if (needUpdate) {
|
||||
update = new MaterialInfomationDO();
|
||||
update.setId(current.getId());
|
||||
update.setCode(current.getCode());
|
||||
update.setName(current.getName());
|
||||
materialInfomationMapper.updateById(update);
|
||||
report.incrementUpdatedMaterials();
|
||||
}
|
||||
mapping.put(code, current);
|
||||
materialCacheByCode.put(code, current);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(pendingMaterialInserts)) {
|
||||
materialInfomationMapper.insertBatch(pendingMaterialInserts);
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
private void bindMaterialClasses(List<MdmMaterialViewDO> batch,
|
||||
Map<String, MaterialInfomationDO> materials,
|
||||
Map<String, MaterialClassesDO> categoryClasses,
|
||||
MasterDataSyncReport report) {
|
||||
if (materials.isEmpty() || categoryClasses.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<Long> infoIds = batch.stream()
|
||||
.map(MdmMaterialViewDO::getMaterialCode)
|
||||
.map(this::normalizeValue)
|
||||
.map(materials::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(MaterialInfomationDO::getId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
Map<Long, MaterialHasClassesDO> existingRelations = materialHasClassesMapper.selectByInfoIds(infoIds)
|
||||
.stream()
|
||||
.collect(Collectors.toMap(MaterialHasClassesDO::getInfomationId, Function.identity(), (a, b) -> a));
|
||||
List<MaterialHasClassesDO> relationsToInsert = new ArrayList<>();
|
||||
for (MdmMaterialViewDO item : batch) {
|
||||
String materialCode = normalizeValue(item.getMaterialCode());
|
||||
MaterialInfomationDO info = materials.get(materialCode);
|
||||
if (info == null) {
|
||||
continue;
|
||||
}
|
||||
String categoryCode = normalizeValue(item.getCategoryCode());
|
||||
MaterialClassesDO cls = categoryClasses.get(categoryCode);
|
||||
if (cls == null) {
|
||||
continue;
|
||||
}
|
||||
MaterialHasClassesDO relation = existingRelations.get(info.getId());
|
||||
if (relation == null) {
|
||||
MaterialHasClassesDO created = MaterialHasClassesDO.builder()
|
||||
.infomationId(info.getId())
|
||||
.classesId(cls.getId())
|
||||
.build();
|
||||
relationsToInsert.add(created);
|
||||
existingRelations.put(info.getId(), created);
|
||||
report.incrementCreatedClassRelations();
|
||||
} else if (!Objects.equals(relation.getClassesId(), cls.getId())) {
|
||||
MaterialHasClassesDO update = new MaterialHasClassesDO();
|
||||
update.setId(relation.getId());
|
||||
update.setClassesId(cls.getId());
|
||||
materialHasClassesMapper.updateById(update);
|
||||
relation.setClassesId(cls.getId());
|
||||
report.incrementUpdatedClassRelations();
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(relationsToInsert)) {
|
||||
materialHasClassesMapper.insertBatch(relationsToInsert);
|
||||
}
|
||||
}
|
||||
|
||||
private void upsertMaterialProperties(List<MdmMaterialViewDO> batch,
|
||||
Map<String, MaterialInfomationDO> materials,
|
||||
Map<MasterDataPropertyDefinition, MaterialPropertiesDO> propertyDefinitions,
|
||||
MasterDataSyncReport report) {
|
||||
if (materials.isEmpty() || propertyDefinitions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<Long> infoIds = batch.stream()
|
||||
.map(MdmMaterialViewDO::getMaterialCode)
|
||||
.map(this::normalizeValue)
|
||||
.map(materials::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(MaterialInfomationDO::getId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
List<Long> propertyIds = propertyDefinitions.values().stream()
|
||||
.map(MaterialPropertiesDO::getId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
Map<String, MaterialHasPropertiesDO> existing = materialHasPropertiesMapper
|
||||
.selectByInfoIdsAndPropertyIds(infoIds, propertyIds)
|
||||
.stream()
|
||||
.collect(Collectors.toMap(item -> buildRelationKey(item.getInfomationId(), item.getPropertiesId()),
|
||||
Function.identity(), (a, b) -> a));
|
||||
List<MaterialHasPropertiesDO> propertyRelationsToInsert = new ArrayList<>();
|
||||
for (MdmMaterialViewDO item : batch) {
|
||||
String materialCode = normalizeValue(item.getMaterialCode());
|
||||
MaterialInfomationDO info = materials.get(materialCode);
|
||||
if (info == null || info.getId() == null) {
|
||||
continue;
|
||||
}
|
||||
for (Map.Entry<MasterDataPropertyDefinition, MaterialPropertiesDO> entry : propertyDefinitions.entrySet()) {
|
||||
MaterialPropertiesDO property = entry.getValue();
|
||||
if (property == null || property.getId() == null) {
|
||||
continue;
|
||||
}
|
||||
String value = normalizeValue(entry.getKey().extractValue(item));
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
String key = buildRelationKey(info.getId(), property.getId());
|
||||
MaterialHasPropertiesDO relation = existing.get(key);
|
||||
if (relation == null) {
|
||||
MaterialHasPropertiesDO created = MaterialHasPropertiesDO.builder()
|
||||
.infomationId(info.getId())
|
||||
.propertiesId(property.getId())
|
||||
.value(value)
|
||||
.sort(entry.getKey().getSort())
|
||||
.isKey(0)
|
||||
.isMetering(0)
|
||||
.build();
|
||||
propertyRelationsToInsert.add(created);
|
||||
existing.put(key, created);
|
||||
report.incrementInsertedPropertyValues();
|
||||
} else if (!StrUtil.equals(relation.getValue(), value)
|
||||
|| !Objects.equals(relation.getSort(), entry.getKey().getSort())) {
|
||||
MaterialHasPropertiesDO update = new MaterialHasPropertiesDO();
|
||||
update.setId(relation.getId());
|
||||
update.setValue(value);
|
||||
update.setSort(entry.getKey().getSort());
|
||||
materialHasPropertiesMapper.updateById(update);
|
||||
relation.setValue(value);
|
||||
relation.setSort(entry.getKey().getSort());
|
||||
report.incrementUpdatedPropertyValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(propertyRelationsToInsert)) {
|
||||
materialHasPropertiesMapper.insertBatch(propertyRelationsToInsert);
|
||||
}
|
||||
}
|
||||
|
||||
private String buildRelationKey(Long infoId, Long propertyId) {
|
||||
return infoId + ":" + propertyId;
|
||||
}
|
||||
|
||||
private String normalizeValue(String value) {
|
||||
return StrUtil.isBlank(value) ? null : StrUtil.trim(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.zt.plat.module.base.service.masterdatasync.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 物料分类同步执行结果。
|
||||
*/
|
||||
@Data
|
||||
public class MasterDataCategorySyncReport {
|
||||
|
||||
private long processedCategories;
|
||||
private long insertedCategories;
|
||||
private long updatedCategories;
|
||||
private long missingParentReferences;
|
||||
private boolean success;
|
||||
private String message;
|
||||
private LocalDateTime startedAt;
|
||||
private LocalDateTime finishedAt;
|
||||
|
||||
public static MasterDataCategorySyncReport start() {
|
||||
MasterDataCategorySyncReport report = new MasterDataCategorySyncReport();
|
||||
report.setStartedAt(LocalDateTime.now());
|
||||
report.setSuccess(false);
|
||||
report.setMessage("执行中");
|
||||
return report;
|
||||
}
|
||||
|
||||
public void markSuccess() {
|
||||
this.success = true;
|
||||
this.message = "执行成功";
|
||||
}
|
||||
|
||||
public void markFailure(String message) {
|
||||
this.success = false;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
this.finishedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public void incrementProcessed(long delta) {
|
||||
this.processedCategories += delta;
|
||||
}
|
||||
|
||||
public void incrementInserted() {
|
||||
this.insertedCategories++;
|
||||
}
|
||||
|
||||
public void incrementUpdated() {
|
||||
this.updatedCategories++;
|
||||
}
|
||||
|
||||
public void incrementMissingParent() {
|
||||
this.missingParentReferences++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.zt.plat.module.base.service.masterdatasync.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 主数据同步的入参模型。
|
||||
*/
|
||||
@Data
|
||||
public class MasterDataSyncCommand {
|
||||
|
||||
/**
|
||||
* 增量同步的起始时间,空值表示全量。
|
||||
*/
|
||||
private LocalDateTime since;
|
||||
|
||||
/**
|
||||
* 单批拉取的记录数,空值取配置默认值。
|
||||
*/
|
||||
private Integer batchSize;
|
||||
|
||||
/**
|
||||
* 需要限定同步范围的物料编码集合。
|
||||
*/
|
||||
private List<String> materialCodes;
|
||||
|
||||
/**
|
||||
* 本次同步允许处理的最大记录数,空值表示不限制。
|
||||
*/
|
||||
private Long recordLimit;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.zt.plat.module.base.service.masterdatasync.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 主数据同步的执行结果统计。
|
||||
*/
|
||||
@Data
|
||||
public class MasterDataSyncReport {
|
||||
|
||||
private long processedRecords;
|
||||
private long insertedMaterials;
|
||||
private long updatedMaterials;
|
||||
private long insertedClasses;
|
||||
private long updatedClasses;
|
||||
private long createdClassRelations;
|
||||
private long updatedClassRelations;
|
||||
private long insertedPropertyDefinitions;
|
||||
private long updatedPropertyDefinitions;
|
||||
private long insertedPropertyValues;
|
||||
private long updatedPropertyValues;
|
||||
private LocalDateTime startedAt;
|
||||
private LocalDateTime finishedAt;
|
||||
private boolean success;
|
||||
private String message;
|
||||
private Integer batchSize;
|
||||
private LocalDateTime since;
|
||||
private List<String> materialCodes = Collections.emptyList();
|
||||
private Long recordLimit;
|
||||
|
||||
public static MasterDataSyncReport start(MasterDataSyncCommand command) {
|
||||
MasterDataSyncReport report = new MasterDataSyncReport();
|
||||
report.setStartedAt(LocalDateTime.now());
|
||||
report.setBatchSize(command.getBatchSize());
|
||||
report.setSince(command.getSince());
|
||||
report.setMaterialCodes(command.getMaterialCodes());
|
||||
report.setRecordLimit(command.getRecordLimit());
|
||||
report.setSuccess(false);
|
||||
report.setMessage("执行中");
|
||||
return report;
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
this.finishedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public void markSuccess() {
|
||||
this.success = true;
|
||||
this.message = "执行成功";
|
||||
}
|
||||
|
||||
public void markFailure(String message) {
|
||||
this.success = false;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public void incrementProcessedRecords(long delta) {
|
||||
this.processedRecords += delta;
|
||||
}
|
||||
|
||||
public void incrementInsertedMaterials() {
|
||||
this.insertedMaterials++;
|
||||
}
|
||||
|
||||
public void incrementUpdatedMaterials() {
|
||||
this.updatedMaterials++;
|
||||
}
|
||||
|
||||
public void incrementInsertedClasses() {
|
||||
this.insertedClasses++;
|
||||
}
|
||||
|
||||
public void incrementUpdatedClasses() {
|
||||
this.updatedClasses++;
|
||||
}
|
||||
|
||||
public void incrementCreatedClassRelations() {
|
||||
this.createdClassRelations++;
|
||||
}
|
||||
|
||||
public void incrementUpdatedClassRelations() {
|
||||
this.updatedClassRelations++;
|
||||
}
|
||||
|
||||
public void incrementInsertedPropertyDefinitions() {
|
||||
this.insertedPropertyDefinitions++;
|
||||
}
|
||||
|
||||
public void incrementUpdatedPropertyDefinitions() {
|
||||
this.updatedPropertyDefinitions++;
|
||||
}
|
||||
|
||||
public void incrementInsertedPropertyValues() {
|
||||
this.insertedPropertyValues++;
|
||||
}
|
||||
|
||||
public void incrementUpdatedPropertyValues() {
|
||||
this.updatedPropertyValues++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.zt.plat.module.base.service.masterdatasync.support;
|
||||
|
||||
import com.zt.plat.module.base.dal.dataobject.masterdata.MdmMaterialViewDO;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 源视图字段与物料属性定义之间的标准映射关系。
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum MasterDataPropertyDefinition {
|
||||
|
||||
BASE_UNIT_CODE("MTRL_BASE_UNIT_CODE", "基本计量单位编码", 50L, MdmMaterialViewDO::getBaseUnitCode, "STRING"),
|
||||
BASE_UNIT_NAME("MTRL_BASE_UNIT_NAME", "基本计量单位描述", 60L, MdmMaterialViewDO::getBaseUnitName, "STRING"),
|
||||
SHORT_DESCRIPTION("MTRL_SHORT_DESC", "短描述", 70L, MdmMaterialViewDO::getShortDescription, "STRING"),
|
||||
LONG_DESCRIPTION("MTRL_LONG_DESC", "长描述", 80L, MdmMaterialViewDO::getLongDescription, "STRING"),
|
||||
CHALCO_CODE("MTRL_CHALCO_CODE", "中铝编码", 90L, MdmMaterialViewDO::getChalcoCode, "STRING"),
|
||||
SPECIFICATION("MTRL_SPECIFICATION", "规格", 100L, MdmMaterialViewDO::getSpecification, "STRING"),
|
||||
MODEL("MTRL_MODEL", "型号", 110L, MdmMaterialViewDO::getModel, "STRING"),
|
||||
TEXTURE("MTRL_TEXTURE", "材质", 120L, MdmMaterialViewDO::getTexture, "STRING"),
|
||||
DRAWING_NUMBER("MTRL_DRAWING_NUMBER", "图号", 130L, MdmMaterialViewDO::getDrawingNumber, "STRING"),
|
||||
ORDER_NUMBER("MTRL_ORDER_NUMBER", "订货号", 140L, MdmMaterialViewDO::getOrderNumber, "STRING"),
|
||||
OTHER_PARAMETERS("MTRL_OTHER_PARAMETERS", "其它参数", 150L, MdmMaterialViewDO::getOtherParameters, "STRING"),
|
||||
EQUIPMENT_CATEGORY("MTRL_EQUIPMENT_CATEGORY", "设备类别", 160L, MdmMaterialViewDO::getEquipmentCategory, "STRING"),
|
||||
MANUFACTURER("MTRL_MANUFACTURER", "主机生产商", 170L, MdmMaterialViewDO::getManufacturer, "STRING"),
|
||||
SOURCE("MTRL_SOURCE", "来源", 180L, MdmMaterialViewDO::getSource, "STRING"),
|
||||
RECORD_TIME("MTRL_RECORD_TIME", "记录时间", 190L,
|
||||
source -> source.getRecordTime() == null ? null : source.getRecordTime().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
|
||||
"DATETIME");
|
||||
|
||||
private final String code;
|
||||
private final String displayName;
|
||||
private final long sort;
|
||||
private final Function<MdmMaterialViewDO, String> extractor;
|
||||
private final String dataType;
|
||||
|
||||
public String extractValue(MdmMaterialViewDO source) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
String value = extractor.apply(source);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
value = value.trim();
|
||||
return value.isEmpty() ? null : value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.zt.plat.module.base.service.masterdatasync.support;
|
||||
|
||||
import com.zt.plat.module.base.service.masterdatasync.dto.MasterDataSyncReport;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 同步结束后推送给下游监听方的 JSON 载荷。
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class MasterDataSyncNotificationPayload {
|
||||
|
||||
private MasterDataSyncReport report;
|
||||
private String errorMessage;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.zt.plat.module.base.service.masterdatasync.support;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.zt.plat.framework.common.util.json.JsonUtils;
|
||||
import com.zt.plat.module.base.framework.sync.config.MasterDataSyncProperties;
|
||||
import com.zt.plat.module.base.service.masterdatasync.dto.MasterDataSyncReport;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 在同步结束后发送回调通知。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MasterDataSyncNotifier {
|
||||
|
||||
private static final MediaType JSON = MediaType.get("application/json; charset=UTF-8");
|
||||
|
||||
private final OkHttpClient httpClient;
|
||||
private final MasterDataSyncProperties properties;
|
||||
|
||||
public MasterDataSyncNotifier(@Qualifier("masterDataSyncOkHttpClient") OkHttpClient httpClient,
|
||||
MasterDataSyncProperties properties) {
|
||||
this.httpClient = httpClient;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public void dispatch(MasterDataSyncReport report, Throwable failure) {
|
||||
if (report == null || StrUtil.isBlank(properties.getCallbackUrl())) {
|
||||
return;
|
||||
}
|
||||
if (report.isSuccess() && !properties.isNotifyOnSuccess()) {
|
||||
return;
|
||||
}
|
||||
if (!report.isSuccess() && !properties.isNotifyOnFailure()) {
|
||||
return;
|
||||
}
|
||||
MasterDataSyncNotificationPayload payload = new MasterDataSyncNotificationPayload(report,
|
||||
failure == null ? null : failure.getMessage());
|
||||
RequestBody body = RequestBody.create(JSON, JsonUtils.toJsonString(payload));
|
||||
Request.Builder builder = new Request.Builder()
|
||||
.url(properties.getCallbackUrl())
|
||||
.post(body);
|
||||
properties.getCallbackHeaders().forEach(builder::addHeader);
|
||||
try (Response response = httpClient.newCall(builder.build()).execute()) {
|
||||
if (!response.isSuccessful()) {
|
||||
log.warn("主数据同步回调响应非成功状态: {}", response.code());
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
log.warn("调用主数据同步回调接口失败", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
<configuration>
|
||||
<!-- 引用 Spring Boot 的 logback 基础配置 -->
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
|
||||
<!-- 变量 yudao.info.base-package,基础业务包 -->
|
||||
<springProperty scope="context" name="yudao.info.base-package" source="yudao.info.base-package"/>
|
||||
<!-- 变量 zt.info.base-package,基础业务包 -->
|
||||
<springProperty scope="context" name="zt.info.base-package" source="zt.info.base-package"/>
|
||||
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
||||
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.zt.plat.module.base.dal.mysql.masterdata.MdmMaterialCategoryMapper">
|
||||
|
||||
<select id="selectAll" resultType="com.zt.plat.module.base.dal.dataobject.masterdata.MdmMaterialCategoryDO">
|
||||
SELECT
|
||||
CODEID AS codeId,
|
||||
CODE AS code,
|
||||
DESC1 AS name,
|
||||
DESC2 AS remark,
|
||||
PARENTID AS parentCodeId
|
||||
FROM mdm_wlfl_code
|
||||
ORDER BY CODE ASC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.zt.plat.module.base.dal.mysql.masterdata.MdmMaterialViewMapper">
|
||||
|
||||
<sql id="baseColumns">
|
||||
a.codeid AS code_id,
|
||||
a.code AS material_code,
|
||||
a.categorycode AS category_code,
|
||||
a.categoryname AS category_name,
|
||||
a.desc1 AS material_name,
|
||||
a.desc6 AS base_unit_code,
|
||||
a.desc19 AS base_unit_name,
|
||||
a.descshort AS short_description,
|
||||
a.desclong AS long_description,
|
||||
a.desc86 AS chalco_code,
|
||||
b.pur_class AS major_class_code,
|
||||
c.desc1 AS major_class_name,
|
||||
a.desc9 AS specification,
|
||||
a.desc10 AS model,
|
||||
a.desc11 AS texture,
|
||||
a.desc12 AS drawing_number,
|
||||
a.desc13 AS order_number,
|
||||
a.desc14 AS other_parameters,
|
||||
a.desc15 AS equipment_category,
|
||||
a.desc16 AS manufacturer,
|
||||
a.desc17 AS source,
|
||||
a.recordtime AS record_time
|
||||
</sql>
|
||||
|
||||
<sql id="fromClause">
|
||||
mdm_wlzsj_code a
|
||||
INNER JOIN z_pur_class b ON a.codeid = b.codeid
|
||||
INNER JOIN mdm_wlfl_code c ON b.pur_class = c.code
|
||||
</sql>
|
||||
|
||||
<select id="selectSlice" resultType="com.zt.plat.module.base.dal.dataobject.masterdata.MdmMaterialViewDO">
|
||||
SELECT
|
||||
<include refid="baseColumns"/>
|
||||
FROM
|
||||
<include refid="fromClause"/>
|
||||
WHERE a.auditflag = 2
|
||||
<if test="since != null">
|
||||
AND a.recordtime >= #{since}
|
||||
</if>
|
||||
<if test="codes != null and codes.size > 0">
|
||||
AND a.code IN
|
||||
<foreach collection="codes" item="code" open="(" separator="," close=")">
|
||||
#{code}
|
||||
</foreach>
|
||||
</if>
|
||||
ORDER BY a.CODEID
|
||||
LIMIT #{limit} OFFSET #{offset}
|
||||
</select>
|
||||
|
||||
<select id="countEligible" resultType="long">
|
||||
SELECT COUNT(1)
|
||||
FROM
|
||||
<include refid="fromClause"/>
|
||||
WHERE a.auditflag = 2
|
||||
<if test="since != null">
|
||||
AND a.recordtime >= #{since}
|
||||
</if>
|
||||
<if test="codes != null and codes.size > 0">
|
||||
AND a.code IN
|
||||
<foreach collection="codes" item="code" open="(" separator="," close=")">
|
||||
#{code}
|
||||
</foreach>
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,201 @@
|
||||
package com.zt.plat.module.base.api.businessdictionarytype;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.base.api.businessdictionarytype.dto.BusinessDictionaryDataDTO;
|
||||
import com.zt.plat.module.base.api.businessdictionarytype.dto.BusinessDictionaryTypePageReqDTO;
|
||||
import com.zt.plat.module.base.api.businessdictionarytype.dto.BusinessDictionaryTypeRespDTO;
|
||||
import com.zt.plat.module.base.api.businessdictionarytype.dto.BusinessDictionaryTypeSaveReqDTO;
|
||||
import com.zt.plat.module.base.controller.admin.businessdictionarytype.vo.BusinessDictionaryTypePageReqVO;
|
||||
import com.zt.plat.module.base.controller.admin.businessdictionarytype.vo.BusinessDictionaryTypeRespVO;
|
||||
import com.zt.plat.module.base.controller.admin.businessdictionarytype.vo.BusinessDictionaryTypeSaveReqVO;
|
||||
import com.zt.plat.module.base.dal.dataobject.businessdictionarytype.BusinessDictionaryDataDO;
|
||||
import com.zt.plat.module.base.dal.dataobject.businessdictionarytype.BusinessDictionaryTypeDO;
|
||||
import com.zt.plat.module.base.service.businessdictionarytype.BusinessDictionaryTypeService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class BusinessDictionaryTypeApiImplTest {
|
||||
|
||||
@InjectMocks
|
||||
private BusinessDictionaryTypeApiImpl api;
|
||||
|
||||
@Mock
|
||||
private BusinessDictionaryTypeService businessDictionaryTypeService;
|
||||
|
||||
private BusinessDictionaryTypeSaveReqDTO buildSaveReqDTO() {
|
||||
BusinessDictionaryDataDTO dataDTO = new BusinessDictionaryDataDTO();
|
||||
dataDTO.setId(10L);
|
||||
dataDTO.setLabel("启用");
|
||||
dataDTO.setValue("ENABLE");
|
||||
dataDTO.setRemark("默认状态");
|
||||
BusinessDictionaryTypeSaveReqDTO dto = new BusinessDictionaryTypeSaveReqDTO();
|
||||
dto.setId(1L);
|
||||
dto.setName("状态字典");
|
||||
dto.setType("base_material_status");
|
||||
dto.setStatus(0L);
|
||||
dto.setRemark("备注");
|
||||
dto.setBusinessDictionaryDatas(List.of(dataDTO));
|
||||
return dto;
|
||||
}
|
||||
|
||||
private BusinessDictionaryTypeRespVO buildRespVO() {
|
||||
BusinessDictionaryTypeRespVO respVO = new BusinessDictionaryTypeRespVO();
|
||||
respVO.setId(1L);
|
||||
respVO.setName("状态字典");
|
||||
respVO.setType("base_material_status");
|
||||
respVO.setStatus(0L);
|
||||
respVO.setRemark("备注");
|
||||
respVO.setCreateTime(LocalDateTime.now());
|
||||
return respVO;
|
||||
}
|
||||
|
||||
@Test
|
||||
void createBusinessDictionaryType_shouldForwardToServiceAndReturnConvertedDto() {
|
||||
BusinessDictionaryTypeSaveReqDTO reqDTO = buildSaveReqDTO();
|
||||
BusinessDictionaryTypeRespVO serviceResp = buildRespVO();
|
||||
when(businessDictionaryTypeService.createBusinessDictionaryType(any(BusinessDictionaryTypeSaveReqVO.class)))
|
||||
.thenReturn(serviceResp);
|
||||
|
||||
CommonResult<BusinessDictionaryTypeRespDTO> result = api.createBusinessDictionaryType(reqDTO);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData()).usingRecursiveComparison()
|
||||
.ignoringFields("createTime")
|
||||
.isEqualTo(BeanAssertHelper.toRespDTO(serviceResp));
|
||||
|
||||
ArgumentCaptor<BusinessDictionaryTypeSaveReqVO> captor = ArgumentCaptor.forClass(BusinessDictionaryTypeSaveReqVO.class);
|
||||
verify(businessDictionaryTypeService).createBusinessDictionaryType(captor.capture());
|
||||
BusinessDictionaryTypeSaveReqVO passed = captor.getValue();
|
||||
assertThat(passed.getName()).isEqualTo(reqDTO.getName());
|
||||
assertThat(passed.getBusinessDictionaryDatas()).hasSize(1);
|
||||
BusinessDictionaryDataDO dataDO = passed.getBusinessDictionaryDatas().get(0);
|
||||
assertThat(dataDO.getLabel()).isEqualTo("启用");
|
||||
assertThat(dataDO.getValue()).isEqualTo("ENABLE");
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateBusinessDictionaryType_shouldInvokeServiceWithConvertedPayload() {
|
||||
BusinessDictionaryTypeSaveReqDTO reqDTO = buildSaveReqDTO();
|
||||
|
||||
CommonResult<Boolean> result = api.updateBusinessDictionaryType(reqDTO);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData()).isTrue();
|
||||
ArgumentCaptor<BusinessDictionaryTypeSaveReqVO> captor = ArgumentCaptor.forClass(BusinessDictionaryTypeSaveReqVO.class);
|
||||
verify(businessDictionaryTypeService).updateBusinessDictionaryType(captor.capture());
|
||||
assertThat(captor.getValue().getName()).isEqualTo(reqDTO.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteBusinessDictionaryType_shouldInvokeService() {
|
||||
CommonResult<Boolean> result = api.deleteBusinessDictionaryType(123L);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData()).isTrue();
|
||||
verify(businessDictionaryTypeService).deleteBusinessDictionaryType(123L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteBusinessDictionaryTypeList_shouldInvokeService() {
|
||||
List<Long> ids = List.of(1L, 2L);
|
||||
|
||||
CommonResult<Boolean> result = api.deleteBusinessDictionaryTypeList(ids);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData()).isTrue();
|
||||
verify(businessDictionaryTypeService).deleteBusinessDictionaryTypeListByIds(ids);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBusinessDictionaryType_shouldConvertDoToDto() {
|
||||
BusinessDictionaryTypeDO typeDO = new BusinessDictionaryTypeDO();
|
||||
typeDO.setId(55L);
|
||||
typeDO.setName("状态字典");
|
||||
when(businessDictionaryTypeService.getBusinessDictionaryType(55L)).thenReturn(typeDO);
|
||||
|
||||
CommonResult<BusinessDictionaryTypeRespDTO> result = api.getBusinessDictionaryType(55L);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData().getId()).isEqualTo(55L);
|
||||
assertThat(result.getData().getName()).isEqualTo("状态字典");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBusinessDictionaryTypePage_shouldConvertPageResult() {
|
||||
BusinessDictionaryTypeDO typeDO = new BusinessDictionaryTypeDO();
|
||||
typeDO.setId(11L);
|
||||
typeDO.setName("状态");
|
||||
PageResult<BusinessDictionaryTypeDO> page = new PageResult<>(List.of(typeDO), 1L);
|
||||
when(businessDictionaryTypeService.getBusinessDictionaryTypePage(any(BusinessDictionaryTypePageReqVO.class)))
|
||||
.thenReturn(page);
|
||||
|
||||
BusinessDictionaryTypePageReqDTO reqDTO = new BusinessDictionaryTypePageReqDTO();
|
||||
reqDTO.setName("状态");
|
||||
CommonResult<PageResult<BusinessDictionaryTypeRespDTO>> result = api.getBusinessDictionaryTypePage(reqDTO);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData().getList()).hasSize(1);
|
||||
assertThat(result.getData().getList().get(0).getName()).isEqualTo("状态");
|
||||
assertThat(result.getData().getTotal()).isEqualTo(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBusinessDictionaryDataListByDictionaryTypeId_shouldConvertList() {
|
||||
BusinessDictionaryDataDO dataDO = new BusinessDictionaryDataDO();
|
||||
dataDO.setId(9L);
|
||||
dataDO.setLabel("启用");
|
||||
when(businessDictionaryTypeService.getBusinessDictionaryDataListByDictionaryTypeId(8L))
|
||||
.thenReturn(List.of(dataDO));
|
||||
|
||||
CommonResult<List<BusinessDictionaryDataDTO>> result = api.getBusinessDictionaryDataListByDictionaryTypeId(8L);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData()).hasSize(1);
|
||||
assertThat(result.getData().get(0).getLabel()).isEqualTo("启用");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBusinessDictionaryDataListByType_shouldConvertList() {
|
||||
BusinessDictionaryDataDO dataDO = new BusinessDictionaryDataDO();
|
||||
dataDO.setId(9L);
|
||||
dataDO.setValue("ENABLE");
|
||||
when(businessDictionaryTypeService.getBusinessDictionaryDataListByType("base_material_status"))
|
||||
.thenReturn(List.of(dataDO));
|
||||
|
||||
CommonResult<List<BusinessDictionaryDataDTO>> result = api.getBusinessDictionaryDataListByType("base_material_status");
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData()).hasSize(1);
|
||||
assertThat(result.getData().get(0).getValue()).isEqualTo("ENABLE");
|
||||
}
|
||||
|
||||
private static final class BeanAssertHelper {
|
||||
private BeanAssertHelper() {
|
||||
}
|
||||
|
||||
static BusinessDictionaryTypeRespDTO toRespDTO(BusinessDictionaryTypeRespVO respVO) {
|
||||
BusinessDictionaryTypeRespDTO dto = new BusinessDictionaryTypeRespDTO();
|
||||
dto.setId(respVO.getId());
|
||||
dto.setName(respVO.getName());
|
||||
dto.setType(respVO.getType());
|
||||
dto.setStatus(respVO.getStatus());
|
||||
dto.setRemark(respVO.getRemark());
|
||||
dto.setCreateTime(respVO.getCreateTime());
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package com.zt.plat.module.base.api.departmentmaterial;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.base.api.departmentmaterial.dto.DepartmentMaterialPageReqDTO;
|
||||
import com.zt.plat.module.base.api.departmentmaterial.dto.DepartmentMaterialRespDTO;
|
||||
import com.zt.plat.module.base.api.departmentmaterial.dto.DepartmentMaterialSaveReqDTO;
|
||||
import com.zt.plat.module.base.controller.admin.departmentmaterial.vo.DepartmentMaterialPageReqVO;
|
||||
import com.zt.plat.module.base.controller.admin.departmentmaterial.vo.DepartmentMaterialRespVO;
|
||||
import com.zt.plat.module.base.controller.admin.departmentmaterial.vo.DepartmentMaterialSaveReqVO;
|
||||
import com.zt.plat.module.base.service.departmentmaterial.DepartmentMaterialService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class DepartmentMaterialApiImplTest {
|
||||
|
||||
@InjectMocks
|
||||
private DepartmentMaterialApiImpl api;
|
||||
|
||||
@Mock
|
||||
private DepartmentMaterialService departmentMaterialService;
|
||||
|
||||
private DepartmentMaterialSaveReqDTO buildSaveReq() {
|
||||
DepartmentMaterialSaveReqDTO dto = new DepartmentMaterialSaveReqDTO();
|
||||
dto.setId(100L);
|
||||
dto.setDeptId(200L);
|
||||
dto.setInfomationId(300L);
|
||||
dto.setClassesId(400L);
|
||||
dto.setDictionaryDataValue("TYPE");
|
||||
dto.setStatus("ENABLE");
|
||||
dto.setRemark("备注");
|
||||
return dto;
|
||||
}
|
||||
|
||||
private DepartmentMaterialRespVO buildRespVO() {
|
||||
DepartmentMaterialRespVO respVO = new DepartmentMaterialRespVO();
|
||||
respVO.setId(100L);
|
||||
respVO.setDeptId(200L);
|
||||
respVO.setInfomationId(300L);
|
||||
respVO.setClassesId(400L);
|
||||
respVO.setDictionaryDataValue("TYPE");
|
||||
respVO.setRemark("备注");
|
||||
respVO.setStatus("ENABLE");
|
||||
respVO.setMaterialName("原材料");
|
||||
respVO.setCreateTime(LocalDateTime.now());
|
||||
return respVO;
|
||||
}
|
||||
|
||||
@Test
|
||||
void createDepartmentMaterial_shouldForwardToServiceAndReturnConvertedDto() {
|
||||
DepartmentMaterialSaveReqDTO reqDTO = buildSaveReq();
|
||||
DepartmentMaterialRespVO serviceResp = buildRespVO();
|
||||
when(departmentMaterialService.createDepartmentMaterial(any(DepartmentMaterialSaveReqVO.class)))
|
||||
.thenReturn(serviceResp);
|
||||
|
||||
CommonResult<DepartmentMaterialRespDTO> result = api.createDepartmentMaterial(reqDTO);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
DepartmentMaterialRespDTO data = result.getData();
|
||||
assertThat(data.getId()).isEqualTo(serviceResp.getId());
|
||||
assertThat(data.getMaterialName()).isEqualTo("原材料");
|
||||
|
||||
ArgumentCaptor<DepartmentMaterialSaveReqVO> captor = ArgumentCaptor.forClass(DepartmentMaterialSaveReqVO.class);
|
||||
verify(departmentMaterialService).createDepartmentMaterial(captor.capture());
|
||||
DepartmentMaterialSaveReqVO passed = captor.getValue();
|
||||
assertThat(passed.getDeptId()).isEqualTo(reqDTO.getDeptId());
|
||||
assertThat(passed.getInfomationId()).isEqualTo(reqDTO.getInfomationId());
|
||||
assertThat(passed.getDictionaryDataValue()).isEqualTo(reqDTO.getDictionaryDataValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateDepartmentMaterial_shouldInvokeService() {
|
||||
DepartmentMaterialSaveReqDTO reqDTO = buildSaveReq();
|
||||
|
||||
CommonResult<Boolean> result = api.updateDepartmentMaterial(reqDTO);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData()).isTrue();
|
||||
ArgumentCaptor<DepartmentMaterialSaveReqVO> captor = ArgumentCaptor.forClass(DepartmentMaterialSaveReqVO.class);
|
||||
verify(departmentMaterialService).updateDepartmentMaterial(captor.capture());
|
||||
assertThat(captor.getValue().getDeptId()).isEqualTo(reqDTO.getDeptId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteDepartmentMaterial_shouldInvokeService() {
|
||||
CommonResult<Boolean> result = api.deleteDepartmentMaterial(99L);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData()).isTrue();
|
||||
verify(departmentMaterialService).deleteDepartmentMaterial(99L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteDepartmentMaterialList_shouldInvokeService() {
|
||||
List<Long> ids = List.of(1L, 2L, 3L);
|
||||
|
||||
CommonResult<Boolean> result = api.deleteDepartmentMaterialList(ids);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData()).isTrue();
|
||||
verify(departmentMaterialService).deleteDepartmentMaterialListByIds(ids);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDepartmentMaterial_shouldConvertVoToDto() {
|
||||
DepartmentMaterialRespVO respVO = buildRespVO();
|
||||
when(departmentMaterialService.getDepartmentMaterial(11L)).thenReturn(respVO);
|
||||
|
||||
CommonResult<DepartmentMaterialRespDTO> result = api.getDepartmentMaterial(11L);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData().getId()).isEqualTo(respVO.getId());
|
||||
assertThat(result.getData().getMaterialName()).isEqualTo(respVO.getMaterialName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getDepartmentMaterialPage_shouldConvertPageResult() {
|
||||
DepartmentMaterialRespVO respVO = buildRespVO();
|
||||
PageResult<DepartmentMaterialRespVO> page = new PageResult<>(List.of(respVO), 1L);
|
||||
when(departmentMaterialService.getDepartmentMaterialPage(any(DepartmentMaterialPageReqVO.class)))
|
||||
.thenReturn(page);
|
||||
|
||||
DepartmentMaterialPageReqDTO reqDTO = new DepartmentMaterialPageReqDTO();
|
||||
reqDTO.setDeptId(200L);
|
||||
|
||||
CommonResult<PageResult<DepartmentMaterialRespDTO>> result = api.getDepartmentMaterialPage(reqDTO);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData().getList()).hasSize(1);
|
||||
assertThat(result.getData().getList().get(0).getMaterialName()).isEqualTo("原材料");
|
||||
assertThat(result.getData().getTotal()).isEqualTo(1L);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package com.zt.plat.module.base.api.materialclasses;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesPageReqDTO;
|
||||
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesRespDTO;
|
||||
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesSaveReqDTO;
|
||||
import com.zt.plat.module.base.api.materialclasses.dto.MaterialClassesTreeRespDTO;
|
||||
import com.zt.plat.module.base.controller.admin.materialclasses.vo.MaterialClassesPageReqVO;
|
||||
import com.zt.plat.module.base.controller.admin.materialclasses.vo.MaterialClassesRespVO;
|
||||
import com.zt.plat.module.base.controller.admin.materialclasses.vo.MaterialClassesSaveReqVO;
|
||||
import com.zt.plat.module.base.dal.dataobject.materialclasses.MaterialClassesDO;
|
||||
import com.zt.plat.module.base.service.materialclasses.MaterialClassesService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class MaterialClassesApiImplTest {
|
||||
|
||||
@InjectMocks
|
||||
private MaterialClassesApiImpl api;
|
||||
|
||||
@Mock
|
||||
private MaterialClassesService materialClassesService;
|
||||
|
||||
private MaterialClassesSaveReqDTO buildSaveReq() {
|
||||
MaterialClassesSaveReqDTO dto = new MaterialClassesSaveReqDTO();
|
||||
dto.setId(1L);
|
||||
dto.setParentId(0L);
|
||||
dto.setCode("CLS001");
|
||||
dto.setName("原材料");
|
||||
dto.setLevel(1L);
|
||||
dto.setRemark("顶级分类");
|
||||
return dto;
|
||||
}
|
||||
|
||||
private MaterialClassesRespVO buildRespVO() {
|
||||
MaterialClassesRespVO respVO = new MaterialClassesRespVO();
|
||||
respVO.setId(1L);
|
||||
respVO.setParentId(0L);
|
||||
respVO.setCode("CLS001");
|
||||
respVO.setName("原材料");
|
||||
respVO.setLevel(1L);
|
||||
respVO.setRemark("顶级分类");
|
||||
respVO.setCreateTime(LocalDateTime.now());
|
||||
return respVO;
|
||||
}
|
||||
|
||||
@Test
|
||||
void createMaterialClasses_shouldForwardToServiceAndReturnConvertedDto() {
|
||||
MaterialClassesSaveReqDTO reqDTO = buildSaveReq();
|
||||
MaterialClassesRespVO serviceResp = buildRespVO();
|
||||
when(materialClassesService.createMaterialClasses(any(MaterialClassesSaveReqVO.class)))
|
||||
.thenReturn(serviceResp);
|
||||
|
||||
CommonResult<MaterialClassesRespDTO> result = api.createMaterialClasses(reqDTO);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData().getName()).isEqualTo("原材料");
|
||||
|
||||
ArgumentCaptor<MaterialClassesSaveReqVO> captor = ArgumentCaptor.forClass(MaterialClassesSaveReqVO.class);
|
||||
verify(materialClassesService).createMaterialClasses(captor.capture());
|
||||
MaterialClassesSaveReqVO passed = captor.getValue();
|
||||
assertThat(passed.getCode()).isEqualTo(reqDTO.getCode());
|
||||
assertThat(passed.getName()).isEqualTo(reqDTO.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateMaterialClasses_shouldInvokeService() {
|
||||
MaterialClassesSaveReqDTO reqDTO = buildSaveReq();
|
||||
|
||||
CommonResult<Boolean> result = api.updateMaterialClasses(reqDTO);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData()).isTrue();
|
||||
ArgumentCaptor<MaterialClassesSaveReqVO> captor = ArgumentCaptor.forClass(MaterialClassesSaveReqVO.class);
|
||||
verify(materialClassesService).updateMaterialClasses(captor.capture());
|
||||
assertThat(captor.getValue().getCode()).isEqualTo(reqDTO.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteMaterialClasses_shouldInvokeService() {
|
||||
CommonResult<Boolean> result = api.deleteMaterialClasses(5L);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData()).isTrue();
|
||||
verify(materialClassesService).deleteMaterialClasses(5L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteMaterialClassesList_shouldInvokeService() {
|
||||
List<Long> ids = List.of(3L, 4L);
|
||||
|
||||
CommonResult<Boolean> result = api.deleteMaterialClassesList(ids);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData()).isTrue();
|
||||
verify(materialClassesService).deleteMaterialClassesListByIds(ids);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMaterialClasses_shouldConvertDoToDto() {
|
||||
MaterialClassesDO classesDO = new MaterialClassesDO();
|
||||
classesDO.setId(7L);
|
||||
classesDO.setName("辅料");
|
||||
when(materialClassesService.getMaterialClasses(7L)).thenReturn(classesDO);
|
||||
|
||||
CommonResult<MaterialClassesRespDTO> result = api.getMaterialClasses(7L);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData().getId()).isEqualTo(7L);
|
||||
assertThat(result.getData().getName()).isEqualTo("辅料");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMaterialClassesPage_shouldConvertPageResult() {
|
||||
MaterialClassesDO classesDO = new MaterialClassesDO();
|
||||
classesDO.setId(8L);
|
||||
classesDO.setName("辅料");
|
||||
PageResult<MaterialClassesDO> page = new PageResult<>(List.of(classesDO), 1L);
|
||||
when(materialClassesService.getMaterialClassesPage(any(MaterialClassesPageReqVO.class)))
|
||||
.thenReturn(page);
|
||||
|
||||
MaterialClassesPageReqDTO reqDTO = new MaterialClassesPageReqDTO();
|
||||
reqDTO.setName("辅料");
|
||||
|
||||
CommonResult<PageResult<MaterialClassesRespDTO>> result = api.getMaterialClassesPage(reqDTO);
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
assertThat(result.getData().getList()).hasSize(1);
|
||||
assertThat(result.getData().getList().get(0).getName()).isEqualTo("辅料");
|
||||
assertThat(result.getData().getTotal()).isEqualTo(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMaterialClassesTree_shouldAssembleHierarchy() {
|
||||
MaterialClassesDO root = new MaterialClassesDO();
|
||||
root.setId(1L);
|
||||
root.setParentId(0L);
|
||||
root.setName("根节点");
|
||||
|
||||
MaterialClassesDO child = new MaterialClassesDO();
|
||||
child.setId(2L);
|
||||
child.setParentId(1L);
|
||||
child.setName("子节点");
|
||||
|
||||
MaterialClassesDO orphan = new MaterialClassesDO();
|
||||
orphan.setId(3L);
|
||||
orphan.setParentId(99L);
|
||||
orphan.setName("孤儿节点");
|
||||
|
||||
when(materialClassesService.getMaterialClassesList()).thenReturn(List.of(child, root, orphan));
|
||||
|
||||
CommonResult<List<MaterialClassesTreeRespDTO>> result = api.getMaterialClassesTree();
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
List<MaterialClassesTreeRespDTO> tree = result.getData();
|
||||
assertThat(tree).hasSize(2);
|
||||
MaterialClassesTreeRespDTO rootNode = tree.get(0);
|
||||
assertThat(rootNode.getId()).isEqualTo(1L);
|
||||
assertThat(rootNode.getChildren()).hasSize(1);
|
||||
assertThat(rootNode.getChildren().get(0).getId()).isEqualTo(2L);
|
||||
|
||||
MaterialClassesTreeRespDTO orphanNode = tree.get(1);
|
||||
assertThat(orphanNode.getId()).isEqualTo(3L);
|
||||
assertThat(orphanNode.getChildren()).isEmpty();
|
||||
}
|
||||
}
|
||||
140
zt-module-base/主数据同步说明.md
Normal file
140
zt-module-base/主数据同步说明.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# 主数据同步功能说明
|
||||
|
||||
|
||||
## 功能概述
|
||||
|
||||
主数据同步由“分类同步 + 物料同步”两条独立链路组成:
|
||||
|
||||
1. 分类同步:从 `mdm_wlfl_code` 全量拉取 `01 / 0101 / 010101` 结构的编码,生成 BSE 三层分类。
|
||||
2. 物料同步:从 `mdm_material_view` 拉取物料主数据,依赖已存在的分类信息完成入库。
|
||||
3. 物料同步会维护物料与分类绑定关系,并将非主表字段落入属性表。
|
||||
4. 同步结束后可选地向外部回调推送执行报告。
|
||||
|
||||
## 同步入口
|
||||
|
||||
### 分类同步接口
|
||||
|
||||
- **接口地址**:`POST /base/master-data-sync/categories`
|
||||
- **权限点**:`base:master-data-sync:categories`
|
||||
- **请求体**:无(全量同步)
|
||||
- **返回体**:`MasterDataCategorySyncReport`
|
||||
|
||||
字段说明:
|
||||
|
||||
- `processedCategories`:本次遍历的分类数量。
|
||||
- `insertedCategories` / `updatedCategories`:新增或更新的分类记录数。
|
||||
- `missingParentReferences`:外部数据缺失父级时的降级次数(会挂到根节点)。
|
||||
- `success`、`message`、`startedAt`、`finishedAt`:同物料同步。
|
||||
|
||||
> ⚠️ 分类同步需先于物料同步执行,确保 BSE 中已存在三层分类结构。
|
||||
|
||||
### 物料同步接口
|
||||
|
||||
- **接口地址**:`POST /base/master-data-sync/execute`
|
||||
- **权限点**:`base:master-data-sync:execute`
|
||||
- **请求体**:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `since` | `yyyy-MM-dd HH:mm:ss` | (可选)增量同步起始时间,空值表示全量。 |
|
||||
| `batchSize` | `Integer` | (可选)单批拉取条数,未填写则使用配置默认值。 |
|
||||
| `materialCodes` | `List<String>` | (可选)限定仅同步指定物料编码,留空同步全部。 |
|
||||
| `recordLimit` | `Long` | (可选)本次同步允许处理的最大记录数,留空则不做总量限制。 |
|
||||
|
||||
**返回体**为 `MasterDataSyncReport`,涵盖以下关键指标:
|
||||
|
||||
- `processedRecords`:拉取并处理的记录数。
|
||||
- `insertedMaterials` / `updatedMaterials`:新增或更新的物料数量。
|
||||
- `createdClassRelations` / `updatedClassRelations`:物料与分类的关系处理次数。
|
||||
- `insertedPropertyDefinitions` / `updatedPropertyDefinitions`:属性定义的补齐情况。
|
||||
- `insertedPropertyValues` / `updatedPropertyValues`:属性值的写入情况。
|
||||
- `success` + `message`:执行状态及提示语。
|
||||
- `startedAt` / `finishedAt`:执行起止时间。
|
||||
- `recordLimit`:若请求指定了总量限制,会在报告中回显该值。
|
||||
|
||||
## 数据处理策略
|
||||
|
||||
1. **属性字典**:
|
||||
- 程序会检查 `MasterDataPropertyDefinition` 枚举列出的全部属性(例如类别编码、规格、材质等)。
|
||||
- 若属性定义不存在即创建,存在但名称/排序有差异会自动更新。
|
||||
2. **分类管理**:
|
||||
- 通过分类同步接口预先写入 `01/0101/010101` 三层数据,物料同步阶段仅检查并使用现有分类,如缺失则记录日志并跳过绑定。
|
||||
3. **物料主体**:
|
||||
- 按 `material_code` 进行 upsert,保留基础字段(物料编码、通用信息等)。
|
||||
4. **分类绑定**:
|
||||
- 若物料已有绑定但分类变化,则更新关系;否则创建新绑定。
|
||||
5. **属性值写入**:
|
||||
- 对比新旧值,仅在有变化或缺失时写入,避免无效更新。
|
||||
|
||||
## 配置项
|
||||
|
||||
在 `application-*.yml` 中通过 `base.master-data-sync` 节点进行控制:
|
||||
|
||||
```yaml
|
||||
base:
|
||||
master-data-sync:
|
||||
enabled: true # 是否开放同步入口
|
||||
batch-size: 500 # 默认批量大小
|
||||
source-datasource-name: mdm # 指向外部 MDM 的动态数据源
|
||||
notify-on-success: true # 成功时是否回调
|
||||
notify-on-failure: true # 失败时是否回调
|
||||
callback-url: http://example/callback
|
||||
callback-headers:
|
||||
X-TOKEN: xxx
|
||||
http:
|
||||
connect-timeout: 5s
|
||||
read-timeout: 30s
|
||||
write-timeout: 30s
|
||||
```
|
||||
|
||||
> ⚠️ 请确保在 `datasource.dynamic` 中配置名为 `mdm`(或 `source-datasource-name` 指定值)的数据源,并指向外部 MDM 数据库。
|
||||
|
||||
## 数据源说明
|
||||
|
||||
- `master`:默认业务库(BSE 表所在库),所有增删改依旧走 `master` 数据源,这部分无需额外配置。
|
||||
- `mdm`:主数据来源库(外部 MySQL)。`MdmMaterialViewMapper`、`MdmMaterialCategoryMapper` 均通过 `@DS("mdm")` 读取该库。
|
||||
- `base.master-data-sync.source-datasource-name`:若外部库名称不是 `mdm`,可在此覆盖,示例:
|
||||
|
||||
```yaml
|
||||
base:
|
||||
master-data-sync:
|
||||
source-datasource-name: mdm
|
||||
datasource:
|
||||
dynamic:
|
||||
datasource:
|
||||
master: { ...本地库配置... }
|
||||
mdm: { url: jdbc:mysql://mdm-host/mdm, username: xxx, password: yyy }
|
||||
```
|
||||
|
||||
> ✅ 强调:主数据读取始终走 `mdm`(或你在 `source-datasource-name` 中声明的别名),不要与默认 `master` 数据源混淆。
|
||||
|
||||
## 回调机制
|
||||
|
||||
- 当配置了 `callbackUrl` 时,系统会在同步结束后推送 JSON 结果。
|
||||
- 推送内容为:
|
||||
|
||||
```json
|
||||
{
|
||||
"report": { ...MasterDataSyncReport... },
|
||||
"errorMessage": "可选的错误提示"
|
||||
}
|
||||
```
|
||||
|
||||
- 仅成功/失败分别受 `notifyOnSuccess`、`notifyOnFailure` 控制。
|
||||
- `callbackHeaders` 支持附加认证信息,如 Token、租户标识等。
|
||||
|
||||
## 常见问题排查
|
||||
|
||||
| 问题 | 检查点 |
|
||||
| --- | --- |
|
||||
| 数据源连接失败 | 确认 `mdm` 数据源配置、账号权限、网络可达性。 |
|
||||
| 同步后未触发回调 | 检查 `callbackUrl`、`notify-on-*` 配置,以及目标地址是否可达。 |
|
||||
| 属性值未生效 | 查看 `MasterDataPropertyDefinition` 是否包含该字段,或字段值是否为空/仅有空格。 |
|
||||
| 只需同步单个物料 | 调用接口时在 `materialCodes` 中传入目标编码即可。 |
|
||||
|
||||
## 建议的使用流程
|
||||
|
||||
1. 配置并验证外部数据源与 `base.master-data-sync` 参数。
|
||||
2. 先执行“分类同步接口”,确认三层分类齐全。
|
||||
3. 再执行“物料同步接口”,并确认报表数据、回调通知。
|
||||
4. 线上场景可定期以 `since` 参数驱动增量物料同步,也可按需指定 `materialCodes` 触发刷新;分类若有改动,可重新全量执行一次分类同步。
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.zt.plat.module.contractorder.enums.contract;
|
||||
|
||||
/**
|
||||
* 合同审核结果
|
||||
*/
|
||||
public enum AuditResultEnum {
|
||||
/**
|
||||
* 合同状态-草稿
|
||||
*/
|
||||
PASS("通过","PASS", null),
|
||||
/**
|
||||
* 合同状态-正在审核
|
||||
*/
|
||||
REJECT("驳回","REJECT",null);
|
||||
|
||||
AuditResultEnum(String label, String code, String remark) {
|
||||
this.label = label;
|
||||
this.code = code;
|
||||
this.remark = remark;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标签
|
||||
*/
|
||||
private final String label;
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
private final String code;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private final String remark;
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,8 @@ knife4j:
|
||||
|
||||
# MyBatis Plus 的配置项
|
||||
mybatis-plus:
|
||||
mapper-locations:
|
||||
- classpath*:mapper/**/*.xml
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
|
||||
global-config:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<configuration>
|
||||
<!-- 引用 Spring Boot 的 logback 基础配置 -->
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
|
||||
<!-- 变量 cloud.info.base-package,基础业务包 -->
|
||||
<springProperty scope="context" name="cloud.info.base-package" source="cloud.info.base-package"/>
|
||||
<!-- 变量 zt.info.base-package,基础业务包 -->
|
||||
<springProperty scope="context" name="zt.info.base-package" source="zt.info.base-package"/>
|
||||
<!-- 格式化输出:%d 表示日期,%X{tid} SkWalking 链路追踪编号,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度,%msg:日志消息,%n是换行符 -->
|
||||
<property name="PATTERN_DEFAULT" value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread [%tid]) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
</appender>
|
||||
|
||||
<!-- 本地环境 -->
|
||||
<springProfile name="local">
|
||||
<springProfile name="local,dev">
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="GRPC"/> <!-- 本地环境下,如果不想接入 SkyWalking 日志服务,可以注释掉本行 -->
|
||||
@@ -65,8 +65,8 @@
|
||||
</root>
|
||||
</springProfile>
|
||||
<!-- 其它环境 -->
|
||||
<springProfile name="dev,test,stage,prod,default">
|
||||
<root level="DEBUG">
|
||||
<springProfile name="test,stage,prod,default">
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="ASYNC"/>
|
||||
<appender-ref ref="GRPC"/>
|
||||
|
||||
Reference in New Issue
Block a user