重新初始化项目

This commit is contained in:
2025-08-22 19:55:19 +08:00
commit 65bc67460b
805 changed files with 83402 additions and 0 deletions

36
.gitignore vendored Normal file
View File

@@ -0,0 +1,36 @@
HELP.md
logs/
release/
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
.lock
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

View File

@@ -0,0 +1,270 @@
你是一个资深的java专家请在开发中遵循如下规则
- 严格遵循 **SOLID、DRY、KISS、YAGNI** 原则
- 遵循 **OWASP 安全最佳实践**如输入验证、SQL注入防护
- 采用 **分层架构设计**,确保职责分离
- 代码变更需通过 **单元测试覆盖**(测试覆盖率 ≥ 80%
---
## 二、技术栈规范
### 技术栈要求
- **框架**JavaFx 22 + Spring Boot 3.x + Java 21
- **依赖**
- 核心Spring Data JPA, Lombok
- 数据库MySQL Driver、MsSQL Driver
- 其他controlsfx
---
## 三、应用逻辑设计规范
### 1. 分层架构原则
| 层级 | 职责 | 约束条件 |
|----------------|------------------------|----------------------------------------------------------|
| **Controller** | 处理 fxml 请求与响应,定义 API 接口 | - 禁止直接操作数据库<br>- 必须通过 Service 层调用 |
| **Service** | 业务逻辑实现,事务管理,数据校验 | - 必须通过 Repository 访问数据库<br>- 返回 DTO 而非实体类(除非必要) |
| **Repository** | 数据持久化操作,定义数据库查询逻辑 | - 必须继承 `MyRepository`<br>- 使用 `@EntityGraph` 避免 N+1 查询问题 |
| **Entity** | 数据库表结构映射对象 | - 仅用于数据库交互<br>- 禁止直接返回给前端(需通过 DTO 转换) |
| **Tasker** | 运行的任务 | - |
| **ViewModel** | 界面数据模型 | - |
| **.fxml** | UI 界面逻辑 | - 位于 /resources/ui/ |
---
## 四、核心代码规范
### 1. 实体类Entity规范
```java
@Entity
@Data // Lombok 注解
@Table(name = "USER") // 数据表名,默认为大写的类名
public class User {
@Id
@Column(name = "ID", nullable = false) // 字段名大写
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "USERNAME") // 字段名大写
@Size(min = 3, max = 50)
private String username;
// 关联关系使用懒加载
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "DEPARTMENT_ID") // 关联关系,字段名大写
private Department department;
}
```
### 2. 数据访问层Repository规范
```java
public interface UserRepository extends MyRepository<User, Integer> {
// 命名查询
Optional<User> findByUsername(String username);
// 自定义 JPQL 查询
@Query("SELECT u FROM User u JOIN FETCH u.department WHERE u.id = :id")
@EntityGraph(attributePaths = {"department"})
Optional<User> findUserWithDepartment(@Param("id") Long id);
}
```
### 3. 服务层Service规范
```java
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public ApiResponse<UserDTO> createUser(UserDTO dto) {
// 业务逻辑实现
User user = User.builder().username(dto.getUsername()).build();
User savedUser = userRepository.save(user);
return ApiResponse.success(UserDTO.fromEntity(savedUser));
}
}
```
### 4. 控制器Controller规范
```java
@Lazy
@Scope("prototype") // 单例
@Component
@FxmlPath("/ui/employee/employee.fxml") // FXML 文件路径
public class EmployeeWindowController extends AbstEntityController<Employee, EmployeeViewModel>{
public BorderPane root;
public TabPane tabPane;
public Tab baseInfoTab;
public Tab rolesTab;
public Tab loginHistoryTab;
public Tab authBindTab;
@Autowired
private EmployeeService employeeService;
@Override
public void onShown(WindowEvent windowEvent) {
super.onShown(windowEvent);
getTitle().bind(viewModel.getName().map(name -> "[" + viewModel.getId().get() + "] " + name + " 员工详情"));
}
@Override
protected void registerTabSkins() {
registerTabSkin(baseInfoTab, tab -> new EmployeeTabSkinBase(this));
registerTabSkin(rolesTab, tab -> new EmployeeTabSkinRole(this));
registerTabSkin(loginHistoryTab, tab -> new EmployeeTabSkinLoginHistory(this));
}
@Override
public EmployeeService getViewModelService() {
return employeeService;
}
}
```
---
## 五、Tab 界面控制
```java
public class EmployeeTabSkinBase
extends AbstEmployeeBasedTabSkin
implements TabSkin {
public EmployeeTabSkinBase(EmployeeWindowController controller) {
super(controller);
}
@Override
public Tab getTab() {
return controller.baseInfoTab;
}
@Override
public void initializeTab() {
}
}
@FxmlPath("/ui/employee/employee-login-history.fxml")
public class EmployeeTabSkinLoginHistory
extends AbstEmployeeTableTabSkin<EmployeeLoginHistory, EmployeeLoginHistoryViewModel>
implements TabSkin {
public TableColumn<EmployeeLoginHistoryViewModel, Number> idColumn;
public TableColumn<EmployeeLoginHistoryViewModel, String> ipColumn;
public TableColumn<EmployeeLoginHistoryViewModel, String> macColumn;
public TableColumn<EmployeeLoginHistoryViewModel, LocalDateTime> loginTimeColumn;
public TableColumn<EmployeeLoginHistoryViewModel, LocalDateTime> activeTimeColumn;
private EmployeeLoginHistoryService loginHistoryService;
public EmployeeTabSkinLoginHistory(EmployeeWindowController controller) {
super(controller);
}
EmployeeLoginHistoryService getLoginHistoryService() {
if (loginHistoryService == null) {
loginHistoryService = getBean(EmployeeLoginHistoryService.class);
}
return loginHistoryService;
}
@Override
protected EmployeeLoginHistoryService getViewModelService() {
return getLoginHistoryService();
}
@Override
public Tab getTab() {
return controller.loginHistoryTab;
}
@Override
public void initializeTab() {
super.initializeTab();
idColumn.setCellValueFactory(param -> param.getValue().getId());
ipColumn.setCellValueFactory(param -> param.getValue().getIp());
macColumn.setCellValueFactory(param -> param.getValue().getMac());
loginTimeColumn.setCellValueFactory(param -> param.getValue().getLoginTime());
loginTimeColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
activeTimeColumn.setCellValueFactory(param -> param.getValue().getActiveTime());
activeTimeColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
Platform.runLater(() -> {
getTableView().getSortOrder().add(activeTimeColumn);
});
}
}
```
---
## 六、全局异常处理规范
```java
```
### 2. 全局异常处理器GlobalExceptionHandler
```java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<ApiResponse<?>> handleEntityNotFound(EntityNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(ApiResponse.error(ex.getMessage()));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiResponse<?>> handleValidationErrors(MethodArgumentNotValidException ex) {
String errorMessage = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.joining(", "));
return ResponseEntity.badRequest().body(ApiResponse.error(errorMessage));
}
}
```
---
## 七、安全与性能规范
1. 输入校验:
2. **事务管理**
- `@Transactional` 注解仅标注在 Service 方法上
- 避免在循环中频繁提交事务
3. **性能优化**
- 使用 `@EntityGraph` 预加载关联关系
- 避免在循环中执行数据库查询(批量操作优先)
---
## 八、代码风格规范
1. **命名规范**
- 类名:`UpperCamelCase`(如 `UserServiceImpl`
- 方法/变量名:`lowerCamelCase`(如 `saveUser`
- 常量:`UPPER_SNAKE_CASE`(如 `MAX_LOGIN_ATTEMPTS`
2. **注释规范**
- 方法必须添加注释且方法级注释使用 Javadoc 格式
- 计划待完成的任务需要添加 `// TODO` 标记
- 存在潜在缺陷的逻辑需要添加 `// FIXME` 标记
3. **代码格式化**
- 使用 IntelliJ IDEA 默认的 Spring Boot 风格
- 禁止手动修改代码缩进(依赖 IDE 自动格式化)
---
## 九、部署规范
1. **部署规范**
- 生产环境需禁用 `@EnableAutoConfiguration` 的默认配置
- 敏感信息通过 `application.properties` 外部化配置
- 使用 `Spring Profiles` 管理环境差异(如 `dev`, `prod`
---
## 十、扩展性设计规范
1. **接口优先**
- 服务层接口(`UserService`)与实现(`UserServiceImpl`)分离
2. **扩展点预留**
- 关键业务逻辑需提供 `Strategy``Template` 模式支持扩展
3. **日志规范**
- 使用 `SLF4J` 记录日志(禁止直接使用 `System.out.println`
- 核心操作需记录 `INFO` 级别日志,异常记录 `ERROR` 级别
```

4
.mvn/maven.config Normal file
View File

@@ -0,0 +1,4 @@
-Dfile.encoding=UTF-8
-Dmaven.compiler.source=21
-Dmaven.compiler.target=21
-Dmaven.compiler.encoding=UTF-8

19
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View File

@@ -0,0 +1,19 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
wrapperVersion=3.3.2
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.7/apache-maven-3.9.7-bin.zip

0
.trae/.ignore Normal file
View File

View File

@@ -0,0 +1,13 @@
Java 21
Spring Boot 3.3.7
Spring Data JPA 3.3.7
JavaFX 21
ControlsFX 11.1.2
MySQL 8.0.33
Lombok 1.18.32
POI 5.2.5
PDFBox 3.0.1
ignore:
- .idea
- target

33
README.md Normal file
View File

@@ -0,0 +1,33 @@
## 项目改进与优化分析报告
### 1. 同步任务与调度优化
- 调度策略优化 :各同步任务(如 ContractSyncTask 、 VendorSyncTask )使用不同的调度间隔和策略,建议统一调度配置,避免重复执行和资源浪费
- 增量同步实现 多数同步任务缺乏断点续传机制建议添加基于最后同步ID或时间戳的增量同步功能
- 任务依赖管理 :部分任务存在隐式依赖关系(如 OldVersionSyncVendorTask 中的多步骤执行),建议引入任务依赖管理机制
### 2. 线程池与异步处理
- 线程池配置 :当前项目未明确配置线程池参数(核心线程数、最大线程数等),建议在 SpringApp 中添加显式线程池配置
- 线程池隔离 不同类型的任务IO密集型、CPU密集型应使用不同线程池避免资源竞争
- 异步任务监控 :添加异步任务执行状态监控和超时处理机制,避免任务长时间阻塞
### 3. 缓存机制优化
- 缓存策略细化 :当前缓存配置较为简单( CaffeineCacheManager ),建议为不同类型数据配置差异化缓存策略(过期时间、最大容量等)
- 缓存一致性 :修复 CloudRkService 中缓存更新问题(注释中提到的"这个可以无法更新缓存"
- 缓存预热 :添加关键数据缓存预热机制,提高系统启动后响应速度
### 4. 依赖注入与懒加载
- 依赖注入规范化 :减少 SpringApp.getBean() 手动获取bean的方式推广构造函数注入或字段注入
- 懒加载优化 :充分利用 @Lazy 注解和 BootstrapMode.LAZY 配置,优化应用启动性能
- 服务解耦 :继续推进服务拆分工作(如之前的 ContractService 拆分为专用服务),减少服务间耦合
### 5. 异常处理与重试机制
- 异常处理统一 :规范异常处理策略,确保所有异常都被适当记录和处理
- 重试机制添加 :为网络请求和数据库操作添加重试机制(如使用 Spring Retry
- 熔断降级 对外部系统调用如用友U8接口添加熔断降级机制提高系统稳定性
### 6. 数据库操作优化
- 批量操作引入 对大量数据的CRUD操作建议使用批量处理API提高性能
- 查询优化 :添加适当索引,优化复杂查询,避免全表扫描
- 连接池配置 :优化 HikariDataSource 配置参数(如连接池大小、超时时间等)
### 7. 代码质量与维护性
- 重复代码消除 :提取同步任务中的共同逻辑(如进度更新、异常处理)为抽象基类
- 注释完善 :补充关键类和方法的文档注释,特别是复杂业务逻辑和优化点
- 技术债务清理 解决代码中的TODO项如 CloudRkService 中的缓存更新问题)
### 8. 配置管理优化
- 配置集中管理 :将分散在代码中的配置项(如同步间隔、批处理大小)集中到配置文件
- 动态配置支持 :添加动态配置更新机制,避免重启应用
以上优化点已按优先级和影响范围排序,建议逐步实施。实施过程中应注意性能测试和兼容性验证,确保优化不会引入新问题。

9
config.properties Normal file
View File

@@ -0,0 +1,9 @@
#Updated config.properties
#Wed Mar 26 16:33:45 CST 2025
cloud.u8.enabled=true
db.server.database=supplier_ms
db.server.host=db-server1.ecctrl.com
db.server.password=ecep.62335656
db.server.port=3306
db.server.username=ecep
username_password.remember=true

1
cookie.json Normal file

File diff suppressed because one or more lines are too long

256
dependency-reduced-pom.xml Normal file
View File

@@ -0,0 +1,256 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>3.3.7</version>
<relativePath>pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.ecep.contract</groupId>
<artifactId>Contract-Manager</artifactId>
<name>Contract-Manager</name>
<version>0.0.1-SNAPSHOT</version>
<description>Contract-Manager</description>
<developers>
<developer>
<id>1</id>
<name>宋其青</name>
<email>qiqing.song@ecep.com</email>
</developer>
</developers>
<licenses>
<license />
</licenses>
<scm />
<build>
<plugins>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>com.ecep.contract.manager.AppV2</mainClass>
<launcher>app</launcher>
<jlinkZipName>app-jlink</jlinkZipName>
<jlinkImageName>app-jlink-image</jlinkImageName>
<noManPages>true</noManPages>
<stripDebug>true</stripDebug>
<compress>2</compress>
</configuration>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>3.3.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>3.3.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>12.6.4.jre11</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.1.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>3.3.7</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>spring-boot-test</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
<exclusion>
<artifactId>spring-boot-test-autoconfigure</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
<exclusion>
<artifactId>json-path</artifactId>
<groupId>com.jayway.jsonpath</groupId>
</exclusion>
<exclusion>
<artifactId>json-smart</artifactId>
<groupId>net.minidev</groupId>
</exclusion>
<exclusion>
<artifactId>assertj-core</artifactId>
<groupId>org.assertj</groupId>
</exclusion>
<exclusion>
<artifactId>awaitility</artifactId>
<groupId>org.awaitility</groupId>
</exclusion>
<exclusion>
<artifactId>hamcrest</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
<exclusion>
<artifactId>junit-jupiter</artifactId>
<groupId>org.junit.jupiter</groupId>
</exclusion>
<exclusion>
<artifactId>mockito-core</artifactId>
<groupId>org.mockito</groupId>
</exclusion>
<exclusion>
<artifactId>mockito-junit-jupiter</artifactId>
<groupId>org.mockito</groupId>
</exclusion>
<exclusion>
<artifactId>jsonassert</artifactId>
<groupId>org.skyscreamer</groupId>
</exclusion>
<exclusion>
<artifactId>spring-test</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>xmlunit-core</artifactId>
<groupId>org.xmlunit</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>3.3.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jdbc</artifactId>
<version>3.3.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.3.0</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>protobuf-java</artifactId>
<groupId>com.google.protobuf</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>3.3.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>3.3.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>22.0.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>22.0.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>22.0.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.controlsfx</groupId>
<artifactId>controlsfx</artifactId>
<version>11.2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.17.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.5.12</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.3</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<java.version>22</java.version>
<poi.version>5.3.0</poi.version>
<javafx.version>22.0.2</javafx.version>
</properties>
</project>

29
docs/Black_Reason.json Normal file
View File

@@ -0,0 +1,29 @@
{
"id": 7398596,
"entId": "10275671",
"entName": "上海星宇建设集团有限公司",
"entType": "E",
"blackGrey": "黑",
"blackLevel": "1",
"subordinateBusinessParty": null,
"subordinateBusinessPartyNm": "全集团",
"businessArea": "6",
"includeDate": "2024-06-28",
"dataSources": "4",
"blackReason": "已被列为失信被执行人",
"applyName": "外部",
"applyDate": "2024-06-28",
"processId": null,
"formInstanceId": null,
"description": "案号2021沪0110执1129号 失信被执行人具体行为:有履行能力而拒不履行生效法律文书确定义务 生效法律文书确定义务:无 被执行人履行情况:全部未履行 执行法院310202",
"balckTemplateId": null,
"removeDate": null,
"blackStatus": "1",
"createTime": "2024-06-28",
"uploadingDocuments": null,
"uploadingName": null,
"source": "外部数据",
"ispublic": "0",
"updateTime": "2024-06-28",
"createByName": null
}

43
docs/Ent_Fuzzy.json Normal file
View File

@@ -0,0 +1,43 @@
{
"data" : [ {
"entid" : "pWjJpZENa",
"entname" : "中国移动通信集团有限公司",
"isNowName" : "0"
}, {
"entid" : "PfMGOgxfEV",
"entname" : "中国石油天然气股份有限公司",
"isNowName" : "0"
}, {
"entid" : "v5asxpqV",
"entname" : "华能国际电力股份有限公司",
"isNowName" : "0"
}, {
"entid" : "VyDNRKw9J89",
"entname" : "国家能源集团宁夏煤业有限责任公司",
"isNowName" : "0"
}, {
"entid" : "pKVZYm8db6t",
"entname" : "宏润建设集团股份有限公司",
"isNowName" : "0"
}, {
"entid" : "LzMLH2winP",
"entname" : "抚顺矿业集团有限责任公司",
"isNowName" : "0"
}, {
"entid" : "jz7PqUtTBK9",
"entname" : "中国移动通信集团湖北有限公司",
"isNowName" : "0"
}, {
"entid" : "ywxksg38oLO",
"entname" : "中国广电四川网络股份有限公司",
"isNowName" : "0"
}, {
"entid" : "faVnctUWKa",
"entname" : "中国石油化工股份有限公司",
"isNowName" : "0"
}, {
"entid" : "j2zbBGHC0QV",
"entname" : "山东莱芜农村商业银行股份有限公司",
"isNowName" : "0"
} ]
}

157
docs/Ent_Report_B1001.json Normal file
View File

@@ -0,0 +1,157 @@
{
"B1001" : {
"data" : {
"esdate" : "1995-03-13",
"nameHistory" : "",
"dom" : "上海市宝山区杨泰路868号",
"reccap" : 37234.2827,
"enttype" : "有限责任公司(台港澳与境内合资)",
"nacaoid" : "607300405",
"opfrom" : "1995-03-13",
"exenum" : null,
"parform" : "",
"localadm" : null,
"insform" : null,
"entname" : "上海一冷开利空调设备有限公司",
"nicfulltitle" : "制造业-通用设备制造业-烘炉、风机、包装等设备制造-制冷、空调设备制造",
"regorg" : "上海市市场监督管理局",
"tel" : "021-26092000",
"abuitem" : "生产空调制冷、采暖、通风设备及相关零部件,销售自产产品;自产产品及同类商品的批发、进出口、佣金代理(拍卖除外);机电设备安装工程、建筑智能化工程专业承包;提供相关技术咨询、售后服务等配套服务(不涉及国营贸易管理商品,涉及配额、许可证管理及建筑业资质要求的,需在取得许可证和相应资质后开展经营业务)。【依法须经批准的项目,经相关部门批准后方可开展经营活动】",
"email" : "ming.jiang@carrier.utc.com",
"frname" : "汤盛锋",
"regno" : "310000400109398",
"opto" : "2045-03-12",
"ancheyear" : "2023",
"seicfulltitle" : null,
"domproright" : null,
"parnum" : null,
"cbuitem" : "生产空调制冷、采暖、通风设备及相关零部件,销售自产产品;自产产品及同类商品的批发、进出口、佣金代理(拍卖除外);机电设备安装工程、建筑智能化工程专业承包;提供相关技术咨询、售后服务等配套服务(不涉及国营贸易管理商品,涉及配额、许可证管理及建筑业资质要求的,需在取得许可证和相应资质后开展经营业务)。【依法须经批准的项目,经相关部门批准后方可开展经营活动】",
"oploc" : "上海市宝山区杨泰路868号",
"regcapcur" : "人民币元",
"empnum" : "331",
"uniscid" : "913100006073004059",
"opscoandform" : "生产空调制冷、采暖、通风设备及相关零部件,销售自产产品;自产产品及同类商品的批发、进出口、佣金代理(拍卖除外);机电设备安装工程、建筑智能化工程专业承包;提供相关技术咨询、售后服务等配套服务(不涉及国营贸易管理商品,涉及配额、许可证管理及建筑业资质要求的,需在取得许可证和相应资质后开展经营业务)。【依法须经批准的项目,经相关部门批准后方可开展经营活动】",
"regcap" : "37234.2827万",
"regorgprovince" : "上海市宝山区",
"limparnum" : null,
"entstatus" : "在营(开业)",
"apprdate" : "2024-07-11"
},
"count" : 1,
"ishide" : true,
"header" : [ {
"key" : "entName",
"label" : "企业名称"
}, {
"key" : "historyName",
"label" : "曾用名",
"only" : true
}, {
"key" : "regno",
"label" : "工商注册号"
}, {
"key" : "frname",
"label" : "法定代表人"
}, {
"key" : "uniscid",
"label" : "统一社会信用代码",
"only" : true
}, {
"key" : "regcap",
"label" : "注册资本"
}, {
"key" : "regcapcur",
"label" : "注册资本币种"
}, {
"key" : "entstatus",
"label" : "经营状态"
}, {
"key" : "enttype",
"label" : "企业(机构)类型"
}, {
"key" : "esdate",
"label" : "注册日期"
}, {
"key" : "opfrom",
"label" : "经营期限自"
}, {
"key" : "opto",
"label" : "经营期限至"
}, {
"key" : "regorgprovince",
"label" : "所在地"
}, {
"key" : "dom",
"label" : "注册地址",
"only" : true
}, {
"key" : "regorg",
"label" : "注册机关"
}, {
"key" : "reccap",
"label" : "实收资本(万)",
"only" : true
}, {
"key" : "ancheyear",
"label" : "最后年检日期",
"only" : true
}, {
"key" : "empnum",
"label" : "员工人数",
"only" : true
}, {
"key" : "apprdate",
"label" : "核准日期"
}, {
"key" : "oploc",
"label" : "经营场所",
"only" : true
}, {
"key" : "email",
"label" : "邮箱"
}, {
"key" : "tel",
"label" : "电话"
}, {
"key" : "domproright",
"label" : "住所产权",
"only" : true
}, {
"key" : "insform",
"label" : "设立方式",
"only" : true
}, {
"key" : "parnum",
"label" : "合伙人数",
"only" : true
}, {
"key" : "limparnum",
"label" : "有限合伙人数",
"only" : true
}, {
"key" : "parform",
"label" : "合伙方式",
"only" : true
}, {
"key" : "exenum",
"label" : "执行人数",
"only" : true
}, {
"key" : "nicfulltitle",
"label" : "经济行业分类"
}, {
"key" : "seicfulltitle",
"label" : "战兴产业分类",
"only" : true
}, {
"key" : "abuitem",
"label" : "许可经营项目",
"only" : true
}, {
"key" : "opscoandform",
"label" : "经营(业务)范围"
} ],
"text" : "基本注册信息",
"source" : "国家市场监督管理总局"
}
}

24
docs/Ent_Score.json Normal file
View File

@@ -0,0 +1,24 @@
{
"success" : true,
"code" : 20000,
"message" : "成功",
"data" : {
"adverses" : [ {
"adverseEvent" : "被执行人",
"score" : 10,
"count" : 1
} ],
"reduceScore" : 10,
"level" : "C",
"AHP" : false,
"entTypeCheck" : {
"entType" : "国企",
"finalentname" : "开利亚洲有限公司",
"score" : 75,
"ratioroad" : "70.0%",
"id" : null
},
"adverseChecks" : [ ],
"levelDescription" : "信用资质中等"
}
}

21
docs/Report_Detail.json Normal file
View File

@@ -0,0 +1,21 @@
{
"success" : true,
"code" : 20000,
"total" : null,
"message" : "成功",
"data" : {
"entid" : 8853120,
"entname" : "上海华启电器设备有限公司",
"externalEnvironment" : 526,
"enterpriseCharacteristics" : 731,
"stability" : 950,
"managementLevel" : 675,
"negativeRisk" : 699,
"associatedRisk" : 980,
"totalScore" : 720,
"grade" : "R2",
"description" : "次优的等级,具有几乎最好的信用质量。",
"updated" : "2024-10-09T07:43:24.000+00:00",
"entUrl" : "https://rk.shanghai-electric.com/rk-platform/unified-query/panoramic/Za0Wi8Dz17V/上海华启电器设备有限公司"
}
}

BIN
docs/S24036/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
docs/S24036/img_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
docs/S24036/img_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

40
docs/SupplierScore.json Normal file
View File

@@ -0,0 +1,40 @@
{
"success" : true,
"code" : 20000,
"total" : null,
"message" : "成功",
"data" : {
"id" : 6302179,
"entid" : "9996400",
"entname" : "上海一冷开利空调设备有限公司",
"score" : 425,
"s1" : 615,
"s2Ys" : 320,
"s3" : 506,
"s4" : 820,
"s101" : 680,
"s102" : 550,
"s201" : 500,
"s202Ys" : 275,
"s301" : 475,
"s302" : 390,
"s303" : 800,
"s401" : 825,
"s402" : 800,
"scoreLevel" : "R3",
"scoreDes" : "次优资质,供应商有较优的企业表现。",
"s1Des" : "较好",
"s2YsDes" : "一般",
"s3Des" : "一般",
"s4Des" : "很好",
"s101Des" : "较好",
"s102Des" : "较好",
"s201Des" : "一般",
"s202YsDes" : "较差",
"s301Des" : "一般",
"s302Des" : "较差",
"s303Des" : "很好",
"s401Des" : "很好",
"s402Des" : "较好"
}
}

6
docs/readme.txt Normal file
View File

@@ -0,0 +1,6 @@
list = [
ProjectCost(id=10, applyDate=null, standardPayWay=false, noStandardPayWayText=null, standardContractText=false, noStandardContractText=null, stampTax=0.0, stampTaxFee=0.0, onSiteServiceFee=0.0, assemblyServiceFee=0.0, technicalServiceFee=0.0, bidServiceFee=0.0, freightCost=0.0, guaranteeLetterFee=0.0, taxAndSurcharges=0.0, taxAndSurchargesFee=0.0, inQuantities=0.0, inTaxAmount=0.0, inExclusiveTaxAmount=0.0, outQuantities=0.0, outTaxAmount=0.0, outExclusiveTaxAmount=0.0, grossProfitMargin=0.0),
ProjectCost(id=11, applyDate=null, standardPayWay=false, noStandardPayWayText=null, standardContractText=false, noStandardContractText=null, stampTax=0.0, stampTaxFee=0.0, onSiteServiceFee=0.0, assemblyServiceFee=0.0, technicalServiceFee=0.0, bidServiceFee=0.0, freightCost=0.0, guaranteeLetterFee=0.0, taxAndSurcharges=0.0, taxAndSurchargesFee=0.0, inQuantities=0.0, inTaxAmount=0.0, inExclusiveTaxAmount=0.0, outQuantities=0.0, outTaxAmount=0.0, outExclusiveTaxAmount=0.0, grossProfitMargin=0.0)
]

284
docs/temp.sql Normal file
View File

@@ -0,0 +1,284 @@
/** MySQL **/
GRANT ALL PRIVILEGES ON *.* TO 'ecep'@'10.84.209.89' WITH GRANT OPTION;
/** 修改用户密码 **/
ALTER USER 'mianli.wang'@'10.84.209.38' IDENTIFIED WITH mysql_native_password BY 'A2025b0512#';
/* 查询CLOUD_YU表中VEN_CODE不以 | 开头的记录 */
select *
from CLOUD_YU
where EX_MSG not like '|%';
select *
from VENDOR;
/* 查询一级行业分类 */
SELECT SUBSTRING_INDEX(INDUSTRY, '-', 1) as title, COUNT(*) as total
FROM `COMPANY`
where COMPANY.INDUSTRY is not null
and length(INDUSTRY) > 0
GROUP BY title
order by total DESC;
/* 查询一级二级行业分类 */
SELECT SUBSTRING_INDEX(INDUSTRY, '-', 2) as title, COUNT(*) as total
FROM `COMPANY`
where SUBSTRING_INDEX(INDUSTRY, '-', 1) = '交通运输、仓储和邮政业'
GROUP BY title
order by total desc;
select COMPANY_ID, count(*)
from COMPANY_CONTRACT
group by COMPANY_ID;
select *
from CONTRACT
left join supplier_ms.COMPANY_CONTRACT CC on CONTRACT.ID = CC.CONTRACT_ID
where CC.ID is null;
select *
from CONTRACT
where CODE = 'S23108';
select *, locate('-', CODE)
from CONTRACT
# where PARENT_CODE is null or length(PARENT_CODE) = 0
where locate('-', CODE) = 0
order by CREATED desc
limit 100;
select *
from COMPANY_VENDOR
where VEN_CODE like '%|shykwlyxgs|%';
select *
from COMPANY_VENDOR
where COMPANY_ID = 3;
select *
from COMPANY_CUSTOMER
where CUS_CODE like '%|shykwlyxgs|%';
select *
from COMPANY_CUSTOMER
where COMPANY_ID = 795;
select *
from CONTRACT
where GUID = '7A839F83-70FF-4F3F-9063-F930B93F1445';
select *
from COMPANY
where NAME = '德州六顺电气自动化设备有限公司';
select GUID, COUNT(*)
from CONTRACT
group by GUID
having count(*) > 1;
select COMPANY_ID, count(*) as total
from COMPANY_VENDOR
group by COMPANY_ID
having total > 1;
select COMPANY_ID, count(*) as total
from COMPANY_CUSTOMER
group by COMPANY_ID
having total > 1;
select NAME, count(*) as total
from VENDOR
group by NAME
having total > 1;
select *
from COMPANY_CUSTOMER_FILE CCF
left join COMPANY_CUSTOMER_EVALUATION_FORM_FILE on CCF.ID = COMPANY_CUSTOMER_EVALUATION_FORM_FILE.ID
where CUSTOMER_ID = 1266
and CCF.TYPE = 'EvaluationForm';
select cceff1_0.ID,
cceff1_1.CUSTOMER_ID,
cceff1_1.EDIT_FILE_PATH,
cceff1_1.FILE_PATH,
cceff1_1.SIGN_DATE,
cceff1_1.TYPE,
cceff1_1.VALID,
cceff1_0.CATALOG,
cceff1_0.CREDIT_LEVEL,
cceff1_0.LEVEL,
cceff1_0.score1,
cceff1_0.score2,
cceff1_0.score3,
cceff1_0.score4,
cceff1_0.score5,
cceff1_0.SCORE_TEMPLATE_VER
from COMPANY_CUSTOMER_FILE ccf1_0
left join (COMPANY_CUSTOMER_EVALUATION_FORM_FILE cceff1_0 join COMPANY_CUSTOMER_FILE cceff1_1
on cceff1_0.ID = cceff1_1.ID) on ccf1_0.ID = cceff1_0.ID
where ccf1_0.CUSTOMER_ID = 1266
and ccf1_0.TYPE = 'EvaluationForm';
/**
* 统计合同的State数量
*/
select STATE, COUNT(*)
from CONTRACT
group by STATE
having count(*) > 1;
/**
* 统计从2024年合同的GROUP数量
*/
select GROUP_ID, COUNT(*)
from CONTRACT
where CONTRACT.SETUP_DATE between '2024-01-01' and '2024-12-31'
group by GROUP_ID
having count(*) > 1;
INSERT INTO PRODUCT_DELIVERY_SIGN_METHOD (NAME, CODE)
VALUES ('到货签收', 'A');
INSERT INTO PRODUCT_DELIVERY_SIGN_METHOD (NAME, CODE)
VALUES ('到货签收+拼装签收', 'P');
INSERT INTO PRODUCT_USAGE (NAME, CODE)
VALUES ('高效机房', 'H');
INSERT INTO PRODUCT_USAGE (NAME, CODE)
VALUES ('能源站', 'E');
INSERT INTO PRODUCT_USAGE (NAME, CODE)
VALUES ('高效机房+能源站', 'F');
INSERT INTO PRODUCT_USAGE (NAME, CODE)
VALUES ('其他', 'O');
INSERT INTO PROJECT_TYPE (NAME, CODE)
VALUES ('既有建筑', 'R');
INSERT INTO PROJECT_TYPE (NAME, CODE)
VALUES ('新建项目', 'N');
INSERT INTO PROJECT_TYPE (NAME, CODE)
VALUES ('家装', 'Z');
INSERT INTO PRODUCT_TYPE (NAME, CODE)
VALUES ('开利设备', 'C');
INSERT INTO PRODUCT_TYPE (NAME, CODE)
VALUES ('净化设备', 'J');
INSERT INTO PRODUCT_TYPE (NAME, CODE)
VALUES ('东芝设备', 'T');
INSERT INTO PRODUCT_TYPE (NAME, CODE)
VALUES ('其他设备', 'Q');
INSERT INTO PRODUCT_TYPE (NAME, CODE)
VALUES ('多种设备混合', 'X');
INSERT INTO PRODUCT_TYPE (NAME, CODE)
VALUES ('应急维修', 'M');
INSERT INTO PRODUCT_TYPE (NAME, CODE)
VALUES ('年度保养', 'A');
INSERT INTO PRODUCT_TYPE (NAME, CODE)
VALUES ('技术咨询服务', 'F');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('汽车行业', 'A');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('电子行业', 'B');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('医药行业', 'C');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('食品行业', 'D');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('化工行业', 'E');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('太阳能光伏', 'F');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('农林行业', 'G');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('数据中心', 'H');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('机械加工', 'I');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('医院', 'J');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('机场高铁', 'K');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('文化体育', 'L');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('商业楼宇', 'M');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('住宅楼宇', 'N');
INSERT INTO PROJECT_INDUSTRY (NAME, CODE)
VALUES ('其它', 'O');
INSERT INTO PROJECT_SALE_TYPE (NAME, CODE)
VALUES ('设备销售', 'S');
INSERT INTO PROJECT_SALE_TYPE (NAME, CODE)
VALUES ('工程安装', 'G');
INSERT INTO PROJECT_SALE_TYPE (NAME, CODE)
VALUES ('服务', 'M');
INSERT INTO PRODUCT_DELIVERY_SIGN_METHOD (NAME, CODE)
VALUES ('按进度结算', 'P');
ALTER USER 'ecep'@'10.84.209.229' IDENTIFIED WITH mysql_native_password BY 'ecep.62335656';
UPDATE supplier_ms.CONTRACT t
SET t.STANDARD_PAY_WAY = false;
# \\\\\\\\10.84.209.8\\\\项目信息\\\\相关方信息\\\\%
select *, replace(FILE_PATH, '\\相关方信息\\', '\\B-相关方\\')
from COMPANY_FILE
where FILE_PATH like '\\\\\\\\10.84.209.8\\\\项目信息\\\\相关方信息\\\\%';
#
update COMPANY f
set f.PATH = replace(PATH, '\\相关方信息\\', '\\B-相关方\\')
where PATH like '\\\\\\\\10.84.209.8\\\\项目信息\\\\相关方信息\\\\%';
update COMPANY_FILE f
set f.FILE_PATH = replace(FILE_PATH, '\\相关方信息\\', '\\B-相关方\\')
where FILE_PATH like '\\\\\\\\10.84.209.8\\\\项目信息\\\\相关方信息\\\\%';
delete
from COMPANY_VENDOR_ENTITY
where VEN_CODE is null;
alter table CONTRACT
add TOTAL_QUANTITY decimal(10, 2) default 0.00 not null;
alter table CONTRACT
add TOTAL_AMOUNT decimal(10, 2) default 0.00 not null;
alter table CONTRACT
add TOTAL_UNTAX_AMOUNT decimal(10, 2) default 0.00 not null;
select i1_0.ID,
i1_0.CATALOG_ID,
i1_0.CODE,
i1_0.CREATE_DATE,
i1_0.DESCRIPTION,
i1_0.NAME,
i1_0.PURCHASE_PRICE,
i1_0.PURCHASE_TAX,
i1_0.SALE_PRICE,
i1_0.SALE_TAX,
i1_0.SPEC,
i1_0.UNIT,
i1_0.UPDATE_DATE
from INVENTORY i1_0
left join INVENTORY_CATALOG c1_0 on c1_0.ID = i1_0.CATALOG_ID
where i1_0.CATALOG_ID is not null and c1_0.NAME = ?
or i1_0.CODE like ? escape '' or i1_0.SPEC like ? escape '' or i1_0.NAME like ? escape ''
order by i1_0.ID desc
limit ?,?

136
docs/temp_u8.sql Normal file
View File

@@ -0,0 +1,136 @@
/**
*/
select *
from Vendor
where cVenCode = '一冷开利';
select *
from UFDATA_001_2017.dbo.Customer
where cCusCode = 'GLDKJGFYXGSBJFGS';
select *
from CM_List;
select *
from CM_Contract_Main
where strContractID = 'S24057-F1';
select *
from CM_Contract_A
where strContractID = 'S24057-F1';
select *
from CM_Contract_B
where strContractID = 'S24057-F1';
select *
from CM_Contract_C
where strContractID = 'S24057-F1';
select *
from CM_Contract
where strContractID = 'S24057-F1';
select *
from UFDATA_001_2017.dbo.CM_Contract
where GUID = '1B74DDAF-12FA-4676-A236-AFB3245ACB96'
or strContractID = 'S23111ACRM';
select *
from UFDATA_001_2017.dbo.CM_Contract_B
where GUID = '1B74DDAF-12FA-4676-A236-AFB3245ACB96'
or strContractID = 'S23111ACRM';
select *
from Person
where cPersonCode = '07';
/**
* 根据合同ID,统计合同下所有商品信息
*/
select I.GUID,
sum(isnull(I.dblQuantity, 0)) AS SumdblQuantity,
sum(isnull(I.dblUntaxSum, 0)) AS SumdblUntaxSum,
sum(isnull(I.dblSum, 0)) AS SumdblSum,
sum(isnull(I.PieceNum, 0)) as SumdblPieceNum
from CM_Contract_Item_B I
where I.intEnd = 1
and I.IntFlag <> 1 and strContractID='S24036ACNJ'
group by I.GUID;
select sum( decCount),sum(decNoRateMoney), sum(decRateMoney)
from CM_ExecInterface
where cContractID = 'S24036ACNJ';
select *
from CM_ExecInterface left Join so_somain On so_somain.id=CM_ExecInterface.cOrderID where cContractID = 'S24036ACNJ';
/**
order id 1000003696
*/
/**
付款计划
*/
select * from CM_Contract_Pay where strContractID = 'S24036ACNJ';
select * from UFDATA_001_2017.dbo.Inventory as I left join ComputationUnit as U on I.cComUnitCode=U.cComunitCode where I.cInvStd = 'KH29EZ050';
-- 计算查询的CPU使用率占比
DECLARE @init_sum_cpu_time int, @utilizedCpuCount int
SELECT @utilizedCpuCount = COUNT( * )
FROM sys.dm_os_schedulers
WHERE status = 'VISIBLE ONLINE'
SELECT @init_sum_cpu_time = SUM(cpu_time)
FROM sys.dm_exec_requests
WAITFOR DELAY '00:00:05'
SELECT CONVERT(DECIMAL(5,2),((SUM(cpu_time) - @init_sum_cpu_time) / (@utilizedCpuCount * 5000.00)) * 100) AS [CPU FROM Queries AS Percent of Total CPU Capacity]
FROM sys.dm_exec_requests;
-- 获取当前高CPU活动的查询
SELECT TOP 10 s.session_id,
r.status,
r.cpu_time,
r.logical_reads,
r.total_elapsed_time / (1000 * 60) 'Elaps M',
SUBSTRING(st.TEXT, (r.statement_start_offset / 2) + 1,
((CASE r.statement_end_offset
WHEN -1 THEN DATALENGTH(st.TEXT)
ELSE r.statement_end_offset
END - r.statement_start_offset) / 2) + 1) AS statement_text,
s.program_name,
s.last_request_end_time,
s.login_time,
r.open_transaction_count
FROM sys.dm_exec_sessions AS s
JOIN sys.dm_exec_requests AS r ON r.session_id = s.session_id
CROSS APPLY sys.Dm_exec_sql_text(r.sql_handle) AS st
WHERE r.session_id != @@SPID
ORDER BY r.cpu_time DESC;
-- CPU
SELECT TOP 10 st.text AS batch_text,
SUBSTRING(st.TEXT, (qs.statement_start_offset / 2) + 1, ((CASE qs.statement_end_offset WHEN - 1 THEN DATALENGTH(st.TEXT) ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2) + 1) AS statement_text,
(qs.total_worker_time / 1000) / qs.execution_count AS avg_cpu_time_ms,
(qs.total_elapsed_time / 1000) / qs.execution_count AS avg_elapsed_time_ms,
qs.total_logical_reads / qs.execution_count AS avg_logical_reads,
(qs.total_worker_time / 1000) AS cumulative_cpu_time_all_executions_ms,
(qs.total_elapsed_time / 1000) AS cumulative_elapsed_time_all_executions_ms
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(sql_handle) st
ORDER BY(qs.total_worker_time / qs.execution_count) DESC;
select cPOID,cInvCode, count(*) from IA_Subsidiary left join PO_Pomain on PO_Pomain.cPOID=IA_Subsidiary.cOrderCode where cPOID='0000004297' group by cPOID,cInvCode;
select GUID,strContractID,strContractName,strContractType,strParentID,strContractKind,strWay,strContractGrp, strContractDesc,strBisectionUnit,strContractOrderDate,strContractStartDate,strContractEndDate,strSetupPerson,strSetupDate,strInurePerson,strInureDate,strVaryPerson,dtVaryDate,strPersonID, dblTotalCurrency,dblExecCurrency,dblTotalQuantity,dblExecQuqantity from CM_Contract_B where GUID ='A6E6ACE0-EA2A-433B-BC07-19BB8293D7A3';
N'%运输费%' escape '' order by i1_0.ID desc limit 0,100;

BIN
icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

259
mvnw vendored Normal file
View File

@@ -0,0 +1,259 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.3.2
#
# Optional ENV vars
# -----------------
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
# MVNW_REPOURL - repo url base for downloading maven distribution
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
# ----------------------------------------------------------------------------
set -euf
[ "${MVNW_VERBOSE-}" != debug ] || set -x
# OS specific support.
native_path() { printf %s\\n "$1"; }
case "$(uname)" in
CYGWIN* | MINGW*)
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
native_path() { cygpath --path --windows "$1"; }
;;
esac
# set JAVACMD and JAVACCMD
set_java_home() {
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
if [ -n "${JAVA_HOME-}" ]; then
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACCMD="$JAVA_HOME/jre/sh/javac"
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACCMD="$JAVA_HOME/bin/javac"
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
return 1
fi
fi
else
JAVACMD="$(
'set' +e
'unset' -f command 2>/dev/null
'command' -v java
)" || :
JAVACCMD="$(
'set' +e
'unset' -f command 2>/dev/null
'command' -v javac
)" || :
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
return 1
fi
fi
}
# hash string like Java String::hashCode
hash_string() {
str="${1:-}" h=0
while [ -n "$str" ]; do
char="${str%"${str#?}"}"
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
str="${str#?}"
done
printf %x\\n $h
}
verbose() { :; }
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
die() {
printf %s\\n "$1" >&2
exit 1
}
trim() {
# MWRAPPER-139:
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
# Needed for removing poorly interpreted newline sequences when running in more
# exotic environments such as mingw bash on Windows.
printf "%s" "${1}" | tr -d '[:space:]'
}
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
while IFS="=" read -r key value; do
case "${key-}" in
distributionUrl) distributionUrl=$(trim "${value-}") ;;
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
esac
done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
case "${distributionUrl##*/}" in
maven-mvnd-*bin.*)
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
*)
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
distributionPlatform=linux-amd64
;;
esac
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
;;
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
esac
# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
distributionUrlName="${distributionUrl##*/}"
distributionUrlNameMain="${distributionUrlName%.*}"
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
exec_maven() {
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
}
if [ -d "$MAVEN_HOME" ]; then
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
exec_maven "$@"
fi
case "${distributionUrl-}" in
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
esac
# prepare tmp dir
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
trap clean HUP INT TERM EXIT
else
die "cannot create temp dir"
fi
mkdir -p -- "${MAVEN_HOME%/*}"
# Download and Install Apache Maven
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
verbose "Downloading from: $distributionUrl"
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
# select .zip or .tar.gz
if ! command -v unzip >/dev/null; then
distributionUrl="${distributionUrl%.zip}.tar.gz"
distributionUrlName="${distributionUrl##*/}"
fi
# verbose opt
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
# normalize http auth
case "${MVNW_PASSWORD:+has-password}" in
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
esac
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
verbose "Found wget ... using wget"
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
verbose "Found curl ... using curl"
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
elif set_java_home; then
verbose "Falling back to use Java to download"
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
cat >"$javaSource" <<-END
public class Downloader extends java.net.Authenticator
{
protected java.net.PasswordAuthentication getPasswordAuthentication()
{
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
}
public static void main( String[] args ) throws Exception
{
setDefault( new Downloader() );
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
}
}
END
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
verbose " - Compiling Downloader.java ..."
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
verbose " - Running Downloader.java ..."
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
fi
# If specified, validate the SHA-256 sum of the Maven distribution zip file
if [ -n "${distributionSha256Sum-}" ]; then
distributionSha256Result=false
if [ "$MVN_CMD" = mvnd.sh ]; then
echo "Checksum validation is not supported for maven-mvnd." >&2
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
exit 1
elif command -v sha256sum >/dev/null; then
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
distributionSha256Result=true
fi
elif command -v shasum >/dev/null; then
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
distributionSha256Result=true
fi
else
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
exit 1
fi
if [ $distributionSha256Result = false ]; then
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
exit 1
fi
fi
# unzip and move
if command -v unzip >/dev/null; then
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
else
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
fi
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
clean || :
exec_maven "$@"

149
mvnw.cmd vendored Normal file
View File

@@ -0,0 +1,149 @@
<# : batch portion
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Apache Maven Wrapper startup batch script, version 3.3.2
@REM
@REM Optional ENV vars
@REM MVNW_REPOURL - repo url base for downloading maven distribution
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
@REM ----------------------------------------------------------------------------
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
@SET __MVNW_CMD__=
@SET __MVNW_ERROR__=
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
@SET PSModulePath=
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
)
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
@SET __MVNW_PSMODULEP_SAVE=
@SET __MVNW_ARG0_NAME__=
@SET MVNW_USERNAME=
@SET MVNW_PASSWORD=
@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
@echo Cannot start maven from wrapper >&2 && exit /b 1
@GOTO :EOF
: end batch / begin powershell #>
$ErrorActionPreference = "Stop"
if ($env:MVNW_VERBOSE -eq "true") {
$VerbosePreference = "Continue"
}
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
if (!$distributionUrl) {
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
}
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
"maven-mvnd-*" {
$USE_MVND = $true
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
$MVN_CMD = "mvnd.cmd"
break
}
default {
$USE_MVND = $false
$MVN_CMD = $script -replace '^mvnw','mvn'
break
}
}
# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
if ($env:MVNW_REPOURL) {
$MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
}
$distributionUrlName = $distributionUrl -replace '^.*/',''
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
if ($env:MAVEN_USER_HOME) {
$MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
}
$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
exit $?
}
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
}
# prepare tmp dir
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
trap {
if ($TMP_DOWNLOAD_DIR.Exists) {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
}
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
# Download and Install Apache Maven
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
Write-Verbose "Downloading from: $distributionUrl"
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
$webclient = New-Object System.Net.WebClient
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
# If specified, validate the SHA-256 sum of the Maven distribution zip file
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
if ($distributionSha256Sum) {
if ($USE_MVND) {
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
}
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
}
}
# unzip and move
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
try {
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
} catch {
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
Write-Error "fail to move MAVEN_HOME"
}
} finally {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"

240
pom.xml Normal file
View File

@@ -0,0 +1,240 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ecep.contract</groupId>
<artifactId>Contract-Manager</artifactId>
<version>0.0.45-SNAPSHOT</version>
<name>Contract-Manager</name>
<description>Contract-Manager</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer>
<id>1</id>
<name>宋其青</name>
<email>qiqing.song@ecep.com</email>
</developer>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>21</java.version>
<javafx.version>22.0.2</javafx.version>
<poi.version>5.3.0</poi.version>
<!-- 全局编码设置 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-data-redis</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-jdbc</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.data</groupId>-->
<!-- <artifactId>spring-data-jdbc</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.hibernate.orm</groupId>-->
<!-- <artifactId>hibernate-jpamodelgen</artifactId>-->
<!-- <scope>provided</scope>-->
<!-- </dependency>-->
<!-- JavaFX -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.controlsfx</groupId>
<artifactId>controlsfx</artifactId>
<version>11.2.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.5.13</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.3</version>
</dependency>
<!-- DB Drivers -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>com.ecep.contract.manager.AppV2</mainClass>
<launcher>app</launcher>
<jlinkZipName>app-jlink</jlinkZipName>
<jlinkImageName>app-jlink-image</jlinkImageName>
<noManPages>true</noManPages>
<stripDebug>true</stripDebug>
<compress>2</compress>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.ecep.contract.manager.AppV2</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.16.2</version>
<executions>
<execution>
<inherited>true</inherited>
<id>increment-version</id>
<phase>install</phase>
<goals>
<goal>set</goal>
</goals>
<configuration>
<generateBackupPoms>false</generateBackupPoms>
<processAllModules>true</processAllModules>
<!-- <newVersion>${project.version}</newVersion> -->
<nextSnapshot>true</nextSnapshot>
<nextSnapshotIndexToIncrement>3</nextSnapshotIndexToIncrement>
<!-- <removeSnapshot>true</removeSnapshot>-->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,33 @@
package com.ecep.contract.manager;
import javafx.application.Application;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by Administrator on 2017/4/16.
*/
public class AppV2 {
private static final Logger logger = LoggerFactory.getLogger(AppV2.class);
public static void main(String[] args) {
Application.launch(Desktop.class, args);
done();
}
private static void done() {
logger.info("done");
try {
Desktop.shutdown();
} catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("AppV2.done");
}
public static final String DEFAULT_DB_HOST = "10.84.209.145"; // "db-server1.ecctrl.com"
public static final String DEFAULT_DB_PORT = "3306";
public static final String DEFAULT_DB_USERNAME = "supplier_ms";
public static final String DEFAULT_DB_PASSWORD = "[TPdseO!JKMmlrpf";
public static final String DEFAULT_DB_DATABASE = "supplier_ms";
}

View File

@@ -0,0 +1,89 @@
package com.ecep.contract.manager;
import com.ecep.contract.manager.ds.other.model.Employee;
import com.ecep.contract.manager.ds.other.model.EmployeeRole;
import com.ecep.contract.manager.ds.other.service.EmployeeService;
import com.ecep.contract.manager.ds.other.vo.EmployeeViewModel;
import javafx.application.Platform;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 当前登录用户
*/
public class CurrentEmployee extends EmployeeViewModel {
private static final Logger logger = LoggerFactory.getLogger(CurrentEmployee.class);
/**
* 语言环境
*/
private SimpleObjectProperty<Locale> locale = new SimpleObjectProperty<>(Locale.getDefault());
/**
* 角色
*/
private SimpleListProperty<EmployeeRole> roles = new SimpleListProperty<>(FXCollections.observableArrayList());
/**
* 是否系统管理员
*/
public boolean isSystemAdministrator() {
return roles.stream().anyMatch(EmployeeRole::isSystemAdministrator);
}
/**
* 语言环境属性
*/
public SimpleObjectProperty<Locale> localeProperty() {
return locale;
}
/**
* 角色属性
*/
public SimpleListProperty<EmployeeRole> rolesProperty() {
return roles;
}
/**
* 初始化
*/
public CompletableFuture<Void> initialize() {
CompletableFuture<Void> future = new CompletableFuture<>();
ScheduledExecutorService executorService = Desktop.instance.getExecutorService();
/**
* 异步初始化当前用户
* 1. 从数据库中查询当前用户
* 2. 从数据库中查询当前用户的角色
* 3. 更新当前用户的信息
* 4. 更新当前用户的角色
*/
executorService.submit(() -> {
// issue #1 sss 2020-07-05
EmployeeService employeeService = SpringApp.getBean(EmployeeService.class);
Employee employee = employeeService.findById(Desktop.instance.getActiveEmployeeId());
List<EmployeeRole> roles = employeeService.getRolesByEmployeeId(employee.getId());
Platform.runLater(() -> {
update(employee);
rolesProperty().setAll(roles);
future.complete(null);
});
});
/**
* 定时更新用户活动状态
*/
executorService.scheduleWithFixedDelay(() -> {
try {
SpringApp.getBean(EmployeeService.class).updateActive(Desktop.instance.getSessionId());
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error("updateActive:{}", e.getMessage(), e);
}
}
}, 10, 10, TimeUnit.SECONDS);
return future;
}
}

View File

@@ -0,0 +1,325 @@
package com.ecep.contract.manager;
import com.ecep.contract.manager.ds.other.controller.LoginWidowController;
import com.ecep.contract.manager.ui.BaseController;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.task.TaskMonitorCenter;
import com.ecep.contract.manager.util.UITools;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.*;
import java.util.function.Consumer;
import java.util.logging.Level;
/**
* JavaFx 应用程序
*
* @author ecep
* Created by ecep on 2017/05/08.
*/
public class Desktop extends Application {
private static final Logger logger = LoggerFactory.getLogger(Desktop.class);
public static Desktop instance;
/**
* 在默认浏览器中打开指定的URL。
* <p>
* 该函数使用JavaFX的HostServices类来调用系统默认的浏览器并打开传入的URL。
*
* @param url 要在浏览器中打开的URL字符串。该参数不能为空且应为有效的URL格式。
*/
public static void showInBrowse(String url) {
instance.getHostServices().showDocument(url);
}
/**
* 在系统的文件资源管理器中打开指定的文件夹。
* <p>
* 该方法首先尝试使用 java.awt.Desktop API 打开文件夹。如果该 API 不支持,
* 则在 Windows 系统中使用 explorer.exe 打开文件夹。
*
* @param dir 要打开的文件夹对象。如果为 null 或无效路径,可能会抛出异常。
* @throws RuntimeException 如果使用 java.awt.Desktop 打开文件夹时发生 IOException
* 则将其包装为 RuntimeException 抛出。
*/
public static void showInExplorer(File dir) {
if (java.awt.Desktop.isDesktopSupported()) {
try {
java.awt.Desktop.getDesktop().open(dir);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
try {
// 在Windows中使用explorer.exe打开文件夹路径用双引号括起来
Process process = Runtime.getRuntime().exec(
new String[] { "explorer.exe", "\"" + dir.getAbsolutePath() + "\"" }, null, new File("."));
// process.waitFor();
} catch (IOException e) {
if (logger.isDebugEnabled()) {
logger.debug("Unable open {}", dir.getAbsolutePath(), e);
}
}
}
}
public static void checkAndShowInExplorer(String path, Consumer<String> consumer) {
if (!StringUtils.hasText(path)) {
consumer.accept("文件/目录为空,无法打开");
return;
}
File file = new File(path);
if (!file.exists()) {
if (file.isFile()) {
consumer.accept("文件 " + file.getAbsolutePath() + " 不存在,请确认");
} else {
consumer.accept("目录 " + file.getAbsolutePath() + " 不存在,请确认");
}
return;
}
try {
Desktop.showInExplorer(file);
consumer.accept("打开文件/目录 " + path);
} catch (Exception e) {
consumer.accept("打开文件错误:" + e.getMessage());
}
}
public static void shutdown() {
if (logger.isDebugEnabled()) {
logger.debug("shutdown");
}
if (instance != null) {
try {
instance.stop();
} catch (Throwable e) {
logger.error("shutdown error", e);
}
}
}
private ScheduledExecutorService scheduledExecutorService = null;
private final TaskMonitorCenter taskMonitorCenter = new TaskMonitorCenter();
private final SimpleIntegerProperty sessionId = new SimpleIntegerProperty(0);
@Getter
private final CurrentEmployee activeEmployee = new CurrentEmployee();
public void setActiveEmployeeId(int activeEmployeeId) {
activeEmployee.getId().set(activeEmployeeId);
}
public int getActiveEmployeeId() {
return activeEmployee.getId().get();
}
public int getSessionId() {
return sessionId.get();
}
public void setSessionId(int sessionId) {
this.sessionId.set(sessionId);
}
public ScheduledExecutorService getExecutorService() {
if (scheduledExecutorService == null) {
scheduledExecutorService = Executors.newScheduledThreadPool(3);
}
return scheduledExecutorService;
}
public TaskMonitorCenter getTaskMonitorCenter() {
return taskMonitorCenter;
}
@Override
public void start(Stage primaryStage) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("start");
}
if (instance != null) {
logger.error("Desktop already started");
}
instance = this;
URL resource = getClass().getResource("/ui/start_lamp.fxml");
FXMLLoader loader = new FXMLLoader(resource);
primaryStage.setTitle("CMS");
primaryStage.initStyle(StageStyle.TRANSPARENT);
Parent root = loader.load();
Scene scene = new Scene(root);
scene.getStylesheets().add("/ui/start_lamp.css");
primaryStage.setScene(scene);
primaryStage.setOnShown(e -> {
System.out.println("primaryStage#OnShown");
});
primaryStage.show();
System.out.println("Desktop.start -> primaryStage.show()");
try {
startSpringApp(primaryStage, root, loader);
} catch (Exception e) {
UITools.showExceptionAndWait("启动失败", e);
}
}
private void startSpringApp(Stage primaryStage, Parent root, FXMLLoader loader) {
System.out.println("Desktop.startSpringApp");
// 更新窗口标题
Node titleNode = root.lookup("#title");
if (titleNode != null) {
primaryStage.setTitle(((Text) titleNode).getText());
}
Node lookup = root.lookup("#logBox");
if (!(lookup instanceof VBox logBox)) {
throw new RuntimeException("启动界面加载失败, #logger 类型错误");
}
ScrollPane logPane = (ScrollPane) root.lookup("#logPane");
logBox.getChildren().clear();
MessageHolder holder = (level, message) -> {
Text text = new Text(message);
if (Level.WARNING == level) { // warning
text.setFill(Color.YELLOW);
} else if (Level.SEVERE == level) {// error
text.setFill(Color.RED);
} else if (Level.FINE == level) { // debug
text.setFill(Color.GRAY);
} else {
text.setFill(Color.WHITE);
}
Platform.runLater(() -> {
logBox.getChildren().add(text);
logPane.layout();
logPane.setVvalue(1.0);
});
};
holder.info("启动中,请稍后...");
CompletableFuture.runAsync(() -> {
try {
//
holder.info("读取配置文件...");
Properties properties = new Properties();
File configFile = new File("config.properties");
if (configFile.exists()) {
holder.debug("读取配置文件 " + configFile.getName() + "...");
try (FileInputStream input = new FileInputStream(configFile)) {
properties.load(input);
holder.info("配置文件读取成功.");
} catch (IOException e) {
holder.error("读取失败:" + e.getMessage());
logger.error(e.getMessage(), e);
return;
}
}
CompletableFuture.runAsync(() -> {
SpringApp.launch(properties, holder);
ConfigurableListableBeanFactory beanFactory = SpringApp.context.getBeanFactory();
beanFactory.registerSingleton("scheduledExecutorService", getExecutorService());
beanFactory.registerSingleton("taskMonitorCenter", taskMonitorCenter);
});
try {
LoginWidowController controller = new LoginWidowController();
controller.setHolder(holder);
controller.setPrimaryStage(primaryStage);
controller.setProperties(properties);
while (true) {
controller.tryLogin();
break;
}
if (logger.isDebugEnabled()) {
logger.debug("login in");
}
} catch (Exception e) {
holder.error("登录失败:" + e.getMessage());
logger.error(e.getMessage(), e);
}
} catch (Exception e) {
holder.error(e.getMessage());
logger.error(e.getMessage(), e);
}
});
System.out.println("Desktop.startSpringApp.");
}
@Override
public void stop() throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("stop");
}
CompletableFuture<Void> future = BaseController.shutdown();
future.orTimeout(5, TimeUnit.SECONDS);
future.exceptionally(e -> {
logger.error(e.getMessage(), e);
return null;
});
future.thenRun(() -> {
SpringApp.shutdown();
try {
shutdownExecutorService();
super.stop();
if (logger.isDebugEnabled()) {
logger.debug("stopped");
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
});
}
private void shutdownExecutorService() {
List<Runnable> runnableList = scheduledExecutorService.shutdownNow();
for (Runnable runnable : runnableList) {
if (logger.isDebugEnabled()) {
logger.debug("shutdown runnable = {}", runnable);
}
if (runnable instanceof FutureTask<?> future) {
if (logger.isDebugEnabled()) {
logger.debug("runnable as future, isCancelled() = {}, isDone() = {}", future.isCancelled(),
future.isDone());
}
if (future.cancel(true)) {
if (logger.isDebugEnabled()) {
logger.debug("runnable as future canceled");
}
}
}
}
scheduledExecutorService.close();
}
}

View File

@@ -0,0 +1,205 @@
package com.ecep.contract.manager;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.*;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
public class MyPersistentCookieStore implements CookieStore {
private final File file;
private final ObjectMapper objectMapper;
private Map<URI, List<HttpCookie>> cookiesMap = new HashMap<>();
public MyPersistentCookieStore(File file, ObjectMapper objectMapper) {
this.file = file;
this.objectMapper = objectMapper;
if (file != null && file.exists()) {
loadFromFile2();
}
}
private void loadFromFile2() {
try {
ObjectNode root = (ObjectNode) objectMapper.readTree(file);
for (Iterator<Map.Entry<String, JsonNode>> it = root.fields(); it.hasNext(); ) {
Map.Entry<String, JsonNode> entry = it.next();
String key = entry.getKey();
ArrayNode value = (ArrayNode) entry.getValue();
List<HttpCookie> cookies = new ArrayList<>();
for (JsonNode node1 : value) {
HttpCookie cookie = new HttpCookie(node1.get("name").asText(), node1.get("value").asText());
objectMapper.updateValue(node1, cookie);
cookies.add(cookie);
}
URI uri = URI.create(key);
System.out.println(key + " -> " + uri);
cookiesMap.put(uri, cookies);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void saveToFile2() {
try {
objectMapper.writeValue(file, cookiesMap);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void loadFromFile(File file) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
// 假设格式为: name=value;domain=domain;path=path;expires=expires;
String[] parts = line.split(";");
String nameValue = parts[0];
String[] nameValueParts = nameValue.split("=");
String name = nameValueParts[0];
String value = nameValueParts.length > 1 ? nameValueParts[1] : "";
HttpCookie cookie = new HttpCookie(name, value);
for (int i = 1; i < parts.length; i++) {
String[] attribute = parts[i].split("=");
if (attribute[0].equals("domain")) {
cookie.setDomain(attribute[1]);
} else if (attribute[0].equals("path")) {
cookie.setPath(attribute[1]);
} else if (attribute[0].equals("expires")) {
// 解析日期格式并设置过期时间
// 这里只是示例,实际需要正确解析日期格式
Date expiresDate = new Date(Long.parseLong(attribute[1]));
cookie.setMaxAge(expiresDate.getTime() - System.currentTimeMillis());
}
}
URI uri = URI.create(cookie.getDomain());
List<HttpCookie> cookies = cookiesMap.getOrDefault(uri, new ArrayList<>());
cookies.add(cookie);
cookiesMap.put(uri, cookies);
}
} catch (IOException e) {
// 处理文件读取错误
e.printStackTrace();
}
}
public void saveToFile() {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
for (Map.Entry<URI, List<HttpCookie>> entry : cookiesMap.entrySet()) {
for (HttpCookie cookie : entry.getValue()) {
String line = cookie.getName() + "=" + cookie.getValue() + ";domain=" + cookie.getDomain() + ";path=" + cookie.getPath();
if (cookie.getMaxAge() > 0) {
line += ";expires=" + (System.currentTimeMillis() + cookie.getMaxAge());
}
writer.write(line);
writer.newLine();
}
}
} catch (IOException e) {
// 处理文件写入错误
e.printStackTrace();
}
}
@Override
public void add(URI uri, HttpCookie cookie) {
if (cookie == null) {
throw new NullPointerException("cookie is null");
}
if (cookie.getDomain() != null) {
URI key = getEffectiveURI(cookie);
List<HttpCookie> cookies = cookiesMap.getOrDefault(key, new ArrayList<>());
cookies.remove(cookie);
cookies.add(cookie);
cookiesMap.put(key, cookies);
}
if (uri != null) {
URI key = getEffectiveURI(uri);
List<HttpCookie> cookies = cookiesMap.getOrDefault(key, new ArrayList<>());
cookies.remove(cookie);
cookies.add(cookie);
cookiesMap.put(key, cookies);
}
saveToFile2();
}
@Override
public List<HttpCookie> get(URI uri) {
URI effectiveURI = getEffectiveURI(uri);
System.out.println("effectiveURI = " + effectiveURI);
return cookiesMap.getOrDefault(effectiveURI, new ArrayList<>());
}
@Override
public List<HttpCookie> getCookies() {
return cookiesMap.values().stream().flatMap(List::stream).toList();
}
@Override
public List<URI> getURIs() {
return cookiesMap.keySet().stream().toList();
}
@Override
public boolean remove(URI uri, HttpCookie cookie) {
URI key = getEffectiveURI(uri);
List<HttpCookie> httpCookies = cookiesMap.get(key);
if (httpCookies == null) {
return false;
}
return httpCookies.remove(cookie);
}
@Override
public boolean removeAll() {
cookiesMap.clear();
return true;
}
private URI getEffectiveURI(URI uri) {
URI effectiveURI = null;
try {
effectiveURI = new URI("http",
uri.getHost(),
null, // path component
null, // query component
null // fragment component
);
} catch (URISyntaxException ignored) {
ignored.printStackTrace();
effectiveURI = uri;
}
return effectiveURI;
}
private URI getEffectiveURI(HttpCookie cookie) {
URI effectiveURI = null;
try {
effectiveURI = new URI("http",
cookie.getDomain(),
null, // path component
null, // query component
null // fragment component
);
} catch (URISyntaxException ignored) {
}
return effectiveURI;
}
}

View File

@@ -0,0 +1,436 @@
package com.ecep.contract.manager;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.*;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
public class MyPersistentCookieStore2 implements CookieStore {
private final File file;
private final ObjectMapper objectMapper;
private List<HttpCookie> cookieJar = null;
// the cookies are indexed by its domain and associated uri (if present)
// CAUTION: when a cookie removed from main data structure (i.e. cookieJar),
// it won't be cleared in domainIndex & uriIndex. Double-check the
// presence of cookie when retrieve one form index store.
private Map<String, List<HttpCookie>> domainIndex = null;
private Map<URI, List<HttpCookie>> uriIndex = null;
// use ReentrantLock instead of synchronized for scalability
private ReentrantLock lock = null;
public MyPersistentCookieStore2(File file, ObjectMapper objectMapper) {
this.file = file;
this.objectMapper = objectMapper;
cookieJar = new ArrayList<>();
domainIndex = new HashMap<>();
uriIndex = new HashMap<>();
lock = new ReentrantLock(false);
if (file != null && file.exists()) {
loadFromFile2();
}
}
private void loadFromFile2() {
try {
ObjectNode root = (ObjectNode) objectMapper.readTree(file);
ArrayNode cookieJarNode = (ArrayNode) root.get("cookieJar");
for (JsonNode node1 : cookieJarNode) {
HttpCookie cookie = new HttpCookie(node1.get("name").asText(), node1.get("value").asText());
objectMapper.updateValue(node1, cookie);
cookieJar.add(cookie);
}
ObjectNode domainIndexNode = (ObjectNode) root.get("domainIndex");
for (Iterator<Map.Entry<String, JsonNode>> it = domainIndexNode.fields(); it.hasNext(); ) {
Map.Entry<String, JsonNode> entry = it.next();
String key = entry.getKey();
ArrayNode value = (ArrayNode) entry.getValue();
List<HttpCookie> cookies = new ArrayList<>();
for (JsonNode node1 : value) {
HttpCookie cookie = new HttpCookie(node1.get("name").asText(), node1.get("value").asText());
objectMapper.updateValue(node1, cookie);
cookies.add(cookie);
}
domainIndex.put(key, cookies);
}
ObjectNode uriIndexNode = (ObjectNode) root.get("uriIndex");
for (Iterator<Map.Entry<String, JsonNode>> it = uriIndexNode.fields(); it.hasNext(); ) {
Map.Entry<String, JsonNode> entry = it.next();
String key = entry.getKey();
ArrayNode value = (ArrayNode) entry.getValue();
List<HttpCookie> cookies = new ArrayList<>();
for (JsonNode node1 : value) {
HttpCookie cookie = new HttpCookie(node1.get("name").asText(), node1.get("value").asText());
objectMapper.updateValue(node1, cookie);
cookies.add(cookie);
}
URI uri = URI.create(key);
System.out.println(key + " -> " + uri);
uriIndex.put(uri, cookies);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void saveToFile2() {
try {
HashMap<String, Object> map = new HashMap<>();
map.put("cookieJar", cookieJar);
map.put("domainIndex", domainIndex);
map.put("uriIndex", uriIndex);
objectMapper.writeValue(file, map);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Add one cookie into cookie store.
*/
public void add(URI uri, HttpCookie cookie) {
// pre-condition : argument can't be null
if (cookie == null) {
throw new NullPointerException("cookie is null");
}
lock.lock();
try {
// remove the ole cookie if there has had one
cookieJar.remove(cookie);
// add new cookie if it has a non-zero max-age
if (cookie.getMaxAge() != 0) {
cookieJar.add(cookie);
// and add it to domain index
if (cookie.getDomain() != null) {
addIndex(domainIndex, cookie.getDomain(), cookie);
}
if (uri != null) {
// add it to uri index, too
addIndex(uriIndex, getEffectiveURI(uri), cookie);
}
}
} finally {
lock.unlock();
}
saveToFile2();
}
/**
* Get all cookies, which:
* 1) given uri domain-matches with, or, associated with
* given uri when added to the cookie store.
* 3) not expired.
* See RFC 2965 sec. 3.3.4 for more detail.
*/
public List<HttpCookie> get(URI uri) {
// argument can't be null
if (uri == null) {
throw new NullPointerException("uri is null");
}
List<HttpCookie> cookies = new ArrayList<>();
boolean secureLink = "https".equalsIgnoreCase(uri.getScheme());
lock.lock();
try {
// check domainIndex first
getInternal1(cookies, domainIndex, uri.getHost(), secureLink);
// check uriIndex then
getInternal2(cookies, uriIndex, getEffectiveURI(uri), secureLink);
} finally {
lock.unlock();
}
return cookies;
}
/**
* Get all cookies in cookie store, except those have expired
*/
public List<HttpCookie> getCookies() {
List<HttpCookie> rt;
lock.lock();
try {
Iterator<HttpCookie> it = cookieJar.iterator();
while (it.hasNext()) {
if (it.next().hasExpired()) {
it.remove();
}
}
} finally {
rt = Collections.unmodifiableList(cookieJar);
lock.unlock();
}
return rt;
}
/**
* Get all URIs, which are associated with at least one cookie
* of this cookie store.
*/
public List<URI> getURIs() {
List<URI> uris = new ArrayList<>();
lock.lock();
try {
Iterator<URI> it = uriIndex.keySet().iterator();
while (it.hasNext()) {
URI uri = it.next();
List<HttpCookie> cookies = uriIndex.get(uri);
if (cookies == null || cookies.size() == 0) {
// no cookies list or an empty list associated with
// this uri entry, delete it
it.remove();
}
}
} finally {
uris.addAll(uriIndex.keySet());
lock.unlock();
}
return uris;
}
/**
* Remove a cookie from store
*/
public boolean remove(URI uri, HttpCookie ck) {
// argument can't be null
if (ck == null) {
throw new NullPointerException("cookie is null");
}
boolean modified = false;
lock.lock();
try {
modified = cookieJar.remove(ck);
} finally {
lock.unlock();
}
return modified;
}
/**
* Remove all cookies in this cookie store.
*/
public boolean removeAll() {
lock.lock();
try {
if (cookieJar.isEmpty()) {
return false;
}
cookieJar.clear();
domainIndex.clear();
uriIndex.clear();
} finally {
lock.unlock();
}
return true;
}
/* ---------------- Private operations -------------- */
/*
* This is almost the same as HttpCookie.domainMatches except for
* one difference: It won't reject cookies when the 'H' part of the
* domain contains a dot ('.').
* I.E.: RFC 2965 section 3.3.2 says that if host is x.y.domain.com
* and the cookie domain is .domain.com, then it should be rejected.
* However that's not how the real world works. Browsers don't reject and
* some sites, like yahoo.com do actually expect these cookies to be
* passed along.
* And should be used for 'old' style cookies (aka Netscape type of cookies)
*/
private boolean netscapeDomainMatches(String domain, String host) {
if (domain == null || host == null) {
return false;
}
// if there's no embedded dot in domain and domain is not .local
boolean isLocalDomain = ".local".equalsIgnoreCase(domain);
int embeddedDotInDomain = domain.indexOf('.');
if (embeddedDotInDomain == 0) {
embeddedDotInDomain = domain.indexOf('.', 1);
}
if (!isLocalDomain && (embeddedDotInDomain == -1 || embeddedDotInDomain == domain.length() - 1)) {
return false;
}
// if the host name contains no dot and the domain name is .local
int firstDotInHost = host.indexOf('.');
if (firstDotInHost == -1 && isLocalDomain) {
return true;
}
int domainLength = domain.length();
int lengthDiff = host.length() - domainLength;
if (lengthDiff == 0) {
// if the host name and the domain name are just string-compare equal
return host.equalsIgnoreCase(domain);
} else if (lengthDiff > 0) {
// need to check H & D component
String H = host.substring(0, lengthDiff);
String D = host.substring(lengthDiff);
return (D.equalsIgnoreCase(domain));
} else if (lengthDiff == -1) {
// if domain is actually .host
return (domain.charAt(0) == '.' &&
host.equalsIgnoreCase(domain.substring(1)));
}
return false;
}
private void getInternal1(List<HttpCookie> cookies, Map<String, List<HttpCookie>> cookieIndex,
String host, boolean secureLink) {
// Use a separate list to handle cookies that need to be removed so
// that there is no conflict with iterators.
ArrayList<HttpCookie> toRemove = new ArrayList<>();
for (Map.Entry<String, List<HttpCookie>> entry : cookieIndex.entrySet()) {
String domain = entry.getKey();
List<HttpCookie> lst = entry.getValue();
for (HttpCookie c : lst) {
if ((c.getVersion() == 0 && netscapeDomainMatches(domain, host)) ||
(c.getVersion() == 1 && HttpCookie.domainMatches(domain, host))) {
if ((cookieJar.indexOf(c) != -1)) {
// the cookie still in main cookie store
if (!c.hasExpired()) {
// don't add twice and make sure it's the proper
// security level
if ((secureLink || !c.getSecure()) &&
!cookies.contains(c)) {
cookies.add(c);
}
} else {
toRemove.add(c);
}
} else {
// the cookie has been removed from main store,
// so also remove it from domain indexed store
toRemove.add(c);
}
}
}
// Clear up the cookies that need to be removed
for (HttpCookie c : toRemove) {
lst.remove(c);
cookieJar.remove(c);
}
toRemove.clear();
}
}
// @param cookies [OUT] contains the found cookies
// @param cookieIndex the index
// @param comparator the prediction to decide whether or not
// a cookie in index should be returned
private <T> void getInternal2(List<HttpCookie> cookies,
Map<T, List<HttpCookie>> cookieIndex,
Comparable<T> comparator, boolean secureLink) {
for (T index : cookieIndex.keySet()) {
if (comparator.compareTo(index) == 0) {
List<HttpCookie> indexedCookies = cookieIndex.get(index);
// check the list of cookies associated with this domain
if (indexedCookies != null) {
Iterator<HttpCookie> it = indexedCookies.iterator();
while (it.hasNext()) {
HttpCookie ck = it.next();
if (cookieJar.indexOf(ck) != -1) {
// the cookie still in main cookie store
if (!ck.hasExpired()) {
// don't add twice
if ((secureLink || !ck.getSecure()) &&
!cookies.contains(ck))
cookies.add(ck);
} else {
it.remove();
cookieJar.remove(ck);
}
} else {
// the cookie has been removed from main store,
// so also remove it from domain indexed store
it.remove();
}
}
} // end of indexedCookies != null
} // end of comparator.compareTo(index) == 0
} // end of cookieIndex iteration
}
// add 'cookie' indexed by 'index' into 'indexStore'
private <T> void addIndex(Map<T, List<HttpCookie>> indexStore,
T index,
HttpCookie cookie) {
if (index != null) {
List<HttpCookie> cookies = indexStore.get(index);
if (cookies != null) {
// there may already have the same cookie, so remove it first
cookies.remove(cookie);
cookies.add(cookie);
} else {
cookies = new ArrayList<>();
cookies.add(cookie);
indexStore.put(index, cookies);
}
}
}
//
// for cookie purpose, the effective uri should only be http://host
// the path will be taken into account when path-match algorithm applied
//
private URI getEffectiveURI(URI uri) {
URI effectiveURI = null;
try {
effectiveURI = new URI("http",
uri.getHost(),
null, // path component
null, // query component
null // fragment component
);
} catch (URISyntaxException ignored) {
effectiveURI = uri;
}
return effectiveURI;
}
}

View File

@@ -0,0 +1,35 @@
package com.ecep.contract.manager;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
@Component
@ConfigurationProperties(prefix = "my")
public class MyProperties {
@Getter
@Setter
private String downloadsPath;
/**
* 尝试返回当前用户的下载文件夹
*/
public File getDownloadDirectory() {
String downloadsPath = getDownloadsPath();
if (StringUtils.hasText(downloadsPath)) {
return new File(downloadsPath);
}
// 没有配置下载目录时,尝试使用默认设置
String home = System.getProperty("user.home");
Path path = Paths.get(home, "Downloads");
return path.toFile();
}
}

View File

@@ -0,0 +1,259 @@
package com.ecep.contract.manager;
import com.ecep.contract.manager.cloud.CloudRepositoriesConfig;
import com.ecep.contract.manager.ds.DsRepositoriesConfig;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.util.MyDateTimeUtils;
import com.ecep.contract.manager.util.UITools;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationHook;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
import org.springframework.boot.context.metrics.buffering.StartupTimeline;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.metrics.StartupStep;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService;
@SpringBootApplication
@EnableScheduling
@EnableAsync
@EnableCaching
public class SpringApp {
private static final Logger logger = LoggerFactory.getLogger(SpringApp.class);
static SpringApplication application;
static ConfigurableApplicationContext context;
public static <T> T getBean(Class<T> requiredType) throws BeansException {
return context.getBean(requiredType);
}
public static void launch(Properties properties, MessageHolder holder) {
application = new SpringApplication(SpringApp.class);
BufferingApplicationStartup startup = new BufferingApplicationStartup(2000);
application.setApplicationStartup(startup);
//
holder.debug("应用程序环境准备中...");
SpringApplication.withHook(new Hook(holder), () -> {
// 动态地注册或修改这些组件和配置
application.addBootstrapRegistryInitializer(registry -> {
//
System.out.println("registry = " + registry);
});
application.addListeners(event -> {
logger.debug("SpringApp.launch ApplicationListener, event:{}", event);
});
application.addInitializers(app -> {
logger.debug("SpringApp.launch ApplicationContextInitializer");
ConfigurableEnvironment environment = app.getEnvironment();
logger.debug("environment = {}", environment);
PropertySource<?> dynamicProperties = environment.getPropertySources().get("dynamicProperties");
if (dynamicProperties != null) {
logger.debug("dynamicProperties = {}", dynamicProperties);
}
environment.getPropertySources().addLast(new PropertiesPropertySource("dynamicProperties", properties));
// app.getBeanFactory().registerSingleton("dataSource", dataSource());
logger.debug("app = {}", app);
if (app instanceof AnnotationConfigApplicationContext ctx) {
ctx.register(DsRepositoriesConfig.class);
ctx.register(CloudRepositoriesConfig.class);
}
});
startup.start("");
context = application.run();
logger.debug("SpringApp.launch application.run().");
Duration between = Duration.between(startup.getBufferedTimeline().getStartTime(), Instant.now());
holder.info("应用程序环境加载完成... " + between);
});
CompletableFuture.runAsync(() -> {
// 在这里调用 startup 性能分析
analyzeStartupPerformance(startup);
});
}
/**
* 分析启动性能数据并输出到日志
*/
private static void analyzeStartupPerformance(BufferingApplicationStartup startup) {
// 获取所有记录的事件
StartupTimeline timeline = startup.getBufferedTimeline();
if (timeline == null || timeline.getEvents().isEmpty()) {
logger.warn("StartupTimeline 为空或没有事件!");
return;
}
logger.info("总共有 {} 个事件", timeline.getEvents().size());
// 找出与 Bean 初始化相关的步骤
timeline.getEvents().stream()
.filter(event -> event.getStartupStep().getName().startsWith("spring.beans."))
.sorted((a, b) -> Long.compare(b.getDuration().toMillis(), a.getDuration().toMillis()))
.limit(30)
.forEach(event -> {
String name = event.getStartupStep().getName();
long duration = event.getDuration().toMillis();
logger.info("Bean 初始化阶段: {} - 耗时: {} ms", name, duration);
for (StartupStep.Tag tag : event.getStartupStep().getTags()) {
if ("beanName".equals(tag.getKey())) {
logger.info(" └── Bean 名称: {}", tag.getValue());
}
}
});
}
public static String getMessage(String code, Object[] args, Locale locale) {
return context.getMessage(code, args, locale);
}
public static void shutdown() {
System.out.println("SpringApp.shutdown");
if (logger.isDebugEnabled()) {
logger.debug("shutdown");
}
if (context != null) {
if (context.isRunning()) {
context.close();
}
}
}
public static boolean isRunning() {
return context != null && context.isRunning();
}
static class Hook implements SpringApplicationHook, SpringApplicationRunListener {
MessageHolder holder;
Hook(MessageHolder holder) {
this.holder = holder;
}
public void debug(String msg) {
holder.debug(msg);
}
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
logger.debug("Desktop.starting");
debug("Spring Application 启动中...");
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
logger.debug("Desktop.environmentPrepared");
debug("初始化 Environment 中,请稍后...");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
logger.debug("Desktop.contextPrepared");
debug("Spring Application Context 预处理中,请稍后...");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
logger.debug("Desktop.contextLoaded");
debug("Spring Application Context 初始化完毕,请稍后...");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
logger.debug("Desktop.started");
debug("Spring Application 启动完毕.");
}
@Override
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
logger.debug("Desktop.ready");
debug("Spring Application ready.");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
logger.error("Desktop.failed", exception);
holder.error("Spring Application 启动失败(" + exception.getMessage() + ").");
UITools.showExceptionAndWait("启动失败", exception);
}
@Override
public SpringApplicationRunListener getRunListener(SpringApplication springApplication) {
return this;
}
}
@EventListener
public void handleClosedEvent(ContextClosedEvent event) {
if (logger.isDebugEnabled()) {
logger.debug("handleClosedEvent={}", event);
}
Desktop.shutdown();
}
@Bean
public CacheManager cacheManager() {
// return new ConcurrentMapCacheManager("myCache");
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setAsyncCacheMode(true);
return cacheManager;
}
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN)));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN)));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME));
objectMapper.registerModule(javaTimeModule);
return objectMapper;
}
@Bean
public ScheduledExecutorService scheduledExecutorService() {
return Executors.newScheduledThreadPool(3);
}
}

View File

@@ -0,0 +1,173 @@
package com.ecep.contract.manager.cloud;
import com.ecep.contract.manager.ds.other.service.SysConfService;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.util.MyStringUtils;
import com.ecep.contract.manager.util.NumberUtils;
import lombok.Getter;
import lombok.Setter;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;
import java.util.Locale;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static com.ecep.contract.manager.SpringApp.getBean;
public class AbstractCtx {
@Setter
SysConfService confService;
@Setter
@Getter
Locale locale = Locale.getDefault();
public SysConfService getConfService() {
if (confService == null) {
confService = getBean(SysConfService.class);
}
return confService;
}
public boolean updateText(Supplier<String> getter, Consumer<String> setter, String text, MessageHolder holder, String topic) {
if (!Objects.equals(getter.get(), text)) {
setter.accept(text);
holder.info(topic + "修改为: " + text);
return true;
}
return false;
}
public boolean updateAppendText(Supplier<String> getter, Consumer<String> setter, String text, MessageHolder holder, String topic) {
if (StringUtils.hasText(text)) {
String str = MyStringUtils.appendIfAbsent(getter.get(), text);
if (!Objects.equals(getter.get(), str)) {
setter.accept(text);
holder.info(topic + "修改为: " + text);
return true;
}
}
return false;
}
public boolean updateLocalDate(Supplier<LocalDate> getter, Consumer<LocalDate> setter, java.sql.Date date, MessageHolder holder, String topic) {
if (date != null) {
return updateLocalDate(getter, setter, date.toLocalDate(), holder, topic);
}
return false;
}
public boolean updateLocalDate(Supplier<LocalDate> getter, Consumer<LocalDate> setter, LocalDate date, MessageHolder holder, String topic) {
return updateLocalDate(getter, setter, date, holder, topic, false);
}
public boolean updateLocalDate(Supplier<LocalDate> getter, Consumer<LocalDate> setter, LocalDate date, MessageHolder holder, String topic, boolean allowNull) {
if (date == null && !allowNull) {
return false;
}
if (!Objects.equals(getter.get(), date)) {
setter.accept(date);
holder.info(topic + "更新为 " + date);
return true;
}
return false;
}
public boolean updateLocalDate(Supplier<LocalDate> getter, Consumer<LocalDate> setter, String strDate, MessageHolder holder, String topic) {
LocalDate date = null;
if (StringUtils.hasText(strDate)) {
try {
date = LocalDate.parse(strDate);
} catch (DateTimeParseException e) {
holder.warn("无法解析的日期:" + strDate);
}
}
return updateLocalDate(getter, setter, date, holder, topic);
}
public boolean updateLocalDate(Supplier<LocalDate> getter, Consumer<LocalDate> setter, Timestamp timestamp, MessageHolder holder, String topic) {
LocalDate date = null;
if (timestamp != null) {
try {
date = timestamp.toLocalDateTime().toLocalDate();
} catch (DateTimeParseException e) {
holder.warn("解析日期" + timestamp + " 异常:" + e.getMessage());
}
}
return updateLocalDate(getter, setter, date, holder, topic);
}
public boolean updateLocalDateTime(Supplier<LocalDateTime> getter, Consumer<LocalDateTime> setter, Timestamp timestamp, MessageHolder holder, String topic) {
LocalDateTime dateTime = null;
if (timestamp != null) {
try {
// fixed nanos
timestamp.setNanos(0);
dateTime = timestamp.toLocalDateTime();
} catch (DateTimeParseException e) {
holder.warn("解析日期" + timestamp + " 异常:" + e.getMessage());
}
}
if (!Objects.equals(getter.get(), dateTime)) {
setter.accept(dateTime);
holder.info(topic + "修改为: " + dateTime);
return true;
}
return false;
}
public boolean updateInstant(Supplier<Instant> getter, Consumer<Instant> setter, Instant instant, MessageHolder holder, String topic) {
if (!Objects.equals(getter.get(), instant)) {
setter.accept(instant);
holder.info(topic + "修改为: " + instant);
return true;
}
return false;
}
public boolean updateNumber(Supplier<Double> getter, Consumer<Double> setter, BigDecimal value, MessageHolder holder, String topic) {
double val = value.doubleValue();
return updateNumber(getter, setter, val, holder, topic);
}
public boolean updateNumber(Supplier<Double> getter, Consumer<Double> setter, double value, MessageHolder holder, String topic) {
if (getter.get() == null || !NumberUtils.equals(getter.get(), value)) {
setter.accept(value);
holder.info(topic + "修改为: " + value);
return true;
}
return false;
}
public boolean updateNumber(Supplier<Float> getter, Consumer<Float> setter, float value, MessageHolder holder, String topic) {
if (getter.get() == null || !NumberUtils.equals(getter.get(), value)) {
setter.accept(value);
holder.info(topic + "修改为: " + value);
return true;
}
return false;
}
public boolean updateNumber(Supplier<Integer> getter, Consumer<Integer> setter, Integer value, MessageHolder holder, String topic) {
if (getter.get() == null || !NumberUtils.equals(getter.get(), value)) {
setter.accept(value);
holder.info(topic + "修改为: " + value);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,73 @@
package com.ecep.contract.manager.cloud;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.other.model.IdentityEntity;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.proxy.HibernateProxy;
import java.time.Instant;
import java.util.Objects;
/**
* 记录同步来源
*/
@Getter
@Setter
// @Entity
// @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@ToString
@MappedSuperclass
public abstract class CloudBaseInfo implements IdentityEntity {
/**
* 主键
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", nullable = false)
private Integer id;
/**
* 平台编号
*/
@Column(name = "CLOUD_ID")
private String cloudId;
/**
* 本地更新时间戳,控制更新频率和重复更新
*/
@Column(name = "LATEST_UPDATE")
private Instant latestUpdate;
/**
* 关联的公司
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "COMPANY_ID")
@ToString.Exclude
private Company company;
@Version
@ColumnDefault("0")
@Column(name = "VERSION", nullable = false)
private int version;
@Override
public final boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
Class<?> oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass();
Class<?> thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass();
if (thisEffectiveClass != oEffectiveClass) return false;
CloudBaseInfo cloudInfo = (CloudBaseInfo) o;
return getId() != null && Objects.equals(getId(), cloudInfo.getId());
}
@Override
public final int hashCode() {
return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode();
}
}

View File

@@ -0,0 +1,78 @@
package com.ecep.contract.manager.cloud;
import com.ecep.contract.manager.ds.company.model.Company;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.proxy.HibernateProxy;
import java.time.Instant;
import java.util.Objects;
/**
* 记录同步来源
*/
@Getter
@Setter
@Entity
//@org.springframework.data.relational.core.mapping.Table(name = "CLOUD_INFO")
@Table(name = "CLOUD_INFO", schema = "supplier_ms")
@ToString
public class CloudInfo {
/**
* 主键
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", nullable = false)
private Integer id;
/**
* 记录源类型
*/
@Column(name = "CLOUD_TYPE", length = 50)
private CloudType type;
/**
*
*/
@Column(name = "CLOUD_ID")
private String cloudId;
/**
* 本地更新时间戳,控制更新频率和重复更新
*/
@Column(name = "LATEST_UPDATE")
private Instant latestUpdate;
/**
* 关联的公司
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "COMPANY_ID")
@ToString.Exclude
private Company company;
@Version
@ColumnDefault("0")
@Column(name = "VERSION", nullable = false)
private int version;
@Override
public final boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
Class<?> oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass();
Class<?> thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass();
if (thisEffectiveClass != oEffectiveClass) return false;
CloudInfo cloudInfo = (CloudInfo) o;
return getId() != null && Objects.equals(getId(), cloudInfo.getId());
}
@Override
public final int hashCode() {
return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode();
}
}

View File

@@ -0,0 +1,15 @@
package com.ecep.contract.manager.cloud;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
@Lazy
@Repository
public interface CloudInfoRepository
// curd
extends CrudRepository<CloudInfo, Integer>, PagingAndSortingRepository<CloudInfo, Integer> {
}

View File

@@ -0,0 +1,79 @@
package com.ecep.contract.manager.cloud;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.other.vo.IdentityViewModel;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.*;
import java.util.Objects;
/**
* 云信息
*/
@EqualsAndHashCode(callSuper = false)
@Data
public class CloudInfoViewModel<V extends CloudBaseInfo> extends IdentityViewModel<V> {
/**
* 云端Id
*/
private SimpleStringProperty cloudId = new SimpleStringProperty();
/**
* 公司
*/
private SimpleObjectProperty<Company> company = new SimpleObjectProperty<>();
/**
* 最后更新日期
*/
private SimpleObjectProperty<LocalDateTime> latest = new SimpleObjectProperty<>();
/**
* Version
*/
private SimpleIntegerProperty version = new SimpleIntegerProperty();
@Override
protected void updateFrom(V info) {
super.updateFrom(info);
cloudId.set(info.getCloudId());
company.set(info.getCompany());
if (info.getLatestUpdate() != null) {
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime zonedDateTime = info.getLatestUpdate().atZone(zone);
LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
latest.set(localDateTime);
} else {
latest.set(null);
}
version.set(info.getVersion());
}
@Override
public boolean copyTo(V info) {
boolean changed = super.copyTo(info);
if (!Objects.equals(cloudId.get(), info.getCloudId())) {
info.setCloudId(cloudId.get());
changed = true;
}
Instant latestUpdate = null;
LocalDateTime latestUpdateDateTime = latest.get();
if (latestUpdateDateTime != null) {
latestUpdate = latestUpdateDateTime.toInstant(ZoneOffset.ofHours(8));
}
if (!Objects.equals(latestUpdate, info.getLatestUpdate())) {
info.setLatestUpdate(latestUpdate);
changed = true;
}
return changed;
}
}

View File

@@ -0,0 +1,45 @@
package com.ecep.contract.manager.cloud;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.repository.config.BootstrapMode;
@Configuration
@EnableJpaRepositories(bootstrapMode = BootstrapMode.LAZY)
public class CloudRepositoriesConfig {
// @Bean
// @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
// public BeanDefinition cloudInfoRepositoryDefinition() {
// BeanDefinition definition = new org.springframework.beans.factory.support.GenericBeanDefinition();
// definition.setBeanClassName("com.ecep.contract.manager.cloud.CloudInfoRepository");
// definition.setLazyInit(true);
// return definition;
// }
//
// @Bean
// @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
// public BeanDefinition cloudRkRepositoryDefinition() {
// BeanDefinition definition = new org.springframework.beans.factory.support.GenericBeanDefinition();
// definition.setBeanClassName("com.ecep.contract.manager.cloud.u8.CloudRkRepository");
// definition.setLazyInit(true);
// return definition;
// }
//
// @Bean
// @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
// public BeanDefinition cloudTycRepositoryDefinition() {
// BeanDefinition definition = new org.springframework.beans.factory.support.GenericBeanDefinition();
// definition.setBeanClassName("com.ecep.contract.manager.cloud.u8.CloudTycRepository");
// definition.setLazyInit(true);
// return definition;
// }
//
// @Bean
// @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
// public BeanDefinition cloudYuRepositoryDefinition() {
// BeanDefinition definition = new org.springframework.beans.factory.support.GenericBeanDefinition();
// definition.setBeanClassName("com.ecep.contract.manager.cloud.u8.CloudYuRepository");
// definition.setLazyInit(true);
// return definition;
// }
}

View File

@@ -0,0 +1,23 @@
package com.ecep.contract.manager.cloud;
/**
* 记录源类型
*/
public enum CloudType {
/**
* 上海电气集团相关方平台
*/
RK,
/**
* 天眼查
*/
TYC,
/**
* 用友U8
*/
U8,
/**
* 老版本APP
*/
OLD;
}

View File

@@ -0,0 +1,66 @@
package com.ecep.contract.manager.cloud.old;
import com.ecep.contract.manager.ds.company.model.CompanyContact;
import com.ecep.contract.manager.ds.company.model.CompanyContract;
import java.util.Map;
import java.util.Objects;
/**
*
*/
public class CompanyContactUtils {
/**
* 使用 map 应用到 contact, 如有更新, 则返回 true
*/
public static boolean applyContactByMap(CompanyContact contact, Map<String, Object> map) {
boolean modified = false;
String name = (String) map.get("NAME");
String phone = (String) map.get("PHONE");
String email = (String) map.get("EMAIL");
String address = (String) map.get("ADDRESS");
if (name != null) {
// 更新备注
if (!Objects.equals(contact.getName(), name)) {
contact.setName(name);
modified = true;
}
}
if (phone != null) {
// 更新备注
if (!Objects.equals(contact.getPhone(), phone)) {
contact.setPhone(phone);
modified = true;
}
}
if (email != null) {
// 更新备注
if (!Objects.equals(contact.getEmail(), email)) {
contact.setEmail(email);
modified = true;
}
}
if (address != null) {
// 更新备注
if (!Objects.equals(contact.getAddress(), address)) {
contact.setAddress(address);
modified = true;
}
}
return modified;
}
/**
* 要和{@link CompanyContract#getContactKey(CompanyContact)}一致
*/
public static String getContactKey(Map<String, Object> map) {
if (map == null) {
return null;
}
String name = (String) map.get("NAME");
String phone = (String) map.get("PHONE");
String email = (String) map.get("EMAIL");
return name + phone + email;
}
}

View File

@@ -0,0 +1,53 @@
package com.ecep.contract.manager.cloud.old;
import com.ecep.contract.manager.ds.customer.model.CompanyCustomerFile;
import java.time.LocalDate;
import java.util.Map;
import java.util.Objects;
public class CompanyCustomerFileUtils {
public static boolean applyCustomerFileByMap(CompanyCustomerFile customerFile, Map<String, Object> m) {
boolean modified = false;
String filePath = (String) m.get("FILE_PATH");
String editFilePath = (String) m.get("EDIT_FILE_PATH");
java.sql.Date signDate = (java.sql.Date) m.get("SIGN_DATE");
Boolean valid = (Boolean) m.get("VALID");
if (filePath != null) {
// file path
if (!Objects.equals(customerFile.getFilePath(), filePath)) {
customerFile.setFilePath(filePath);
modified = true;
}
}
if (editFilePath != null) {
// edit file path
if (!Objects.equals(customerFile.getEditFilePath(), editFilePath)) {
customerFile.setEditFilePath(editFilePath);
modified = true;
}
}
if (signDate != null) {
// date
LocalDate localDate = signDate.toLocalDate();
if (!Objects.equals(customerFile.getSignDate(), localDate)) {
customerFile.setSignDate(localDate);
modified = true;
}
}
if (valid != null) {
// valid
if (!Objects.equals(customerFile.isValid(), valid)) {
customerFile.setValid(valid);
modified = true;
}
}
return modified;
}
public static String getCustomerFileKey(Map<String, Object> m) {
return m.get("FILE_PATH").toString();
}
}

View File

@@ -0,0 +1,53 @@
package com.ecep.contract.manager.cloud.old;
import com.ecep.contract.manager.ds.vendor.model.CompanyVendorFile;
import java.time.LocalDate;
import java.util.Map;
import java.util.Objects;
public class CompanyVendorFileUtils {
public static boolean applyVendorFileByMap(CompanyVendorFile vendorFile, Map<String, Object> m) {
boolean modified = false;
String filePath = (String) m.get("FILE_PATH");
String editFilePath = (String) m.get("EDIT_FILE_PATH");
java.sql.Date signDate = (java.sql.Date) m.get("SIGN_DATE");
Boolean valid = (Boolean) m.get("VALID");
if (filePath != null) {
// file path
if (!Objects.equals(vendorFile.getFilePath(), filePath)) {
vendorFile.setFilePath(filePath);
modified = true;
}
}
if (editFilePath != null) {
// edit file path
if (!Objects.equals(vendorFile.getEditFilePath(), editFilePath)) {
vendorFile.setEditFilePath(editFilePath);
modified = true;
}
}
if (signDate != null) {
// date
LocalDate localDate = signDate.toLocalDate();
if (!Objects.equals(vendorFile.getSignDate(), localDate)) {
vendorFile.setSignDate(localDate);
modified = true;
}
}
if (valid != null) {
// valid
if (!Objects.equals(vendorFile.isValid(), valid)) {
vendorFile.setValid(valid);
modified = true;
}
}
return modified;
}
public static String getVendorFileKey(Map<String, Object> m) {
return m.get("FILE_PATH").toString();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,125 @@
package com.ecep.contract.manager.cloud.old;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.contract.model.Contract;
import javafx.concurrent.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
*
*/
public class OldVersionSyncCustomerTask extends Task<Object> {
private static final Logger logger = LoggerFactory.getLogger(OldVersionSyncCustomerTask.class);
private final OldVersionService service = SpringApp.getBean(OldVersionService.class);
private final CompanyService companyService = SpringApp.getBean(CompanyService.class);
private Map<Object, List<Map<String, Object>>> oldNameGroupedMap;
private Map<Object, List<Map<String, Object>>> contactGroupedMap;
private File basePath;
private String titlePrefix = "";
public OldVersionSyncCustomerTask() {
updateTitle("老版本-同步客户数据");
}
@Override
protected void updateTitle(String title) {
super.updateTitle(titlePrefix + title);
}
@Override
protected Object call() throws Exception {
updateTitle("老版本-同步客户数据");
basePath = companyService.getCustomerBasePath();
List<Runnable> runnable = Arrays.asList(this::loadOldNames, this::loadContacts, this::syncCustomers, this::syncContracts);
for (int i = 0; i < runnable.size(); i++) {
titlePrefix = "老版本-同步客户数据-" + (i + 1) + "/" + runnable.size() + "-";
try {
runnable.get(i).run();
} catch (Exception e) {
logger.error("运行至 {} 时,发生错误中断", titlePrefix, e);
break;
}
}
return null;
}
private void loadOldNames() {
try (Stream<Map<String, Object>> stream = service.queryAllCustomerOldNameForStream()) {
updateTitle("载入曾用名");
oldNameGroupedMap = stream.takeWhile(v -> !isCancelled()).parallel()
.collect(Collectors.groupingBy(m -> m.get("GID")));
if (logger.isDebugEnabled()) {
logger.debug("import Customer oldNames = {} from old version app", oldNameGroupedMap.size());
}
updateProgress(0.1, 1);
}
}
private void loadContacts() {
try (Stream<Map<String, Object>> stream = service.queryAllCustomerContactForStream()) {
updateTitle("载入联系人");
contactGroupedMap = stream.takeWhile(v -> !isCancelled()).parallel()
.collect(Collectors.groupingBy(m -> m.get("GID")));
logger.debug("import Customer contacts = {} from old version app", contactGroupedMap.size());
updateProgress(0.2, 1);
}
}
private void syncCustomers() {
try (Stream<Map<String, Object>> stream = service.queryAllCustomerForStream()) {
updateTitle("客户信息");
long size = service.countOfCustomer();
AtomicInteger counter = new AtomicInteger(0);
stream.takeWhile(v -> !isCancelled()).forEach(map -> {
if (isCancelled()) {
updateMessage("Cancelled");
return;
}
Company updated = service.syncCustomer(map, basePath, oldNameGroupedMap, contactGroupedMap);
if (updated != null) {
updateMessage(counter.get() + " / " + size + ">" + updated.getName());
} else {
updateMessage(counter.get() + " / " + size + ">" + map.get("NAME"));
}
updateProgress(counter.incrementAndGet(), size);
});
}
}
private void syncContracts() {
try (Stream<Map<String, Object>> stream = service.queryAllCustomerContractForStream()) {
updateTitle("合同信息");
long size = service.countOfCustomerContract();
AtomicInteger counter = new AtomicInteger(0);
stream.takeWhile(v -> !isCancelled()).forEach(map -> {
if (isCancelled()) {
updateMessage("Cancelled");
return;
}
Contract updated = service.syncCustomerContract(map);
if (updated != null) {
updateMessage(counter.get() + " / " + size + ">" + updated.getName());
} else {
updateMessage(counter.get() + " / " + size + ">" + map.get("NO"));
}
updateProgress(counter.incrementAndGet(), size);
});
}
}
}

View File

@@ -0,0 +1,119 @@
package com.ecep.contract.manager.cloud.old;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.contract.model.Contract;
import javafx.concurrent.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class OldVersionSyncVendorTask extends Task<Object> {
private static final Logger logger = LoggerFactory.getLogger(OldVersionSyncVendorTask.class);
private final OldVersionService service = SpringApp.getBean(OldVersionService.class);
private final CompanyService companyService = SpringApp.getBean(CompanyService.class);
private Map<Object, List<Map<String, Object>>> oldNameGroupedMap;
private Map<Object, List<Map<String, Object>>> contactGroupedMap;
private File basePath;
private String titlePrefix = "";
public OldVersionSyncVendorTask() {
updateTitle("老版本-同步供应商数据");
}
@Override
protected void updateTitle(String title) {
super.updateTitle(titlePrefix + title);
}
@Override
protected Object call() throws Exception {
basePath = companyService.getVendorBasePath();
List<Runnable> runnable = Arrays.asList(this::loadOldNames, this::loadContacts, this::syncVendors, this::syncContracts);
for (int i = 0; i < runnable.size(); i++) {
titlePrefix = "老版本-同步供应商数据-" + (i + 1) + "/" + runnable.size() + "-";
try {
runnable.get(i).run();
} catch (Exception e) {
logger.error("运行至 {} 时,发生错误中断", titlePrefix, e);
break;
}
}
return null;
}
private void loadOldNames() {
try (Stream<Map<String, Object>> stream = service.queryAllVendorOldNameForStream()) {
updateTitle("载入曾用名");
oldNameGroupedMap = stream.takeWhile(v -> !isCancelled()).parallel()
.collect(Collectors.groupingBy(m -> m.get("GID")));
if (logger.isDebugEnabled()) {
logger.debug("import vendor oldNames = {} from old version app", oldNameGroupedMap.size());
}
updateProgress(0.1, 1);
}
}
private void loadContacts() {
try (Stream<Map<String, Object>> stream = service.queryAllVendorContactForStream()) {
updateTitle("载入联系人");
contactGroupedMap = stream.takeWhile(v -> !isCancelled()).parallel()
.collect(Collectors.groupingBy(m -> m.get("GID")));
logger.debug("import vendor contacts = {} from old version app", contactGroupedMap.size());
updateProgress(0.2, 1);
}
}
private void syncVendors() {
try (Stream<Map<String, Object>> stream = service.queryAllVendorForStream()) {
updateTitle("客户信息");
long size = service.countOfVendor();
AtomicInteger counter = new AtomicInteger(0);
stream.takeWhile(v -> !isCancelled()).forEach(map -> {
if (isCancelled()) {
updateMessage("Cancelled");
return;
}
Company updated = service.syncVendor(map, basePath, oldNameGroupedMap, contactGroupedMap);
if (updated != null) {
updateMessage(counter.get() + " / " + size + ">" + updated.getName());
} else {
updateMessage(counter.get() + " / " + size + ">" + map.get("NAME"));
}
updateProgress(counter.incrementAndGet(), size);
});
}
}
private void syncContracts() {
try (Stream<Map<String, Object>> stream = service.queryAllVendorContractForStream()) {
updateTitle("合同信息");
long size = service.countOfVendorContract();
AtomicInteger counter = new AtomicInteger(0);
stream.takeWhile(v -> !isCancelled()).forEach(map -> {
if (isCancelled()) {
updateMessage("Cancelled");
return;
}
Contract updated = service.syncVendorContract(map);
if (updated != null) {
updateMessage(counter.get() + " / " + size + ">" + updated.getName());
} else {
updateMessage(counter.get() + " / " + size + ">" + map.get("NO"));
}
updateProgress(counter.incrementAndGet(), size);
});
}
}
}

View File

@@ -0,0 +1,42 @@
package com.ecep.contract.manager.cloud.rk;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URI;
public class BlackListUpdateContext {
@Setter
@Getter
private ObjectMapper objectMapper;
private Proxy.Type proxyType;
@Getter
private Proxy socksProxy;
@Setter
@Getter
private String url;
@Getter
private long elapse = 1440;
public void setProxy(String proxy) {
if (proxy != null) {
URI proxyUri = URI.create(proxy);
proxyType = Proxy.Type.valueOf(proxyUri.getScheme().toUpperCase());
socksProxy = new Proxy(
proxyType,
new InetSocketAddress(proxyUri.getHost(), proxyUri.getPort())
);
}
}
public void setElapse(String value) {
elapse = Long.parseLong(value);
}
}

View File

@@ -0,0 +1,84 @@
package com.ecep.contract.manager.cloud.rk;
import com.ecep.contract.manager.cloud.CloudBaseInfo;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.ColumnDefault;
import java.time.Instant;
@Getter
@Setter
@Entity
@Table(name = "CLOUD_RK", schema = "supplier_ms")
public class CloudRk extends CloudBaseInfo {
/**
* 是否自动更新
*/
@Column(name = "AUTO_UPDATE", nullable = false, columnDefinition = "boolean default true")
private boolean autoUpdate = false;
/**
* 更新间隔天数
*/
@Column(name = "UPDATE_DAYS", nullable = false, columnDefinition = "int default 30")
private int updateDays;
/**
* 客户信用评级
*/
@ColumnDefault("''")
@Column(name = "CUSTOMER_GRADE", nullable = false)
private String customerGrade;
/**
* 客户信用总分
*/
@ColumnDefault("0")
@Column(name = "CUSTOMER_SCORE", nullable = false)
private Integer customerScore;
@Column(name = "CUSTOMER_DESCRIPTION")
private String customerDescription;
/**
* 供应商信用评级
*/
@ColumnDefault("''")
@Column(name = "VENDOR_GRADE", nullable = false)
private String vendorGrade;
/**
* 供应商信用总分
*/
@ColumnDefault("0")
@Column(name = "VENDOR_SCORE", nullable = false)
private Integer vendorScore;
@Column(name = "VENDOR_DESCRIPTION")
private String vendorDescription;
/**
* 相关方资信评价等级
*/
@ColumnDefault("''")
@Column(name = "CREDIT_RANK", nullable = false)
private String rank;
@Column(name = "CREDIT_RANK_DESCRIPTION")
private String rankDescription;
@Column(name = "CLOUD_LATEST")
private Instant cloudLatest;
@Column(name = "BLACK_LIST_UPDATED")
private Instant cloudBlackListUpdated;
@Column(name = "ENT_UPDATED")
private Instant cloudEntUpdate;
@Column(name = "DESCRIPTION")
private String description;
}

View File

@@ -0,0 +1,55 @@
package com.ecep.contract.manager.cloud.rk;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.Tasker;
import lombok.Setter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
/**
* 数据修复任务
*/
public class CloudRkDataRepairTask extends Tasker<Object> {
@Setter
private int batchSize = 50;
@Override
protected Object execute(MessageHolder holder) {
CompanyService companyService = getBean(CompanyService.class);
CloudRkService cloudRkService = getBean(CloudRkService.class);
Pageable pageRequest = PageRequest.ofSize(batchSize);
while (!isCancelled()) {
Page<Company> page = companyService.findAll(null, pageRequest);
int index = page.getNumber() * page.getSize();
int i = 1;
for (Company company : page) {
if (isCancelled()) {
break;
}
String prefix = (index + i) + "/" + page.getTotalElements() + ", " + company.getName() + "> ";
cloudRkService.getOrCreateCloudRk(company);
holder.info(prefix + " 完成");
updateProgress(index + i, page.getTotalElements());
i++;
}
if (!page.hasNext()) {
break;
}
pageRequest = page.nextPageable();
}
if (isCancelled()) {
updateMessage("Cancelled");
}
return null;
}
}

View File

@@ -0,0 +1,172 @@
package com.ecep.contract.manager.cloud.rk;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Objects;
import com.ecep.contract.manager.cloud.CloudInfoViewModel;
import com.ecep.contract.manager.ui.util.MyDateTimePropertyUtils;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class CloudRkInfoViewModel extends CloudInfoViewModel<CloudRk> {
private SimpleBooleanProperty autoUpdate = new SimpleBooleanProperty();
private SimpleStringProperty rank = new SimpleStringProperty();
private SimpleStringProperty rankDescription = new SimpleStringProperty();
private SimpleStringProperty customerGrade = new SimpleStringProperty();
private SimpleIntegerProperty customerScore = new SimpleIntegerProperty();
private SimpleStringProperty customerDescription = new SimpleStringProperty();
private SimpleStringProperty vendorGrade = new SimpleStringProperty();
private SimpleIntegerProperty vendorScore = new SimpleIntegerProperty();
private SimpleStringProperty vendorDescription = new SimpleStringProperty();
private SimpleObjectProperty<LocalDateTime> cloudLatest = new SimpleObjectProperty<>();
private SimpleObjectProperty<LocalDateTime> cloudBlackListUpdated = new SimpleObjectProperty<>();
private SimpleObjectProperty<LocalDateTime> cloudEntUpdate = new SimpleObjectProperty<>();
private SimpleStringProperty description = new SimpleStringProperty();
@Override
protected void updateFrom(CloudRk info) {
super.updateFrom(info);
update_((CloudRk) info);
}
private void update_(CloudRk info) {
autoUpdate.set(info.isAutoUpdate());
rank.set(info.getRank());
rankDescription.set(info.getRankDescription());
customerGrade.set(info.getCustomerGrade());
customerScore.set(info.getCustomerScore());
customerDescription.set(info.getCustomerDescription());
vendorGrade.set(info.getVendorGrade());
vendorScore.set(info.getVendorScore());
vendorDescription.set(info.getVendorDescription());
description.set(info.getDescription());
if (info.getCloudLatest() != null) {
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime zonedDateTime = info.getCloudLatest().atZone(zone);
LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
cloudLatest.set(localDateTime);
} else {
cloudLatest.set(null);
}
if (info.getCloudBlackListUpdated() != null) {
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime zonedDateTime = info.getCloudBlackListUpdated().atZone(zone);
LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
cloudBlackListUpdated.set(localDateTime);
} else {
cloudBlackListUpdated.set(null);
}
if (info.getCloudEntUpdate() != null) {
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime zonedDateTime = info.getCloudEntUpdate().atZone(zone);
LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
cloudEntUpdate.set(localDateTime);
} else {
cloudEntUpdate.set(null);
}
}
@Override
public boolean copyTo(CloudRk info) {
boolean modified = super.copyTo(info);
if (copyTo_((CloudRk) info)) {
modified = true;
}
return modified;
}
private boolean copyTo_(CloudRk info) {
boolean modified = false;
if (info.isAutoUpdate() != autoUpdate.get()) {
info.setAutoUpdate(autoUpdate.get());
modified = true;
}
if (!Objects.equals(info.getRank(), rank.get())) {
info.setRank(rank.get());
modified = true;
}
if (!Objects.equals(info.getRankDescription(), rankDescription.get())) {
info.setRankDescription(rankDescription.get());
modified = true;
}
if (!Objects.equals(info.getCustomerGrade(), customerGrade.get())) {
info.setCustomerGrade(customerGrade.get());
modified = true;
}
if (!Objects.equals(info.getCustomerScore(), customerScore.get())) {
info.setCustomerScore(customerScore.get());
modified = true;
}
if (!Objects.equals(info.getCustomerDescription(), customerDescription.get())) {
info.setCustomerDescription(customerDescription.get());
modified = true;
}
if (!Objects.equals(info.getVendorGrade(), vendorGrade.get())) {
info.setVendorGrade(vendorGrade.get());
modified = true;
}
if (!Objects.equals(info.getVendorScore(), vendorScore.get())) {
info.setVendorScore(vendorScore.get());
modified = true;
}
if (!Objects.equals(info.getVendorDescription(), vendorDescription.get())) {
info.setVendorDescription(vendorDescription.get());
modified = true;
}
Instant latest = MyDateTimePropertyUtils.localDateTimeToInstant(cloudLatest);
if (!Objects.equals(info.getCloudLatest(), latest)) {
info.setCloudLatest(latest);
modified = true;
}
Instant blackListUpdated = MyDateTimePropertyUtils.localDateTimeToInstant(cloudBlackListUpdated);
if (!Objects.equals(info.getCloudBlackListUpdated(), blackListUpdated)) {
info.setCloudBlackListUpdated(blackListUpdated);
modified = true;
}
if (!Objects.equals(info.getDescription(), description.get())) {
info.setDescription(description.get());
modified = true;
}
Instant entUpdated = MyDateTimePropertyUtils.localDateTimeToInstant(cloudEntUpdate);
if (!Objects.equals(info.getCloudEntUpdate(), entUpdated)) {
info.setCloudEntUpdate(entUpdated);
modified = true;
}
return modified;
}
public static CloudRkInfoViewModel from(CloudRk info) {
CloudRkInfoViewModel viewModel = new CloudRkInfoViewModel();
viewModel.updateFrom(info);
return viewModel;
}
}

View File

@@ -0,0 +1,111 @@
package com.ecep.contract.manager.cloud.rk;
import org.hibernate.Hibernate;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.company.controller.CompanyTableCell;
import com.ecep.contract.manager.ds.company.controller.CompanyWindowController;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ui.AbstEntityManagerSkin;
import com.ecep.contract.manager.ui.util.LocalDateTimeTableCell;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.cell.CheckBoxTableCell;
import lombok.Setter;
public class CloudRkManagerSkin
extends AbstEntityManagerSkin<CloudRk, CloudRkInfoViewModel, CloudRkManagerSkin, CloudRkManagerWindowController> {
@Setter
private CompanyService companyService;
public CloudRkManagerSkin(CloudRkManagerWindowController controller) {
super(controller);
}
CloudRkService getCloudRkService() {
return controller.getViewModelService();
}
CompanyService getCompanyService() {
if (companyService == null) {
companyService = SpringApp.getBean(CompanyService.class);
}
return companyService;
}
@Override
public void initializeTable() {
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
controller.companyColumn.setCellValueFactory(param -> param.getValue().getCompany());
controller.companyColumn.setCellFactory(param -> new CompanyTableCell<>(getCompanyService()));
controller.cloudIdColumn.setCellValueFactory(param -> param.getValue().getCloudId());
controller.latestUpdateColumn.setCellValueFactory(param -> param.getValue().getLatest());
controller.latestUpdateColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
controller.cloudLatestColumn.setCellValueFactory(param -> param.getValue().getCloudLatest());
controller.cloudLatestColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
controller.cloudBlackListUpdatedColumn.setCellValueFactory(param -> param.getValue().getCloudBlackListUpdated());
controller.cloudBlackListUpdatedColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
controller.cloudEntUpdateColumn.setCellValueFactory(param -> param.getValue().getCloudEntUpdate());
controller.cloudEntUpdateColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
controller.autoUpdateColumn.setCellValueFactory(param -> param.getValue().getAutoUpdate());
controller.autoUpdateColumn.setCellFactory(CheckBoxTableCell.forTableColumn(controller.autoUpdateColumn));
controller.descriptionColumn.setCellValueFactory(param -> param.getValue().getDescription());
}
private void onAutoUpdateColumnEditCommit(TableColumn.CellEditEvent<CloudRkInfoViewModel, Boolean> event) {
CloudRkInfoViewModel row = event.getRowValue();
row.getAutoUpdate().set(event.getNewValue());
saveRowData(row);
}
@Override
protected void createContextMenu(ContextMenu contextMenu) {
MenuItem item2 = new MenuItem("刷新");
item2.setOnAction(this::onTableRefreshAction);
MenuItem item3 = new MenuItem("清空备注");
item3.setOnAction(this::onTableClearDescriptionAction);
contextMenu.getItems().addAll(item2, item3);
}
/**
* 请空选择行的注释
*
* @param event event
*/
public void onTableClearDescriptionAction(ActionEvent event) {
ObservableList<CloudRkInfoViewModel> selectedItems = getTableView().getSelectionModel().getSelectedItems();
if (selectedItems.isEmpty()) {
return;
}
CloudRkService service = getCloudRkService();
for (CloudRkInfoViewModel selectedItem : selectedItems) {
selectedItem.getDescription().set("");
selectedItem.saveInFxApplicationThread(service);
}
}
@Override
protected void onTableRowDoubleClickedAction(CloudRkInfoViewModel item) {
Company company = item.getCompany().get();
if (!Hibernate.isInitialized(item)) {
company = getCompanyService().findById(company.getId());
}
CompanyWindowController.show(company, getTableView().getScene().getWindow());
}
}

View File

@@ -0,0 +1,160 @@
package com.ecep.contract.manager.cloud.rk;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.CloudBaseInfo;
import com.ecep.contract.manager.cloud.CloudInfo;
import com.ecep.contract.manager.cloud.tyc.CloudTyc;
import com.ecep.contract.manager.cloud.tyc.CloudTycService;
import com.ecep.contract.manager.cloud.u8.CloudYu;
import com.ecep.contract.manager.cloud.u8.YongYouU8Service;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ui.AbstManagerWindowController;
import com.ecep.contract.manager.ui.FxmlPath;
import com.ecep.contract.manager.ui.Message;
import com.ecep.contract.manager.ui.ViewModelService;
import com.ecep.contract.manager.util.UITools;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.scene.control.TableColumn;
import javafx.stage.WindowEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Consumer;
@Lazy
@Scope("prototype")
@Component
@FxmlPath("/ui/cloud/rk_manager.fxml")
public class CloudRkManagerWindowController
extends AbstManagerWindowController<CloudRk, CloudRkInfoViewModel, CloudRkManagerSkin> {
private static final Logger logger = LoggerFactory.getLogger(CloudRkManagerWindowController.class);
public static void show() {
show(CloudRkManagerWindowController.class, null);
}
@Autowired
private CloudRkService cloudRkService;
public TableColumn<CloudRkInfoViewModel, Number> idColumn;
public TableColumn<CloudRkInfoViewModel, LocalDateTime> latestUpdateColumn;
public TableColumn<CloudRkInfoViewModel, Company> companyColumn;
public TableColumn<CloudRkInfoViewModel, String> cloudIdColumn;
public TableColumn<CloudRkInfoViewModel, LocalDateTime> cloudLatestColumn;
public TableColumn<CloudRkInfoViewModel, LocalDateTime> cloudBlackListUpdatedColumn;
public TableColumn<CloudRkInfoViewModel, LocalDateTime> cloudEntUpdateColumn;
public TableColumn<CloudRkInfoViewModel, Boolean> autoUpdateColumn;
public TableColumn<CloudRkInfoViewModel, String> descriptionColumn;
@Override
protected CloudRkManagerSkin createDefaultSkin() {
return new CloudRkManagerSkin(this);
}
@Override
public void onShown(WindowEvent windowEvent) {
super.onShown(windowEvent);
getTitle().set("数据源:集团相关方");
}
boolean copyTo(CloudInfo v, CloudBaseInfo cloudRk) {
boolean modified = false;
if (!Objects.equals(cloudRk.getLatestUpdate(), v.getLatestUpdate())) {
cloudRk.setLatestUpdate(v.getLatestUpdate());
modified = true;
}
if (!Objects.equals(cloudRk.getCloudId(), v.getCloudId())) {
cloudRk.setCloudId(v.getCloudId());
modified = true;
}
if (!Objects.equals(cloudRk.getCompany(), v.getCompany())) {
cloudRk.setCompany(v.getCompany());
modified = true;
}
return modified;
}
/**
* 数据迁移,从 CloudInfo 迁移到 CloudRk
*/
public void onDateTransferAction(ActionEvent event) {
CompletableFuture.runAsync(() -> {
com.ecep.contract.manager.cloud.CloudInfoRepository cloudInfoRepository = SpringApp.getBean(com.ecep.contract.manager.cloud.CloudInfoRepository.class);
CloudTycService tycService = SpringApp.getBean(CloudTycService.class);
YongYouU8Service u8Service = SpringApp.getBean(YongYouU8Service.class);
cloudInfoRepository.findAll().forEach(v -> {
try {
CloudRk cloudRk = cloudRkService.getOrCreateCloudRk(v);
if (copyTo(v, cloudRk)) {
cloudRkService.save(cloudRk);
}
CloudTyc cloudTyc = tycService.getOrCreateCloudTyc(v);
if (copyTo(v, cloudTyc)) {
tycService.save(cloudTyc);
}
CloudYu cloudYu = u8Service.getOrCreateCloudYu(v);
if (copyTo(v, cloudYu)) {
u8Service.save(cloudYu);
}
} catch (Exception e) {
e.printStackTrace();
}
});
});
}
private void initializeTask(Task<Object> task, String prefix, Consumer<String> consumer) {
task.setOnScheduled(e -> {
consumer.accept("正在从相关方平台同步" + prefix + ",请稍后...");
});
task.setOnRunning(e -> {
consumer.accept("开始" + prefix + "...");
});
task.setOnSucceeded(e -> {
consumer.accept(prefix + "完成...");
});
task.exceptionProperty().addListener((observable, oldValue, newValue) -> {
consumer.accept(newValue.getMessage());
logger.error("{} 发生异常", prefix, newValue);
});
SpringApp.getBean(ScheduledExecutorService.class).submit(task);
consumer.accept("任务已创建...");
}
public void onDataRepairAction(ActionEvent event) {
CloudRkDataRepairTask task = new CloudRkDataRepairTask();
task.titleProperty().get();
UITools.showTaskDialogAndWait("修复数据", task, null);
}
public void onSyncAction(ActionEvent event) {
CloudRkSyncTask task = new CloudRkSyncTask();
UITools.showTaskDialogAndWait("同步数据", task, consumer -> {
initializeTask(task, "同步数据", msg -> consumer.accept(Message.info(msg)));
});
}
@Override
public CloudRkService getViewModelService() {
return cloudRkService;
}
}

View File

@@ -0,0 +1,57 @@
package com.ecep.contract.manager.cloud.rk;
import com.ecep.contract.manager.ds.company.model.Company;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
@Repository
public interface CloudRkRepository
// curd
extends CrudRepository<CloudRk, Integer>, PagingAndSortingRepository<CloudRk, Integer>,
// JPA interfaces
JpaRepository<CloudRk, Integer>, JpaSpecificationExecutor<CloudRk> {
Stream<CloudRk> findByCloudLatestAfter(Instant timestamp);
Stream<CloudRk> findByCloudEntUpdateAfter(Instant timestamp);
/**
* 按公司查找 Cloud RK
*
* @param company 公司对象
* @return Cloud RK
*/
Optional<CloudRk> findByCompany(Company company);
/**
* 按公司查找 Cloud RK
*
* @param companyId 公司对象编号
* @return Cloud RK
*/
Optional<CloudRk> findByCompanyId(int companyId);
List<CloudRk> findAllByCompanyId(int companyId);
long countByLatestUpdateBefore(Instant instant);
long countByAutoUpdateIsTrueAndLatestUpdateBefore(Instant instant);
List<CloudRk> findTop100ByLatestUpdateBeforeOrderByLatestUpdateDesc(Instant instant);
List<CloudRk> findTop100ByAutoUpdateIsTrueAndLatestUpdateBeforeOrderByLatestUpdateDesc(Instant instant);
@Modifying
@Transactional
int deleteAllByCompany(Company company);
}

View File

@@ -0,0 +1,417 @@
package com.ecep.contract.manager.cloud.rk;
import com.ecep.contract.manager.cloud.CloudInfo;
import com.ecep.contract.manager.ds.company.BlackReasonType;
import com.ecep.contract.manager.ds.company.CompanyFileUtils;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.model.CompanyBlackReason;
import com.ecep.contract.manager.ds.company.repository.CompanyBlackReasonRepository;
import com.ecep.contract.manager.ds.company.repository.CompanyOldNameRepository;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.other.service.SysConfService;
import com.ecep.contract.manager.ui.ViewModelService;
import com.ecep.contract.manager.util.HttpJsonUtils;
import com.ecep.contract.manager.util.MyStringUtils;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.persistence.criteria.Path;
import javafx.application.Platform;
import javafx.concurrent.Task;
import lombok.Data;
import org.controlsfx.control.TaskProgressView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
@Lazy
@Service
@CacheConfig(cacheNames = "cloud-rk")
public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoViewModel> {
private static final Logger logger = LoggerFactory.getLogger(CloudRkService.class);
public static final String NAME = "集团相关方平台";
public static final String VENDOR_NAME = "元素征信";
public final static String ENTERPRISE_CREDIT_REPORT = "企业征信报告";
public static final String KEY_PROXY = "cloud.rk.proxy";
public static final String KEY_SYNC_ELAPSE = "cloud.rk.sync.elapse";
public static final long DEFAULT_SYNC_ELAPSE = 36000L;
public static final String KEY_VENDOR_REPORT_URL = "cloud.rk.vendor.report.url";
public static final String KEY_CUSTOMER_REPORT_URL = "cloud.rk.customer.report.url";
public static final String KEY_ENT_SCORE_URL = "cloud.rk.ent_score.url";
public static final String KEY_ENT_REPORT_URL = "cloud.rk.ent_report.url";
public static final String KEY_ENT_FUZZY_URL = "cloud.rk.ent_fuzzy.url";
public static final String KEY_BLACK_LIST_URL = "cloud.rk.black_list.url";
public static final String KEY_BLACK_LIST_ELAPSE = "cloud.rk.black_list.elapse";
@Autowired
private ObjectMapper objectMapper;
/**
* 同步超时, 单位 毫秒
*
* @return 毫秒
*/
public long getSyncElapse() {
String string = confService.getString(KEY_SYNC_ELAPSE);
if (!StringUtils.hasText(string)) {
return DEFAULT_SYNC_ELAPSE;
}
return MyStringUtils.toLong(string, DEFAULT_SYNC_ELAPSE);
}
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public static class EntInfo {
@JsonAlias("entid")
private String id;
@JsonAlias("entname")
private String name;
private boolean nowName;
}
@Autowired
private SysConfService confService;
@Autowired
private CloudRkRepository cloudRKRepository;
@Lazy
@Autowired
private CompanyService companyService;
@Autowired
private CompanyOldNameRepository companyOldNameRepository;
@Autowired
private CompanyBlackReasonRepository companyBlackReasonRepository;
@Autowired
private ScheduledExecutorService scheduledExecutorService;
@Cacheable(key = "#p0")
public CloudRk findById(Integer id) {
return cloudRKRepository.findById(id).orElse(null);
}
public Page<CloudRk> findAll(Specification<CloudRk> spec, Pageable pageable) {
return cloudRKRepository.findAll(spec, pageable);
}
@Override
public Specification<CloudRk> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
Path<Object> company = root.get("company");
return builder.or(
builder.like(company.get("name"), "%" + searchText + "%"),
builder.like(company.get("shortName"), "%" + searchText + "%"),
builder.like(root.get("cloudId"), "%" + searchText + "%"),
builder.like(root.get("description"), "%" + searchText + "%")
);
};
}
/**
* 更新黑名单列表
*/
public void updateBlackList(
Company company, CloudRk cloudRk, BlackListUpdateContext context
) throws IOException {
List<String> companyNames = new ArrayList<>();
companyNames.add(company.getName());
// fixed 平台API使用企业名称可能记录的是曾用名
companyOldNameRepository.findAllByCompanyId(company.getId()).forEach(oldName -> {
// 歧义的曾用名不采用
if (oldName.getAmbiguity()) {
return;
}
companyNames.add(oldName.getName());
});
List<CompanyBlackReason> reasonList = new ArrayList<>();
List<CompanyBlackReason> dbReasons = companyBlackReasonRepository.findAllByCompany(company);
companyNames.forEach(name -> {
String url = context.getUrl() + URLEncoder.encode(name, StandardCharsets.UTF_8);
try {
HttpJsonUtils.get(url, json -> {
if (!json.has("success") || !json.get("success").asBoolean()) {
System.out.println("json = " + json.toPrettyString());
return;
}
if (json.has("data")) {
JsonNode data = json.get("data");
try {
if (data.has("blackReason")) {
for (JsonNode reason : data.get("blackReason")) {
toCompanyBlackReasonList(company, BlackReasonType.BLACK, reason, dbReasons, reasonList, context.getObjectMapper());
}
}
if (data.has("greyReason")) {
for (JsonNode reason : data.get("greyReason")) {
toCompanyBlackReasonList(company, BlackReasonType.GRAY, reason, dbReasons, reasonList, context.getObjectMapper());
}
}
} catch (Exception ex) {
logger.error("{} {},json = {}", company.getName(), ex.getMessage(), json, ex);
throw new RuntimeException(json.toString(), ex);
}
}
// 保存JSON数据到公司目录
String companyPath = company.getPath();
if (StringUtils.hasText(companyPath)) {
File dir = new File(companyPath);
if (dir.exists()) {
File file = new File(dir, CompanyFileUtils.FILE_BLACK_LIST_JSON);
try {
objectMapper.writeValue(file, json);
} catch (IOException e) {
logger.warn("Unable Save BlackList to {}, company:{}", file, company.getName(), e);
}
}
}
}, context.getObjectMapper(), context.getSocksProxy());
} catch (IOException e) {
throw new RuntimeException(e);
}
});
if (!reasonList.isEmpty()) {
companyBlackReasonRepository.saveAll(reasonList);
}
cloudRk.setCloudBlackListUpdated(Instant.now());
}
private void toCompanyBlackReasonList(
Company company, BlackReasonType type,
JsonNode reason, List<CompanyBlackReason> dbReasons,
List<CompanyBlackReason> reasonList, ObjectMapper objectMapper
) throws JsonMappingException {
ObjectNode object = (ObjectNode) reason;
String key = "rk-" + object.remove("id").asText();
CompanyBlackReason cbr = dbReasons.stream().filter(r -> r.getKey().equals(key)).findAny().orElseGet(CompanyBlackReason::new);
objectMapper.updateValue(cbr, reason);
cbr.setCompany(company);
cbr.setType(type);
cbr.setKey(key);
reasonList.add(cbr);
}
public CompletableFuture<BlackListUpdateContext> createBlackListUpdateContext() {
return CompletableFuture.supplyAsync(() -> {
BlackListUpdateContext context = new BlackListUpdateContext();
context.setObjectMapper(objectMapper);
context.setProxy(confService.getString(KEY_PROXY));
context.setUrl(confService.getString(KEY_BLACK_LIST_URL));
// context.setElapse(confService.getLong(KEY_BLACK_LIST_ELAPSE));
return context;
});
}
/**
* @return true
*/
public boolean checkBlackListUpdateElapse(
Company company, CloudRk cloudRk, BlackListUpdateContext context
) {
Instant start = cloudRk.getCloudBlackListUpdated();
if (start == null) {
return true;
}
Instant elapse = start.plusSeconds(context.getElapse());
return elapse.isBefore(Instant.now());
}
public CloudRk getOrCreateCloudRk(CloudInfo info) {
Optional<CloudRk> optional = cloudRKRepository.findById(info.getId());
return optional.orElseGet(() -> getOrCreateCloudRk(info.getCompany()));
}
/**
* 返回或者创建 Cloud RK
*
* @param company 公司对象
* @return Cloud RK
*/
public CloudRk getOrCreateCloudRk(Company company) {
Integer companyId = company.getId();
List<CloudRk> list = cloudRKRepository.findAllByCompanyId(companyId);
if (list.isEmpty()) {
CloudRk rk = new CloudRk();
rk.setCompany(company);
rk.setCustomerGrade("");
rk.setCustomerScore(-1);
rk.setVendorGrade("");
rk.setVendorScore(-1);
rk.setRank("");
return cloudRKRepository.save(rk);
}
if (list.size() == 1) {
return list.getFirst();
}
// 查询有 CloudId 的记录
List<CloudRk> hasCouldIdList = list.stream().filter(v -> StringUtils.hasText(v.getCloudId())).collect(Collectors.toList());
// 没有匹配到一条时
if (hasCouldIdList.isEmpty()) {
// 保留第一条,其他删除
CloudRk rk = list.removeFirst();
cloudRKRepository.deleteAll(list);
return rk;
}
// 只有匹配到一条有 CloudId 的记录
if (hasCouldIdList.size() == 1) {
// 保留匹配的记录,其他删除
CloudRk rk = hasCouldIdList.removeFirst();
list.remove(rk);
cloudRKRepository.deleteAll(list);
return rk;
}
// 查询有 CloudLatest 的记录
List<CloudRk> hasLatestList = hasCouldIdList.stream().filter(v -> v.getCloudLatest() != null).collect(Collectors.toList());
// 没有匹配到一条时
if (hasLatestList.isEmpty()) {
// 保留第一条,其他删除
CloudRk rk = hasCouldIdList.removeFirst();
list.remove(rk);
cloudRKRepository.deleteAll(list);
return rk;
}
// 只有匹配到一条有 CloudId 的记录
if (hasLatestList.size() == 1) {
// 保留匹配的记录,其他删除
CloudRk rk = hasLatestList.removeFirst();
list.remove(rk);
cloudRKRepository.deleteAll(list);
return rk;
}
return hasLatestList.getFirst();
}
/**
* 保存 Cloud Rk
*
* @param cloudRk Cloud Rk 对象
* @return 更新的 Cloud Rk
*/
@CacheEvict(key = "#p0.id")
public CloudRk save(CloudRk cloudRk) {
return cloudRKRepository.save(cloudRk);
}
@CacheEvict(key = "#p0.id")
@Override
public void delete(CloudRk entity) {
cloudRKRepository.delete(entity);
}
/**
* 返回 在 {@link #getSyncElapse()} 毫秒前,更新的
*
* @return 记录条数
*/
public long countNeedUpdate() {
Instant now = Instant.now();
long elapse = getSyncElapse();
Instant instant = now.minusSeconds(elapse);
return cloudRKRepository.countByAutoUpdateIsTrueAndLatestUpdateBefore(instant);
}
/**
* 返回距离上次更新超过 SysConfigcloud.rk.black_list.elapse 秒的公司
*/
// @Transactional
public List<CloudRk> findNeedUpdate() {
Instant now = Instant.now();
long elapse = getSyncElapse();
Instant instant = now.minusSeconds(elapse);
return cloudRKRepository.findTop100ByAutoUpdateIsTrueAndLatestUpdateBeforeOrderByLatestUpdateDesc(instant);
}
/**
* 生成定时同步任务
*
* @param taskProgressView 任务视图
*/
public void scheduledTasks(TaskProgressView<Task<?>> taskProgressView) {
AtomicReference<Runnable> reference = new AtomicReference<>();
Runnable runnable = () -> {
CloudRkSyncTask task = new CloudRkSyncTask();
Platform.runLater(() -> taskProgressView.getTasks().add(task));
// 延迟10秒
task.delay(10, CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS, scheduledExecutorService))
.thenRun(() -> {
try {
task.run();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
// 30 分钟后再次运行
scheduledExecutorService.schedule(reference.get(), 30, TimeUnit.MINUTES);
}
);
};
reference.set(runnable);
// 第一次延时启动
scheduledExecutorService.schedule(runnable, 1, TimeUnit.MINUTES);
}
@CacheEvict
public void deleteByCompany(Company company) {
int deleted = cloudRKRepository.deleteAllByCompany(company);
if (deleted > 0) {
if (logger.isInfoEnabled()) {
logger.info("Delete {} records by company:#{}", deleted, company.getId());
}
}
}
// TODO 这个可以无法更新缓存
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "#p1.id"),
}
)
public void resetTo(Company from, Company to) {
List<CloudRk> list = cloudRKRepository.findAllByCompanyId(from.getId());
for (CloudRk item : list) {
item.setCompany(to);
}
cloudRKRepository.saveAll(list);
}
}

View File

@@ -0,0 +1,143 @@
package com.ecep.contract.manager.cloud.rk;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.rk.ctx.CloudRkCtx;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.contract.service.ContractService;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.Tasker;
import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import java.time.Instant;
import java.time.LocalDate;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
/**
* 集团相关方平台同步任务
*/
public class CloudRkSyncTask extends Tasker<Object> {
private static final Logger logger = LoggerFactory.getLogger(CloudRkSyncTask.class);
private ContractService contractService;
@Override
protected Object execute(MessageHolder holder) throws Exception {
updateTitle("集团相关方平台");
CloudRkCtx cloudRkCtx = null;
CloudRkService service = null;
try {
cloudRkCtx = new CloudRkCtx();
service = SpringApp.getBean(CloudRkService.class);
cloudRkCtx.setCloudRkService(service);
} catch (BeansException e) {
holder.error("没有找到 " + CloudRkService.NAME + " 服务");
return null;
}
long total = service.countNeedUpdate();
if (total == 0) {
holder.info("没有需要更新");
return null;
}
AtomicInteger counter = new AtomicInteger(0);
holder.info("统计需要更新的 " + total + "");
try {
// 每次获取100条记录
while (!isCancelled()) {
List<CloudRk> needUpdate = service.findNeedUpdate();
if (needUpdate.isEmpty()) {
holder.info("处理完成");
break;
}
for (CloudRk cloudRk : needUpdate) {
if (isCancelled()) {
break;
}
MessageHolder subHolder = holder.sub(counter.get() + " / " + total + ">");
// fixed lazy
Company company = cloudRk.getCompany();
if (company == null) {
subHolder.error("数据不完整,没有关联公司");
break;
}
if (!Hibernate.isInitialized(company)) {
company = getCompanyService().findById(company.getId());
cloudRk.setCompany(company);
}
if (cloudRk.isAutoUpdate()) {
LocalDate date = LocalDate.now().minusYears(3);
long count = getContractService().findAllByCompany(company).stream()
.filter(c -> c.getSetupDate() != null)
.filter(c -> c.getSetupDate().isAfter(date))
.count();
if (count == 0) {
holder.info("公司:" + company.getName() + " 没有3年以上的合同, 取消自动更新");
cloudRk.setAutoUpdate(false);
}
}
try {
cloudRk.setDescription("");
if (cloudRkCtx.syncCompany(company, cloudRk, subHolder)) {
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
cloudRk.setLatestUpdate(Instant.now());
service.save(cloudRk);
}
updateProgress(counter.incrementAndGet(), total);
}
}
if (isCancelled()) {
updateMessage("Cancelled");
}
} catch (Exception e) {
logger.error("运行至 {}/{} 时,发生错误中断", counter.get(), total, e);
}
updateProgress(1, 1);
return null;
}
public CompletableFuture<Void> delay(int second, Executor executor) {
CompletableFuture<Void> future = new CompletableFuture<>();
long until = System.currentTimeMillis() + second * 1000L;
String title = getTitle();
AtomicReference<Runnable> reference = new AtomicReference<>();
Runnable runnable = () -> {
long let = until - System.currentTimeMillis();
if (let < 0) {
System.out.println("complete @" + Thread.currentThread().getName());
future.complete(null);
} else {
// 再次调度
executor.execute(reference.get());
updateTitle(title + " 延时 " + ((int) let / 1000) + "");
}
};
reference.set(runnable);
// 第一次调度
executor.execute(runnable);
return future;
}
ContractService getContractService() {
if (contractService == null) {
contractService = getBean(ContractService.class);
}
return contractService;
}
}

View File

@@ -0,0 +1,271 @@
package com.ecep.contract.manager.cloud.rk;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.company.CompanyFileUtils;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.model.CompanyContact;
import com.ecep.contract.manager.ds.company.model.CompanyOldName;
import com.ecep.contract.manager.ds.company.repository.CompanyContactRepository;
import com.ecep.contract.manager.ds.company.repository.CompanyOldNameRepository;
import com.ecep.contract.manager.ds.company.service.CompanyOldNameService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@Data
public class EntReportParser {
private static final Logger logger = LoggerFactory.getLogger(EntReportParser.class);
private ObjectMapper objectMapper;
private Company company;
private CloudRk cloudRk;
private boolean modified = false;
public void parse(JsonNode json) {
if (!json.has("B1001")) {
// 没有数据
throw new RuntimeException("B1001 can't be null, json:" + json);
}
JsonNode b1001 = json.get("B1001");
if (!b1001.has("count") || b1001.get("count").asInt() < 1 || !b1001.has("data")) {
// 没有数据
return;
}
JsonNode data = b1001.get("data");
updateCompanyProperty("entType", data.get("enttype"));
updateCompanyProperty("entStatus", data.get("entstatus"));
updateCompanyProperty("setupDate", data.get("esdate"));
updateCompanyUniscid(data);
updateCompanyNameHistory(data);
updateCompanyProperty("regAddr", data.get("dom"));
updateCompanyProperty("registeredCapital", data.get("regcap"));
updateCompanyProperty("registeredCapitalCurrency", data.get("regcapcur"));
updateCompanyProperty("legalRepresentative", data.get("frname"));
updateCompanyProperty("district", data.get("regorgprovince"));
updateCompanyProperty("telephone", data.get("tel"));
updateCompanyProperty("address", data.get("oploc"));
updateCompanyProperty("operationPeriodBegin", data.get("opfrom"));
updateCompanyProperty("operationPeriodEnd", data.get("opto"), "-");
updateCompanyProperty("industry", data.get("nicfulltitle"));
//
updateCloudRkEntUpdateDate(data);
// 更新法人联系人
updateLegalRepresentativeContact(data);
// 保存JSON数据到公司目录
saveJsonToFile(json);
}
private void updateLegalRepresentativeContact(JsonNode data) {
String legalRepresentative = company.getLegalRepresentative();
if (!StringUtils.hasText(legalRepresentative)) {
return;
}
CompanyContact contact = null;
boolean modified = false;
CompanyContactRepository contactRepository = SpringApp.getBean(CompanyContactRepository.class);
List<CompanyContact> contactList = contactRepository.findAllByCompanyAndName(company, legalRepresentative);
if (contactList == null) {
// db error
return;
}
if (contactList.isEmpty()) {
//没有,创建法人联系人
contact = new CompanyContact();
contact.setCompany(company);
contact.setName(legalRepresentative);
contact.setPosition("法定代表人");
contact.setCreated(LocalDate.now());
modified = true;
} else {
Optional<CompanyContact> any = contactList.stream().filter(c -> "法定代表人".equals(c.getPosition())).findAny();
if (any.isEmpty()) {
any = contactList.stream().findAny();
}
contact = any.get();
// if (contact.getPostion() == null || !contact.setPostion().contains("法定代表人")) {
// contact.setMemo("法定代表人");
// modified = true;
// }
}
if (!StringUtils.hasText(contact.getEmail())) {
String text = data.get("email").asText();
contact.setEmail(text);
modified = true;
}
if (!StringUtils.hasText(contact.getAddress())) {
String text = company.getAddress();
contact.setAddress(text);
modified = true;
}
if (!StringUtils.hasText(contact.getPhone())) {
String text = company.getTelephone();
contact.setPhone(text);
modified = true;
}
if (!StringUtils.hasText(contact.getPosition())) {
contact.setPosition("法定代表人");
modified = true;
}
if (modified) {
contactRepository.save(contact);
}
}
private void updateCompanyNameHistory(JsonNode data) {
JsonNode node = data.get("nameHistory");
if (node == null) {
return;
}
// 历史曾用名
String nameHistory = node.asText();
if (!StringUtils.hasText(nameHistory)) {
return;
}
List<String> historyNames = new ArrayList<>();
for (String str : nameHistory.split(",")) {
String trimmed = str.trim();
if (StringUtils.hasText(trimmed)) {
historyNames.add(trimmed);
}
}
CompanyOldNameService service = SpringApp.getBean(CompanyOldNameService.class);
List<CompanyOldName> oldNames = service.findAllByCompany(company);
for (CompanyOldName oldName : oldNames) {
historyNames.remove(oldName.getName());
}
for (String historyName : historyNames) {
CompanyOldName oldName = new CompanyOldName();
oldName.setName(historyName);
oldName.setCompanyId(company.getId());
oldName.setMemo("从相关方平台导入");
oldName.setAmbiguity(false);
service.save(oldName);
}
}
private void updateCompanyUniscid(JsonNode data) {
JsonNode node = data.get("uniscid");
if (node == null) {
return;
}
String uid = node.asText();
if (StringUtils.hasText(uid)) {
if (!uid.equals(company.getUniscid())) {
if (logger.isInfoEnabled()) {
logger.info("更新 {} 的 UNISCID {} -> {}", company.getName(), company.getUniscid(), uid);
}
company.setUniscid(uid);
modified = true;
}
} else {
//fixed 当平台返回的 社会统一信用代码为空时,如果原来已经有的,则不做更新
if (StringUtils.hasText(company.getUniscid())) {
if (logger.isInfoEnabled()) {
logger.info("来自平台的 UNISCID 为空,但本地{}已经记录{},不做更改", company.getName(), company.getUniscid());
}
} else {
company.setUniscid("");
modified = true;
}
}
//
}
/**
* 更新 平台的数据更新时间戳
*/
private void updateCloudRkEntUpdateDate(JsonNode data) {
JsonNode node = data.get("updated");
if (node == null) {
return;
}
LocalDateTime updated = objectMapper.convertValue(node, LocalDateTime.class);
cloudRk.setCloudEntUpdate(updated.toInstant(ZoneOffset.ofHours(8)));
}
private void updateCompanyProperty(String field, JsonNode node, String... excludeValues) {
if (node == null || node.isNull()) {
return;
}
String text = node.asText();
for (String excludeValue : excludeValues) {
if (Objects.equals(text, excludeValue)) {
return;
}
}
updateCompanyProperty(field, node);
}
/**
* 更新属性通用方法, 数据的类型转换由 objectMapper 提供
*
* @param field 类属性名称
* @param node 数据来源 json node
*/
private void updateCompanyProperty(String field, JsonNode node) {
if (node == null || node.isNull()) {
return;
}
PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(Company.class, field);
if (descriptor == null) {
logger.error("Company 的字段 {} 不存在,请确认.", field);
return;
}
try {
Object oldValue = descriptor.getReadMethod().invoke(company);
Object newValue = objectMapper.convertValue(node, descriptor.getReadMethod().getReturnType());
if (!Objects.equals(oldValue, newValue)) {
descriptor.getWriteMethod().invoke(company, newValue);
modified = true;
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void saveJsonToFile(JsonNode json) {
String companyPath = company.getPath();
if (StringUtils.hasText(companyPath)) {
File dir = new File(companyPath);
if (dir.exists()) {
File file = new File(dir, CompanyFileUtils.FILE_B1001_JSON);
try {
objectMapper.writeValue(file, json);
} catch (IOException e) {
logger.warn("Unable Save BlackList to {}, company:{}", file, company.getName(), e);
}
}
}
}
}

View File

@@ -0,0 +1,823 @@
package com.ecep.contract.manager.cloud.rk.ctx;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.AbstractCtx;
import com.ecep.contract.manager.cloud.rk.CloudRk;
import com.ecep.contract.manager.cloud.rk.CloudRkService;
import com.ecep.contract.manager.ds.company.BlackReasonType;
import com.ecep.contract.manager.ds.company.CompanyFileUtils;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.model.CompanyBlackReason;
import com.ecep.contract.manager.ds.company.model.CompanyContact;
import com.ecep.contract.manager.ds.company.model.CompanyOldName;
import com.ecep.contract.manager.ds.company.service.CompanyBlackReasonService;
import com.ecep.contract.manager.ds.company.service.CompanyContactService;
import com.ecep.contract.manager.ds.company.service.CompanyOldNameService;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.util.HttpJsonUtils;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import javax.net.ssl.SSLException;
import java.io.File;
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import static com.ecep.contract.manager.SpringApp.getBean;
public class CloudRkCtx extends AbstractCtx {
private static final Logger logger = LoggerFactory.getLogger(CloudRkCtx.class);
@Setter
private CloudRkService cloudRkService;
@Setter
private CompanyService companyService;
@Setter
private CompanyBlackReasonService companyBlackReasonService;
@Setter
private ObjectMapper objectMapper;
private Proxy socksProxy;
public CloudRkService getCloudRkService() {
if (cloudRkService == null) {
cloudRkService = getBean(CloudRkService.class);
}
return cloudRkService;
}
public CompanyService getCompanyService() {
if (companyService == null) {
companyService = getBean(CompanyService.class);
}
return companyService;
}
CompanyBlackReasonService getCompanyBlackReasonService() {
if (companyBlackReasonService == null) {
companyBlackReasonService = getBean(CompanyBlackReasonService.class);
}
return companyBlackReasonService;
}
ObjectMapper getObjectMapper() {
if (objectMapper == null) {
objectMapper = getBean(ObjectMapper.class);
}
return objectMapper;
}
Proxy getSocksProxy() {
if (socksProxy == null) {
String proxy = getConfService().getString(CloudRkService.KEY_PROXY);
URI proxyUri = URI.create(proxy);
Proxy.Type proxyType = Proxy.Type.valueOf(proxyUri.getScheme().toUpperCase());
socksProxy = new Proxy(
proxyType,
new InetSocketAddress(proxyUri.getHost(), proxyUri.getPort())
);
}
return socksProxy;
}
public void post(String url, Consumer<Map<String, Object>> data, Consumer<JsonNode> consumer) throws IOException {
HttpJsonUtils.post(url, data, consumer, getObjectMapper(), getSocksProxy());
}
public boolean syncCompany(Company company, CloudRk cloudRk, MessageHolder holder) {
if (!StringUtils.hasText(cloudRk.getCloudId())) {
holder.warn("未定义平台编号, 尝试从平台上自动获取");
// 当未定义平台编号时,尝试自动获取
if (!queryCloudIdAndSelectOne(company, cloudRk, holder)) {
// 自动获取到平台编号失败,立即返回
return false;
}
}
if (!StringUtils.hasText(cloudRk.getCloudId()) || cloudRk.getCloudId().equals("-")) {
// 平台编号为 空 或 - 时,跳过同步
holder.debug("平台编号为 空 或 - 时,跳过同步");
return false;
}
boolean updated = false;
try {
if (updateEnterpriseInfo(company, cloudRk, holder)) {
company = getCompanyService().save(company);
updated = true;
}
if (updateBlackList(company, cloudRk, holder)) {
updated = true;
}
if (updateEnterpriseCredit(company, cloudRk, holder)) {
// cloudRk modified
updated = true;
}
if (updateCustomerScore(company, cloudRk, holder)) {
// cloudRk modified
updated = true;
}
if (updateVendorScore(company, cloudRk, holder)) {
// cloudRk modified
updated = true;
}
} catch (Exception e) {
// 异常
logger.error("使用评分接口更新企业资信评价等级时发生错误", e);
cloudRk.setDescription("评分接口错误:" + e.getMessage());
}
return updated;
}
/**
* 更新黑名单列表
*/
public boolean updateBlackList(
Company company, CloudRk cloudRk, MessageHolder holder
) throws IOException {
Instant start = cloudRk.getCloudBlackListUpdated();
if (start != null) {
long elapse = getConfService().getLong(CloudRkService.KEY_BLACK_LIST_ELAPSE);
if (elapse > 0) {
Instant next = start.plusSeconds(elapse);
if (next.isAfter(Instant.now())) {
holder.debug("更新时间未到, 上次更新时间 = " + start);
return false;
}
}
}
String api = getConfService().getString(CloudRkService.KEY_BLACK_LIST_URL);
List<String> companyNames = getCompanyService().getAllNames(company);
List<CompanyBlackReason> reasonList = new ArrayList<>();
List<CompanyBlackReason> dbReasons = getCompanyBlackReasonService().findAllByCompany(company);
for (String name : companyNames) {
String url = api + URLEncoder.encode(name, StandardCharsets.UTF_8);
try {
HttpJsonUtils.get(url, json -> {
applyBlackReason(json, company, cloudRk, reasonList, dbReasons, holder);
saveJsonToFile(company, json, "black-" + name + ".json", holder);
}, getObjectMapper(), getSocksProxy());
} catch (IOException e) {
catchException(e, holder);
}
}
if (reasonList.isEmpty()) {
cloudRk.setCloudBlackListUpdated(Instant.now());
return false;
}
for (CompanyBlackReason companyBlackReason : reasonList) {
getCompanyBlackReasonService().save(companyBlackReason);
}
cloudRk.setCloudBlackListUpdated(Instant.now());
return true;
}
private boolean applyBlackReason(
JsonNode json, Company company, CloudRk cloudRk,
List<CompanyBlackReason> reasonList, List<CompanyBlackReason> dbReasons,
MessageHolder holder
) {
if (isUnSuccess(json, holder)) {
return false;
}
if (!json.has("data")) {
holder.error("数据异常返回的json中没有 data 字段");
return false;
}
JsonNode data = json.get("data");
if (data.has("blackReason")) {
for (JsonNode reason : data.get("blackReason")) {
try {
toCompanyBlackReasonList(company, BlackReasonType.BLACK, reason, dbReasons, reasonList);
} catch (JsonMappingException e) {
holder.error("blackReason " + e.getMessage() + ", " + reason);
}
}
}
if (data.has("greyReason")) {
for (JsonNode reason : data.get("greyReason")) {
try {
toCompanyBlackReasonList(company, BlackReasonType.GRAY, reason, dbReasons, reasonList);
} catch (JsonMappingException e) {
holder.error("greyReason " + e.getMessage() + ", " + reason);
}
}
}
return true;
}
private void toCompanyBlackReasonList(
Company company, BlackReasonType type,
JsonNode reason, List<CompanyBlackReason> dbReasons,
List<CompanyBlackReason> reasonList
) throws JsonMappingException {
ObjectNode object = (ObjectNode) reason;
String key = "rk-" + object.remove("id").asText();
CompanyBlackReason cbr = dbReasons.stream().filter(r -> r.getKey().equals(key)).findAny().orElseGet(CompanyBlackReason::new);
getObjectMapper().updateValue(cbr, reason);
cbr.setCompany(company);
cbr.setType(type);
cbr.setKey(key);
reasonList.add(cbr);
}
/**
* 更新评分
*/
public boolean updateEnterpriseCredit(
Company company, CloudRk cloudRk, MessageHolder holder
) throws IOException {
String api = getConfService().getString(CloudRkService.KEY_ENT_SCORE_URL);
AtomicBoolean modified = new AtomicBoolean(false);
try {
post(api, data -> {
data.put("entname", company.getName());
// data.put("entid", cloudInfo.getCloudId());
data.put("get", true);
}, json -> {
modified.set(applyEnterpriseCredit(json, cloudRk, holder));
saveJsonToFile(company, json, "credit.json", holder);
});
} catch (IOException e) {
catchException(e, holder);
}
return modified.get();
}
private boolean applyEnterpriseCredit(JsonNode json, CloudRk cloudRk, MessageHolder holder) {
if (isUnSuccess(json, holder)) {
return false;
}
if (isUnHasField(json, "data", holder)) {
return false;
}
JsonNode data = json.get("data");
boolean modified = false;
String level = "";
String description = "";
if (data.isNull()) {
level = "-";
} else {
level = data.get("level").asText();
description = data.get("levelDescription").asText();
}
if (updateText(cloudRk::getRank, cloudRk::setRank, level, holder, "企业资信评价等级")) {
modified = true;
}
if (updateText(cloudRk::getRankDescription, cloudRk::setRankDescription, description, holder, "企业资信评价等级说明")) {
modified = true;
}
return modified;
}
private boolean isUnHasField(JsonNode json, String field, MessageHolder holder) {
if (!json.has("data")) {
holder.error("数据异常返回的json中没有 data 字段");
return true;
}
return false;
}
private boolean isUnSuccess(JsonNode json, MessageHolder holder) {
if (isUnHasField(json, "success", holder)) {
return true;
}
if (!json.get("success").asBoolean()) {
holder.error("数据异常,返回 success = false, " + json);
return true;
}
return false;
}
/**
* 客户信用
*/
public boolean updateCustomerScore(
Company company, CloudRk cloudRk, MessageHolder holder
) throws IOException {
String url = getConfService().getString(CloudRkService.KEY_CUSTOMER_REPORT_URL);
AtomicBoolean modified = new AtomicBoolean(false);
try {
post(url, data -> {
// data.put("entName", company.getName());
data.put("entId", cloudRk.getCloudId());
data.put("get", true);
}, json -> {
modified.set(applyCustomerScore(json, company, cloudRk, holder));
saveJsonToFile(company, json, "customer-score.json", holder);
});
} catch (IOException e) {
catchException(e, holder);
}
return modified.get();
}
private boolean applyCustomerScore(JsonNode json, Company company, CloudRk cloudRk, MessageHolder holder) {
if (isUnSuccess(json, holder)) {
return false;
}
boolean modified = false;
String grade = "";
int score = 0;
String description = "";
if (isUnHasField(json, "data", holder)) {
grade = "-";
score = -1;
} else {
JsonNode data = json.get("data");
if (data.isNull()) {
grade = "";
score = -1;
} else {
grade = data.get("grade").asText();
score = data.get("totalScore").asInt();
description = data.get("description").asText();
}
}
if (updateText(cloudRk::getCustomerGrade, cloudRk::setCustomerGrade, grade, holder, "客户信用评级")) {
modified = true;
}
if (updateNumber(cloudRk::getCustomerScore, cloudRk::setCustomerScore, score, holder, "客户信用总分")) {
modified = true;
}
if (updateText(cloudRk::getCustomerDescription, cloudRk::setCustomerDescription, description, holder, "客户信用评级说明")) {
modified = true;
}
return modified;
}
public boolean updateVendorScore(
Company company, CloudRk cloudRk, MessageHolder holder
) throws IOException {
String url = getConfService().getString(CloudRkService.KEY_VENDOR_REPORT_URL);
AtomicBoolean modified = new AtomicBoolean(false);
try {
post(url, data -> {
// data.put("entName", company.getName());
data.put("entId", cloudRk.getCloudId());
data.put("get", true);
}, json -> {
modified.set(applyVendorScore(json, cloudRk, holder));
saveJsonToFile(company, json, "vendor-score.json", holder);
});
} catch (IOException e) {
catchException(e, holder);
}
return modified.get();
}
private boolean applyVendorScore(JsonNode json, CloudRk cloudRk, MessageHolder holder) {
if (isUnSuccess(json, holder)) {
return false;
}
boolean modified = false;
String grade = "";
int score = 0;
String description = "";
if (isUnHasField(json, "data", holder)) {
grade = "-";
score = -1;
} else {
JsonNode data = json.get("data");
if (data.isNull()) {
grade = "";
score = -1;
} else {
grade = data.get("scoreLevel").asText();
score = data.get("score").asInt();
description = data.get("scoreDes").asText();
}
}
if (updateText(cloudRk::getVendorGrade, cloudRk::setVendorGrade, grade, holder, "供应商信用得分")) {
modified = true;
}
if (updateNumber(cloudRk::getVendorScore, cloudRk::setVendorScore, score, holder, "供应商信用总分")) {
modified = true;
}
if (updateText(cloudRk::getVendorDescription, cloudRk::setVendorDescription, description, holder, "供应商信用评级说明")) {
modified = true;
}
return modified;
}
/**
* 自动获取到平台编号
*
* @param company 公司对象
* @param cloudRk Cloud Rk
* @return true 更新了 cloudId否则false
*/
private boolean queryCloudIdAndSelectOne(
Company company, CloudRk cloudRk, MessageHolder holder
) {
try {
List<CloudRkService.EntInfo> entInfos = queryEnterpriseWithFuzzy(company, cloudRk, holder);
// 返回的查询结果为空时
if (entInfos.isEmpty()) {
// 设置为 -, 不在重复查找
cloudRk.setCloudId("-");
holder.warn("在平台中没有匹配到 " + company.getName());
return false;
}
// 在返回的结果中,找到与公司名字一致的一个
Optional<CloudRkService.EntInfo> optional = entInfos.stream().filter(n -> n.getName().equals(company.getName())).findAny();
if (optional.isPresent()) {
cloudRk.setCloudId(optional.get().getId());
return true;
}
//
holder.error("在平台中查询到多个匹配 (" + entInfos.stream().map(CloudRkService.EntInfo::getName).collect(Collectors.joining(", ")) + "),请手工同步选择匹配");
return false;
} catch (Exception e) {
// 异常
holder.error("查询接口获取企业平台编号发生错误 = " + e.getMessage());
if (logger.isErrorEnabled()) {
logger.error("使用模糊查询接口获取 {} 企业平台编号发生错误", company.getName(), e);
}
return false;
}
}
/**
* 使用模糊查询接口查询相关企业信息
*/
public List<CloudRkService.EntInfo> queryEnterpriseWithFuzzy(
Company company, CloudRk cloudRk, MessageHolder holder
) throws IOException {
String url = getConfService().getString(CloudRkService.KEY_ENT_FUZZY_URL);
List<CloudRkService.EntInfo> results = new ArrayList<>();
ObjectMapper objectMapper = getObjectMapper();
try {
HttpJsonUtils.post(url, data -> {
data.put("theKey", company.getName());
data.put("get", true);
}, json -> {
applyEnterpriseQuery(json, company, cloudRk, results, holder);
saveJsonToFile(company, json, "fuzzy.json", holder);
}, objectMapper, getSocksProxy());
} catch (IOException ex) {
catchException(ex, holder);
}
return results;
}
private boolean applyEnterpriseQuery(JsonNode json, Company company, CloudRk cloudRk, List<CloudRkService.EntInfo> results, MessageHolder holder) {
if (!json.has("data")) {
// 没有数据
holder.error("数据异常返回的json中没有 data 字段");
return false;
}
JsonNode dataNode = json.get("data");
if (!dataNode.isArray()) {
holder.error("数据异常返回的json中 data 字段不是数组");
return false;
}
ObjectMapper objectMapper = getObjectMapper();
for (JsonNode node : dataNode) {
try {
CloudRkService.EntInfo entInfo = new CloudRkService.EntInfo();
objectMapper.updateValue(entInfo, node);
if (node.has("isNowName")) {
String s = node.get("isNowName").asText();
entInfo.setNowName(s.equals("1") || s.equals("true"));
}
results.add(entInfo);
} catch (Exception e) {
holder.error("更新企业信息失败:" + e.getMessage() + ", json=" + node.toString());
return false;
}
}
return true;
}
/**
* 更新企业工商注册信息
*/
public boolean updateEnterpriseInfo(
Company company, CloudRk cloudRk, MessageHolder holder
) throws IOException {
String api = getConfService().getString(CloudRkService.KEY_ENT_REPORT_URL);
Proxy socksProxy = getSocksProxy();
holder.debug("更新企业工商注册信息: " + company.getName() + " @ " + api + ", proxy=" + socksProxy);
AtomicBoolean modified = new AtomicBoolean(false);
try {
post(api, data -> {
data.put("entName", company.getName());
data.put("entid", cloudRk.getCloudId());
data.put("get", true);
data.put("method", "data");
data.put("nodetype", "B1001");
}, jsonNode -> {
modified.set(applyEnterpriseInfo(jsonNode, company, cloudRk, holder));
saveJsonToFile(company, jsonNode, CompanyFileUtils.FILE_B1001_JSON, holder);
});
} catch (IOException e) {
catchException(e, holder);
}
return modified.get();
}
private void catchException(IOException e, MessageHolder holder) throws IOException {
if (e instanceof SSLException) {
holder.error("网络错误:" + e.getMessage());
// 网络错误时,抛出异常,中断后续网络请求
throw e;
}
if (e instanceof SocketException) {
holder.error("网络错误:" + e.getMessage());
// 网络错误时,抛出异常,中断后续网络请求
throw e;
}
holder.error(e.getMessage());
}
private boolean applyEnterpriseInfo(JsonNode json, Company company, CloudRk cloudRk, MessageHolder holder) {
if (!json.has("B1001")) {
holder.error("数据异常返回的json中没有 B1001 字段");
return false;
}
JsonNode b1001 = json.get("B1001");
if (!b1001.has("count") || b1001.get("count").asInt() < 1 || !b1001.has("data")) {
holder.error("数据异常B1001 字段没有数据");
return false;
}
boolean modified = false;
JsonNode data = b1001.get("data");
if (updateText(company::getEntType, company::setEntType, data, "enttype", holder, "企业类型")) {
modified = true;
}
if (updateText(company::getEntStatus, company::setEntStatus, data, "entstatus", holder, "企业状态")) {
modified = true;
}
if (updateLocalDate(company::getSetupDate, company::setSetupDate, data, "esdate", holder, "成立日期")) {
modified = true;
}
if (updateText(company::getUniscid, company::setUniscid, data, "uniscid", holder, "企业状态")) {
modified = true;
}
if (updateText(company::getRegAddr, company::setRegAddr, data, "dom", holder, "注册地址")) {
modified = true;
}
if (updateText(company::getRegisteredCapital, company::setRegisteredCapital, data, "regcap", holder, "注册资金")) {
modified = true;
}
if (updateText(company::getRegisteredCapitalCurrency, company::setRegisteredCapitalCurrency, data, "regcapcur", holder, "资本金币种")) {
modified = true;
}
if (updateText(company::getLegalRepresentative, company::setLegalRepresentative, data, "frname", holder, "法人")) {
modified = true;
}
if (updateText(company::getDistrict, company::setDistrict, data, "regorgprovince", holder, "注册区域")) {
modified = true;
}
if (updateText(company::getTelephone, company::setTelephone, data, "tel", holder, "注册电话")) {
modified = true;
}
if (updateText(company::getAddress, company::setAddress, data, "oploc", holder, "通讯地址")) {
modified = true;
}
if (updateOperationPeriodBegin(company, data, holder)) {
modified = true;
}
if (updateOperationPeriodEnd(company, data, holder)) {
modified = true;
}
if (updateText(company::getIndustry, company::setIndustry, data, "nicfulltitle", holder, "行业")) {
modified = true;
}
updateCompanyNameHistory(company, data, holder.sub("曾用名"));
updateLegalRepresentativeContact(company, data, holder.sub("法人联系方式"));
updateInstant(cloudRk::getCloudEntUpdate, cloudRk::setCloudEntUpdate, data, "updated", holder, "更新时间", false);
return modified;
}
/**
* 更新法人联系人联系方式
*/
private void updateLegalRepresentativeContact(Company company, JsonNode data, MessageHolder holder) {
String legalRepresentative = company.getLegalRepresentative();
if (!StringUtils.hasText(legalRepresentative)) {
return;
}
CompanyContactService contactService = SpringApp.getBean(CompanyContactService.class);
List<CompanyContact> contactList = contactService.findAllByCompanyAndName(company, legalRepresentative);
if (contactList == null) {
// db error
return;
}
CompanyContact contact = null;
boolean modified = false;
if (contactList.isEmpty()) {
//没有,创建法人联系人
contact = new CompanyContact();
contact.setCompany(company);
contact.setName(legalRepresentative);
contact.setPosition("法定代表人");
contact.setCreated(LocalDate.now());
modified = true;
} else {
// 先尝试查找法人
Optional<CompanyContact> any = contactList.stream().filter(c -> "法定代表人".equals(c.getPosition())).findAny();
// 如果没有找到,列表中第一个联系人
if (any.isEmpty()) {
any = contactList.stream().findFirst();
}
contact = any.get();
if (updateText(contact::getPosition, contact::setPosition, "法定代表人", holder, "职位")) {
modified = true;
}
}
if (!StringUtils.hasText(contact.getEmail())) {
if (updateText(contact::getEmail, contact::setEmail, data, "email", holder, "邮箱")) {
modified = true;
}
}
if (!StringUtils.hasText(contact.getAddress())) {
if (updateText(contact::getAddress, contact::setAddress, data, "oploc", holder, "地址")) {
modified = true;
}
}
if (!StringUtils.hasText(contact.getPhone())) {
if (updateText(contact::getPhone, contact::setPhone, data, "tel", holder, "电话")) {
modified = true;
}
}
if (modified) {
contactService.save(contact);
}
}
private boolean updateOperationPeriodBegin(Company company, JsonNode data, MessageHolder holder) {
return updateLocalDate(company::getOperationPeriodBegin, company::setOperationPeriodBegin, data, "opfrom", holder, "营业期限起始日期", true);
}
private boolean updateOperationPeriodEnd(Company company, JsonNode data, MessageHolder holder) {
JsonNode node = data.get("opto");
if (node == null) {
return false;
}
String text = node.asText();
if (StringUtils.hasText(text)) {
if (text.equals("-")) {
return updateLocalDate(company::getOperationPeriodEnd, company::setOperationPeriodEnd, (LocalDate) null, holder, "营业期限截至日期", true);
}
return updateLocalDate(company::getOperationPeriodEnd, company::setOperationPeriodEnd, data, "opto", holder, "营业期限截至日期", true);
}
return false;
}
private void updateCompanyNameHistory(Company company, JsonNode data, MessageHolder holder) {
JsonNode node = data.get("nameHistory");
if (node == null) {
return;
}
// 历史曾用名
String nameHistory = node.asText();
if (!StringUtils.hasText(nameHistory)) {
return;
}
List<String> historyNames = new ArrayList<>();
for (String str : nameHistory.split(",")) {
String trimmed = str.trim();
if (StringUtils.hasText(trimmed)) {
historyNames.add(trimmed);
}
}
CompanyOldNameService service = SpringApp.getBean(CompanyOldNameService.class);
List<CompanyOldName> oldNames = service.findAllByCompany(company);
for (CompanyOldName oldName : oldNames) {
// 已经存在的移除
historyNames.remove(oldName.getName());
}
for (String historyName : historyNames) {
CompanyOldName oldName = service.createNew(company, historyName, false);
oldName.setMemo("从相关方平台导入");
service.save(oldName);
}
}
private boolean updateLocalDate(Supplier<LocalDate> getter, Consumer<LocalDate> setter, JsonNode data, String field, MessageHolder holder, String topic, boolean allowNull) {
JsonNode node = data.get(field);
if (node == null || node.isNull()) {
return false;
}
LocalDate localDate = getObjectMapper().convertValue(node, LocalDate.class);
if (localDate == null && !allowNull) {
return false;
}
return updateLocalDate(getter, setter, localDate, holder, topic, allowNull);
}
private boolean updateLocalDate(Supplier<LocalDate> getter, Consumer<LocalDate> setter, JsonNode data, String field, MessageHolder holder, String topic) {
return updateLocalDate(getter, setter, data, field, holder, topic, false);
}
private void updateInstant(Supplier<Instant> getter, Consumer<Instant> setter, JsonNode data, String field, MessageHolder holder, String topic, boolean allowNull) {
JsonNode node = data.get("updated");
if (node == null) {
return;
}
LocalDateTime updated = getObjectMapper().convertValue(node, LocalDateTime.class);
if (updated == null) {
if (!allowNull) {
return;
}
updateInstant(getter, setter, null, holder, topic);
return;
}
Instant instant = updated.toInstant(ZoneOffset.ofHours(8));
updateInstant(getter, setter, instant, holder, topic);
}
private boolean updateText(Supplier<String> getter, Consumer<String> setter, JsonNode data, String field, MessageHolder holder, String topic) {
JsonNode node = data.get(field);
if (node == null || node.isNull()) {
return false;
}
String text = node.asText();
if (!StringUtils.hasText(text)) {
return false;
}
return updateText(getter, setter, text, holder, topic);
}
private void saveJsonToFile(Company company, JsonNode json, String fileName, MessageHolder holder) {
String companyPath = company.getPath();
if (!StringUtils.hasText(companyPath)) {
return;
}
File dir = new File(companyPath);
if (!dir.exists()) {
return;
}
File file = new File(dir, fileName);
try {
getObjectMapper().writeValue(file, json);
holder.debug("保存文件 " + file.getName());
} catch (IOException e) {
holder.error("保存文件 " + file.getName() + " 发生错误:" + e.getMessage());
logger.error("Save {}", file.getAbsolutePath(), e);
}
}
public CloudRk getOrCreateCloudRk(Company company) {
return getCloudRkService().getOrCreateCloudRk(company);
}
public CloudRk save(CloudRk cloudRk) {
return getCloudRkService().save(cloudRk);
}
}

View File

@@ -0,0 +1,28 @@
package com.ecep.contract.manager.cloud.tyc;
import com.ecep.contract.manager.cloud.CloudBaseInfo;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.ColumnDefault;
import java.time.Instant;
@Getter
@Setter
@Entity
@Table(name = "CLOUD_TYC", schema = "supplier_ms")
public class CloudTyc extends CloudBaseInfo {
@ColumnDefault("0")
@Column(name = "SCORE", nullable = false)
private Integer score;
@Column(name = "CLOUD_LATEST")
private Instant cloudLatest;
}

View File

@@ -0,0 +1,77 @@
package com.ecep.contract.manager.cloud.tyc;
import com.ecep.contract.manager.cloud.CloudInfoViewModel;
import com.ecep.contract.manager.ui.util.MyDateTimePropertyUtils;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Objects;
@Data
@EqualsAndHashCode(callSuper = false)
public class CloudTycInfoViewModel extends CloudInfoViewModel<CloudTyc> {
private SimpleIntegerProperty score = new SimpleIntegerProperty();
private SimpleObjectProperty<LocalDateTime> cloudLatest = new SimpleObjectProperty<>();
@Override
protected void updateFrom(CloudTyc info) {
super.updateFrom(info);
update_((CloudTyc) info);
}
private void update_(CloudTyc info) {
score.set(info.getScore());
if (info.getCloudLatest() != null) {
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime zonedDateTime = info.getCloudLatest().atZone(zone);
LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
cloudLatest.set(localDateTime);
} else {
cloudLatest.set(null);
}
}
@Override
public boolean copyTo(CloudTyc info) {
boolean modified = super.copyTo(info);
if (copyTo_((CloudTyc) info)) {
modified = true;
}
return modified;
}
private boolean copyTo_(CloudTyc info) {
boolean modified = super.copyTo(info);
if (!Objects.equals(info.getId(), getId().get())) {
info.setId(getId().get());
modified = true;
}
if (!Objects.equals(info.getScore(), getScore().get())) {
info.setScore(getScore().get());
modified = true;
}
Instant latest = MyDateTimePropertyUtils.localDateTimeToInstant(cloudLatest);
if (!Objects.equals(info.getCloudLatest(), latest)) {
info.setCloudLatest(latest);
modified = true;
}
return modified;
}
public static CloudTycInfoViewModel from(CloudTyc cc) {
CloudTycInfoViewModel model = new CloudTycInfoViewModel();
model.update(cc);
return model;
}
}

View File

@@ -0,0 +1,134 @@
package com.ecep.contract.manager.cloud.tyc;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.company.controller.CompanyTableCell;
import com.ecep.contract.manager.ds.company.controller.CompanyWindowController;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ui.AbstEntityManagerSkin;
import com.ecep.contract.manager.ui.ManagerSkin;
import com.ecep.contract.manager.ui.util.LocalDateTimeTableCell;
import jakarta.persistence.criteria.Path;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import lombok.Setter;
import org.hibernate.Hibernate;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;
import java.util.List;
public class CloudTycManagerSkin
extends AbstEntityManagerSkin<CloudTyc, CloudTycInfoViewModel, CloudTycManagerSkin, CloudTycManagerWindowController>
implements ManagerSkin {
@Setter
private CloudTycService cloudTycService;
@Setter
private CompanyService companyService;
public CloudTycManagerSkin(CloudTycManagerWindowController controller) {
super(controller);
}
CloudTycService getCloudTycService() {
if (cloudTycService == null) {
cloudTycService = getBean(CloudTycService.class);
}
return cloudTycService;
}
CompanyService getCompanyService() {
if (companyService == null) {
companyService = SpringApp.getBean(CompanyService.class);
}
return companyService;
}
@Override
protected List<CloudTycInfoViewModel> loadTableData() {
String searchText = controller.searchKeyField.getText();
Specification<CloudTyc> spec = null;
if (StringUtils.hasText(searchText)) {
Specification<CloudTyc> companySpec = (root, query, builder) -> {
Path<Object> company = root.get("company");
return builder.or(
builder.like(company.get("name"), "%" + searchText + "%"),
builder.like(company.get("shortName"), "%" + searchText + "%")
);
};
Specification<CloudTyc> cloudIdSpec = (root, query, builder) -> {
return builder.like(root.get("cloudId"), "%" + searchText + "%");
};
spec = Specification.anyOf(companySpec, cloudIdSpec);
}
Page<CloudTyc> page = getCloudTycService().findAll(spec, getPageable());
updateFooter(page);
return page.map(CloudTycInfoViewModel::from).toList();
}
@Override
public void initializeTable() {
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
controller.companyColumn.setCellValueFactory(param -> param.getValue().getCompany());
controller.companyColumn.setCellFactory(param -> new CompanyTableCell<>(getCompanyService()));
controller.cloudIdColumn.setCellValueFactory(param -> param.getValue().getCloudId());
controller.latestUpdateColumn.setCellValueFactory(param -> param.getValue().getLatest());
controller.latestUpdateColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
controller.cloudLatestColumn.setCellValueFactory(param -> param.getValue().getCloudLatest());
controller.cloudLatestColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
controller.scoreColumn.setCellValueFactory(param -> param.getValue().getScore());
}
@Override
protected void createContextMenu(ContextMenu contextMenu) {
MenuItem item2 = new MenuItem("刷新");
item2.setOnAction(this::onTableRefreshAction);
MenuItem item3 = new MenuItem("清空备注");
item3.setOnAction(this::onTableClearDescriptionAction);
contextMenu.getItems().addAll(item2, item3);
}
/**
* 请空选择行的注释
*
* @param event event
*/
public void onTableClearDescriptionAction(ActionEvent event) {
ObservableList<CloudTycInfoViewModel> selectedItems = getTableView().getSelectionModel().getSelectedItems();
if (selectedItems.isEmpty()) {
return;
}
for (CloudTycInfoViewModel selectedItem : selectedItems) {
CloudTyc cloudTyc = getCloudTycService().findById(selectedItem.getId().get());
// selectedItem.getDescription().set("");
if (selectedItem.copyTo(cloudTyc)) {
CloudTyc saved = getCloudTycService().save(cloudTyc);
selectedItem.update(saved);
}
}
}
@Override
protected void onTableRowDoubleClickedAction(CloudTycInfoViewModel item) {
Company company = item.getCompany().get();
if (!Hibernate.isInitialized(item)) {
company = getCompanyService().findById(company.getId());
}
CompanyWindowController.show(company, getTableView().getScene().getWindow());
}
}

View File

@@ -0,0 +1,126 @@
package com.ecep.contract.manager.cloud.tyc;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.CloudBaseInfo;
import com.ecep.contract.manager.cloud.CloudInfo;
import com.ecep.contract.manager.ds.company.controller.CompanyWindowController;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ui.AbstManagerWindowController;
import com.ecep.contract.manager.ui.FxmlPath;
import com.ecep.contract.manager.ui.ViewModelService;
import com.ecep.contract.manager.ui.util.DelayOnceExecutor;
import com.ecep.contract.manager.ui.util.LocalDateTimeTableCell;
import com.ecep.contract.manager.util.TableViewUtils;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import static com.ecep.contract.manager.util.TableViewUtils.getTableViewVisibleRows;
/**
* 天眼查信息管理窗口控制器
*/
@Lazy
@Scope("prototype")
@Component
@FxmlPath("/ui/cloud/tyc_manager.fxml")
public class CloudTycManagerWindowController
extends AbstManagerWindowController<CloudTyc, CloudTycInfoViewModel, CloudTycManagerSkin> {
public static void show() {
show(CloudTycManagerWindowController.class, null);
}
@Autowired
private CloudTycService cloudTycService;
@Autowired
private CompanyService companyService;
public TableColumn<CloudTycInfoViewModel, Number> idColumn;
public TableColumn<CloudTycInfoViewModel, LocalDateTime> latestUpdateColumn;
public TableColumn<CloudTycInfoViewModel, Company> companyColumn;
public TableColumn<CloudTycInfoViewModel, String> cloudIdColumn;
public TableColumn<CloudTycInfoViewModel, LocalDateTime> cloudLatestColumn;
public TableColumn<CloudTycInfoViewModel, Number> scoreColumn;
public TableColumn<CloudTycInfoViewModel, String> descriptionColumn;
@Override
public CloudTycService getViewModelService() {
return cloudTycService;
}
@Override
protected CloudTycManagerSkin createDefaultSkin() {
return new CloudTycManagerSkin(this);
}
@Override
public void show(Stage stage) {
super.show(stage);getTitle().set("数据源:天眼查");
}
/**
* 数据迁移,从 CloudInfo 迁移到 CloudRk
*/
public void onDateTransferAction(ActionEvent event) {
CompletableFuture.runAsync(() -> {
com.ecep.contract.manager.cloud.CloudInfoRepository cloudInfoRepository = SpringApp.getBean(com.ecep.contract.manager.cloud.CloudInfoRepository.class);
cloudInfoRepository.findAll().forEach(v -> {
try {
CloudTyc cloudTyc = cloudTycService.getOrCreateCloudTyc(v);
if (copyTo(v, cloudTyc)) {
cloudTycService.save(cloudTyc);
}
} catch (Exception e) {
e.printStackTrace();
}
});
});
}
boolean copyTo(CloudInfo v, CloudBaseInfo cloudRk) {
boolean modified = false;
if (!Objects.equals(cloudRk.getLatestUpdate(), v.getLatestUpdate())) {
cloudRk.setLatestUpdate(v.getLatestUpdate());
modified = true;
}
if (!Objects.equals(cloudRk.getCloudId(), v.getCloudId())) {
cloudRk.setCloudId(v.getCloudId());
modified = true;
}
if (!Objects.equals(cloudRk.getCompany(), v.getCompany())) {
cloudRk.setCompany(v.getCompany());
modified = true;
}
return modified;
}
}

View File

@@ -0,0 +1,31 @@
package com.ecep.contract.manager.cloud.tyc;
import com.ecep.contract.manager.ds.company.model.Company;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
@Repository
public interface CloudTycRepository
// curd
extends CrudRepository<CloudTyc, Integer>, PagingAndSortingRepository<CloudTyc, Integer>,
// JPA interfaces
JpaRepository<CloudTyc, Integer>, JpaSpecificationExecutor<CloudTyc> {
List<CloudTyc> findAllByCompanyId(Integer companyId);
Optional<CloudTyc> findByCompanyId(Integer companyId);
@Modifying
@Transactional
int deleteAllByCompany(Company company);
}

View File

@@ -0,0 +1,210 @@
package com.ecep.contract.manager.cloud.tyc;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.CloudInfo;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.other.repository.SysConfRepository;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.ViewModelService;
import com.ecep.contract.manager.util.MyStringUtils;
import com.ecep.contract.manager.util.UITools;
import javafx.application.Platform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Lazy
@Service
public class CloudTycService implements ViewModelService<CloudTyc, CloudTycInfoViewModel> {
public static final String NAME = "天眼查";
public final static String TYC_ENTERPRISE_ANALYSIS_REPORT = "企业分析报告";
public final static String TYC_ENTERPRISE_BASIC_REPORT = "基础版企业信用报告";
public final static String TYC_ENTERPRISE_MAJOR_REPORT = "专业版企业信用报告";
public final static String TYC_ENTERPRISE_CREDIT_REPORT = "企业信用信息公示报告";
public static final String URL_COMPANY = "https://www.tianyancha.com/company/%s";
public static final String URL_COMPANY_SEARCH = "https://www.tianyancha.com/search?key=%s";
private static final Logger logger = LoggerFactory.getLogger(CloudTycService.class);
/**
* 天眼查报告,文件名中必须包含 天眼查 字样
*
* @param fileName 文件名
* @return 是否是天眼查报告
*/
public static boolean isTycReport(String fileName) {
// 文件名中包含 天眼查 字样
return fileName.contains(CloudTycService.NAME);
}
@Autowired
private CloudTycRepository cloudTycRepository;
public CloudTyc getOrCreateCloudTyc(CloudInfo info) {
Optional<CloudTyc> optional = cloudTycRepository.findById(info.getId());
return optional.orElseGet(() -> getOrCreateCloudTyc(info.getCompany()));
}
public CloudTyc getOrCreateCloudTyc(Company company) {
Integer companyId = company.getId();
List<CloudTyc> list = cloudTycRepository.findAllByCompanyId(companyId);
if (list.isEmpty()) {
CloudTyc tyc = new CloudTyc();
tyc.setCompany(company);
tyc.setScore(-1);
tyc.setCloudLatest(null);
return cloudTycRepository.save(tyc);
}
if (list.size() == 1) {
return list.getFirst();
}
// 查询有 CloudId 的记录
List<CloudTyc> hasCouldIdList = list.stream()
.filter(v -> {
return StringUtils.hasText(v.getCloudId())
&& MyStringUtils.isAllDigit(v.getCloudId());
})
.collect(Collectors.toList());
// 没有匹配到一条时
if (hasCouldIdList.isEmpty()) {
// 保留第一条,其他删除
CloudTyc rk = list.removeFirst();
cloudTycRepository.deleteAll(list);
return rk;
}
// 只有匹配到一条有 CloudId 的记录
if (hasCouldIdList.size() == 1) {
// 保留匹配的记录,其他删除
CloudTyc rk = hasCouldIdList.removeFirst();
list.remove(rk);
cloudTycRepository.deleteAll(list);
return rk;
}
// 查询有 Score 的记录
List<CloudTyc> hasLatestList = hasCouldIdList.stream().filter(v -> {
return v.getScore() != null && v.getScore() > 0;
}).collect(Collectors.toList());
// 没有匹配到一条时
if (hasLatestList.isEmpty()) {
// 保留第一条,其他删除
CloudTyc rk = hasCouldIdList.removeFirst();
list.remove(rk);
cloudTycRepository.deleteAll(list);
return rk;
}
// 只有匹配到一条有 CloudId 的记录
if (hasLatestList.size() == 1) {
// 保留匹配的记录,其他删除
CloudTyc rk = hasLatestList.removeFirst();
list.remove(rk);
cloudTycRepository.deleteAll(list);
return rk;
}
return hasLatestList.getFirst();
}
public CloudTyc save(CloudTyc cloudTyc) {
return cloudTycRepository.save(cloudTyc);
}
@Override
public void delete(CloudTyc entity) {
cloudTycRepository.delete(entity);
}
public void save(CloudTycInfoViewModel viewModel) {
int infoId = viewModel.getId().get();
CloudTyc cloudTyc = cloudTycRepository.findById(infoId).orElse(null);
if (cloudTyc == null) {
return;
}
if (viewModel.copyTo(cloudTyc)) {
cloudTyc.setLatestUpdate(Instant.now());
CloudTyc saved = cloudTycRepository.save(cloudTyc);
Platform.runLater(() -> viewModel.update(saved));
}
}
public void showInBrowse(String cloudId) {
String baseUrl = SpringApp.getBean(SysConfRepository.class).get("cloud.tyc.company");
if (!StringUtils.hasText(baseUrl)) {
UITools.showAlertAndWait("系统参数 cloud.tyc.company 未配置");
return;
}
String url = baseUrl + cloudId;
com.ecep.contract.manager.Desktop.showInBrowse(url);
// UITools.showExceptionAndWait("使用浏览器打开网址出现异常", e);
}
public void deleteByCompany(Company company) {
int deleted = cloudTycRepository.deleteAllByCompany(company);
if (deleted > 0) {
if (logger.isInfoEnabled()) {
logger.info("Delete {} records by company:#{}", deleted, company.getId());
}
}
}
public void resetTo(Company from, Company to) {
List<CloudTyc> list = cloudTycRepository.findAllByCompanyId(from.getId());
for (CloudTyc item : list) {
item.setCompany(to);
}
cloudTycRepository.saveAll(list);
}
public CloudTyc findById(Integer id) {
return cloudTycRepository.findById(id).orElse(null);
}
public Page<CloudTyc> findAll(Specification<CloudTyc> spec, PageRequest pageable) {
return cloudTycRepository.findAll(spec, pageable);
}
public Page<CloudTyc> findAll(Specification<CloudTyc> spec, Pageable pageable) {
return cloudTycRepository.findAll(spec, pageable);
}
@Override
public Specification<CloudTyc> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
return builder.like(root.get("cloudId"), "%" + searchText + "%");
};
}
// TODO
public void syncCompany(Company company, MessageHolder holder) {
holder.warn("TODO 未实现");
}
}

View File

@@ -0,0 +1,42 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.cloud.CloudBaseInfo;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.annotations.ColumnDefault;
import java.time.Instant;
import java.time.LocalDate;
@Getter
@Setter
@Entity
@Table(name = "CLOUD_YU", schema = "supplier_ms")
@ToString
public class CloudYu extends CloudBaseInfo {
@ColumnDefault("''")
@Column(name = "EX_MSG")
private String exceptionMessage;
/**
* 供应商信息更新日期
*/
@Column(name = "VEN_UP_DATE")
private LocalDate vendorUpdateDate;
/**
* 客户信息更新日期
*/
@Column(name = "CUS_UP_DATE")
private LocalDate customerUpdateDate;
/**
* 数据更新日期
*/
@Column(name = "CLOUD_LATEST")
private Instant cloudLatest;
}

View File

@@ -0,0 +1,86 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.cloud.CloudInfoViewModel;
import com.ecep.contract.manager.ui.util.MyDateTimePropertyUtils;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.*;
import java.util.Objects;
@Data
@EqualsAndHashCode(callSuper = false)
public class CloudYuInfoViewModel extends CloudInfoViewModel<CloudYu> {
private SimpleStringProperty vendorCode = new SimpleStringProperty();
private SimpleStringProperty vendorClassCode = new SimpleStringProperty();
private SimpleObjectProperty<LocalDate> vendorDevelopDate = new SimpleObjectProperty<>();
private SimpleStringProperty customerCode = new SimpleStringProperty();
private SimpleStringProperty customerClassCode = new SimpleStringProperty();
private SimpleObjectProperty<LocalDate> customerDevelopDate = new SimpleObjectProperty<>();
private SimpleObjectProperty<LocalDateTime> cloudLatest = new SimpleObjectProperty<>();
@Override
protected void updateFrom(CloudYu info) {
super.updateFrom(info);
update_((CloudYu) info);
}
private void update_(CloudYu info) {
vendorCode.set(info.getExceptionMessage());
vendorDevelopDate.set(info.getVendorUpdateDate());
customerDevelopDate.set(info.getCustomerUpdateDate());
if (info.getCloudLatest() != null) {
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime zonedDateTime = info.getCloudLatest().atZone(zone);
LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
cloudLatest.set(localDateTime);
} else {
cloudLatest.set(null);
}
}
@Override
public boolean copyTo(CloudYu info) {
boolean modified = super.copyTo(info);
if (copyTo_((CloudYu) info)) {
modified = true;
}
return modified;
}
private boolean copyTo_(CloudYu info) {
boolean modified = false;
if (!Objects.equals(info.getExceptionMessage(), vendorCode.get())) {
info.setExceptionMessage(vendorCode.get());
modified = true;
}
if (!Objects.equals(info.getVendorUpdateDate(), vendorDevelopDate.get())) {
info.setVendorUpdateDate(vendorDevelopDate.get());
modified = true;
}
if (!Objects.equals(info.getCustomerUpdateDate(), customerDevelopDate.get())) {
info.setCustomerUpdateDate(customerDevelopDate.get());
modified = true;
}
Instant latest = MyDateTimePropertyUtils.localDateTimeToInstant(cloudLatest);
if (!Objects.equals(info.getCloudLatest(), latest)) {
info.setCloudLatest(latest);
modified = true;
}
return modified;
}
public static CloudYuInfoViewModel from(CloudYu cc) {
CloudYuInfoViewModel model = new CloudYuInfoViewModel();
model.update(cc);
return model;
}
}

View File

@@ -0,0 +1,31 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.ds.company.model.Company;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
@Repository
public interface CloudYuRepository
// curd
extends CrudRepository<CloudYu, Integer>, PagingAndSortingRepository<CloudYu, Integer>,
// JPA interfaces
JpaRepository<CloudYu, Integer>, JpaSpecificationExecutor<CloudYu> {
List<CloudYu> findAllByCompanyId(Integer companyId);
Optional<CloudYu> findByCompanyId(Integer companyId);
@Modifying
@Transactional
int deleteAllByCompany(Company company);
}

View File

@@ -0,0 +1,102 @@
package com.ecep.contract.manager.cloud.u8;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.contract.model.ContractGroup;
import com.ecep.contract.manager.ds.contract.service.ContractGroupService;
import javafx.concurrent.Task;
import lombok.Setter;
/**
* 同步合同分组
*/
public class ContractGroupSyncTask extends Task<Object> {
private static final Logger logger = LoggerFactory.getLogger(ContractGroupSyncTask.class);
@Setter
private ContractGroupService contractGroupService;
public ContractGroupSyncTask() {
updateTitle("用友U8系统-同步合同分组信息");
}
ContractGroupService getContractGroupService() {
if (contractGroupService == null) {
contractGroupService = SpringApp.getBean(ContractGroupService.class);
}
return contractGroupService;
}
@Override
protected Object call() throws Exception {
YongYouU8Repository repository = null;
try {
repository = SpringApp.getBean(YongYouU8Repository.class);
} catch (BeansException e) {
logger.error("can't get bean of YongYouU8Repository", e);
return null;
}
AtomicInteger counter = new AtomicInteger(0);
updateMessage("读取 U8 系统 CM_Group 数据表...");
List<Map<String, Object>> list = repository.queryAllContractGroup();
int size = list.size();
updateMessage("总共读取 CM_Group 数据 " + size + "");
for (Map<String, Object> map : list) {
if (isCancelled()) {
updateMessage("Cancelled");
return null;
}
sync(map, msg -> {
updateMessage(counter.get() + "/" + size + ">" + msg);
});
// 更新进度
updateProgress(counter.incrementAndGet(), size);
}
return null;
}
private void sync(Map<String, Object> map, Consumer<String> consumer) {
boolean modified = false;
String groupCode = (String) map.get("cGroupID");
String groupName = (String) map.get("cGroupName");
String groupTitle = (String) map.get("cRemark");
ContractGroupService service = getContractGroupService();
ContractGroup contractGroup = service.findByCode(groupCode);
if (contractGroup == null) {
contractGroup = service.newContractGroup();
consumer.accept("新建合同分组:" + groupCode);
modified = true;
}
if (!Objects.equals(contractGroup.getCode(), groupCode)) {
contractGroup.setCode(groupCode);
modified = true;
}
if (!Objects.equals(contractGroup.getName(), groupName)) {
contractGroup.setName(groupName);
modified = true;
}
if (!Objects.equals(contractGroup.getTitle(), groupTitle)) {
contractGroup.setTitle(groupTitle);
modified = true;
}
if (modified) {
service.save(contractGroup);
consumer.accept("更新" + contractGroup.getName() + " 信息");
}
}
}

View File

@@ -0,0 +1,102 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.contract.model.ContractKind;
import com.ecep.contract.manager.ds.contract.service.ContractKindService;
import javafx.concurrent.Task;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import org.springframework.beans.BeansException;
/**
* 同步合同分类
*/
public class ContractKindSyncTask extends Task<Object> {
private static final Logger logger = LoggerFactory.getLogger(ContractKindSyncTask.class);
@Setter
private ContractKindService contractKindService;
public ContractKindSyncTask() {
updateTitle("用友U8系统-同步合同分类信息");
}
ContractKindService getContractKindService() {
if (contractKindService == null) {
contractKindService = SpringApp.getBean(ContractKindService.class);
}
return contractKindService;
}
@Override
protected Object call() throws Exception {
YongYouU8Repository repository = null;
try {
repository = SpringApp.getBean(YongYouU8Repository.class);
} catch (BeansException e) {
logger.error("can't get bean of YongYouU8Repository", e);
return null;
}
AtomicInteger counter = new AtomicInteger(0);
updateMessage("读取 U8 系统 CM_Kind 数据表...");
List<Map<String, Object>> list = repository.queryAllContractKind();
int size = list.size();
updateMessage("总共读取 CM_Kind 数据 " + size + "");
for (Map<String, Object> map : list) {
if (isCancelled()) {
updateMessage("Cancelled");
return null;
}
sync(map, msg -> {
updateMessage(counter.get() + "/" + size + ">" + msg);
});
// 更新进度
updateProgress(counter.incrementAndGet(), size);
}
return null;
}
private void sync(Map<String, Object> map, Consumer<String> consumer) {
boolean modified = false;
String typeCode = (String) map.get("KindID");
String typeName = (String) map.get("KindName");
String typeTitle = (String) map.get("Description");
ContractKindService kindService = getContractKindService();
ContractKind contractKind = kindService.findByCode(typeCode);
if (contractKind == null) {
contractKind = new ContractKind();
consumer.accept("新建合同分类:" + typeCode);
modified = true;
}
if (!Objects.equals(contractKind.getCode(), typeCode)) {
contractKind.setCode(typeCode);
modified = true;
}
if (!Objects.equals(contractKind.getName(), typeName)) {
contractKind.setName(typeName);
modified = true;
}
if (!Objects.equals(contractKind.getTitle(), typeTitle)) {
contractKind.setTitle(typeTitle);
modified = true;
}
if (modified) {
kindService.save(contractKind);
consumer.accept("更新" + contractKind.getName() + " 信息");
}
}
}

View File

@@ -0,0 +1,49 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.ds.contract.model.Contract;
import com.ecep.contract.manager.ds.contract.service.ContractService;
import com.ecep.contract.manager.ds.contract.tasker.AbstContractRepairTasker;
import com.ecep.contract.manager.ui.MessageHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
/**
* 用友U8系统-同步全量合同
*/
public class ContractSyncAllTask extends AbstContractRepairTasker {
private static final Logger logger = LoggerFactory.getLogger(ContractSyncAllTask.class);
@Override
protected void repair(MessageHolder holder) {
updateTitle("用友U8系统-同步全量合同");
YongYouU8Repository repository = getBean(YongYouU8Repository.class);
long total = repository.countAllContracts();
AtomicInteger counter = new AtomicInteger(0);
try (Stream<Map<String, Object>> stream = repository.queryAllContractForStream()) {
stream.forEach(rs -> {
if (isCancelled()) {
holder.debug("Cancelled");
return;
}
MessageHolder subHolder = holder.sub(counter.get() + " / " + total + "> ");
try {
repairFromCMList(rs, subHolder);
} catch (Exception e) {
updateMessage(e.getMessage());
logger.error("data = {}", rs, e);
}
updateProgress(counter.incrementAndGet(), total);
});
}
}
}

View File

@@ -0,0 +1,92 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.contract.model.ContractGroup;
import com.ecep.contract.manager.ds.contract.model.ContractKind;
import com.ecep.contract.manager.ds.contract.model.ContractType;
import com.ecep.contract.manager.ds.contract.service.ContractGroupService;
import com.ecep.contract.manager.ds.contract.service.ContractKindService;
import com.ecep.contract.manager.ds.contract.service.ContractTypeService;
import com.ecep.contract.manager.ds.other.model.Employee;
import com.ecep.contract.manager.ds.other.service.EmployeeService;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.BeansException;
import java.util.function.Consumer;
public class ContractSyncContext {
<T> T getBean(Class<T> requiredType) throws BeansException {
return SpringApp.getBean(requiredType);
}
private ContractTypeService contractTypeService;
private ContractGroupService contractGroupService;
private ContractKindService contractKindService;
private EmployeeService employeeService;
@Getter
@Setter
Consumer<String> consumer;
public ContractSyncContext() {
}
private ContractTypeService getContractTypeService() {
if (contractTypeService == null) {
contractTypeService = getBean(ContractTypeService.class);
}
return contractTypeService;
}
private ContractGroupService getContractGroupService() {
if (contractGroupService == null) {
contractGroupService = getBean(ContractGroupService.class);
}
return contractGroupService;
}
private ContractKindService getContractKindService() {
if (contractKindService == null) {
contractKindService = getBean(ContractKindService.class);
}
return contractKindService;
}
private EmployeeService getEmployeeService() {
if (employeeService == null) {
employeeService = getBean(EmployeeService.class);
}
return employeeService;
}
public ContractType getTypeByCode(String typeCode) {
return getContractTypeService().findByCode(typeCode);
}
public ContractGroup getGroupByCode(String groupCode) {
return getContractGroupService().findByCode(groupCode);
}
public ContractKind getKindByName(String kindName) {
return getContractKindService().findByName(kindName);
}
public void updateMessage(String message) {
Consumer<String> consumer = getConsumer();
if (consumer != null) {
consumer.accept(message);
}
}
public Employee findEmployeeByCode(String personCode) {
return getEmployeeService().findByCode(personCode);
}
public Employee findEmployeeByName(String personName) {
if (personName == null) {
return null;
}
return getEmployeeService().findByName(personName);
}
}

View File

@@ -0,0 +1,136 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.contract.service.ContractService;
import com.ecep.contract.manager.ds.contract.tasker.AbstContractRepairTasker;
import com.ecep.contract.manager.ui.MessageHolder;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
/**
* 合同同步任务
*/
public class ContractSyncTask extends AbstContractRepairTasker {
private static final Logger logger = LoggerFactory.getLogger(ContractSyncTask.class);
@Setter
private boolean useLatestId = true;
private YongYouU8Repository repository;
public ContractSyncTask() {
updateTitle("用友U8系统-同步合同");
}
private void syncByLatestId(MessageHolder holder) {
int latestId = getConfService().getInt(ContractService.CONTRACT_LATEST_ID);
updateTitle("用友U8系统-同步合同,从 " + latestId + " 开始");
Long total = repository.countAllContracts(latestId);
updateTitle("用友U8系统-同步合同,从 " + latestId + " 开始,合计 " + total + "");
if (logger.isDebugEnabled()) {
logger.debug("sync latest Id from {}, have {} record.", latestId, total);
}
AtomicInteger counter = new AtomicInteger(0);
AtomicReference<Integer> reference = new AtomicReference<>(latestId);
try (Stream<Map<String, Object>> stream = repository.queryAllContractForStream(latestId)) {
stream.forEach(rs -> {
if (isCancelled()) {
updateMessage("Cancelled");
return;
}
MessageHolder subHolder = holder.sub(counter.get() + " / " + total + "> ");
try {
Integer ID = (Integer) rs.get("ID");
repairFromCMList(rs, subHolder);
if (ID != null) {
Integer latest = reference.get();
if (latest == null || ID.compareTo(latest) > 0) {
reference.set(ID);
}
}
} catch (Exception e) {
logger.error("Contract sync failure {}, data = {}", e.getMessage(), rs, e);
updateMessage(e.getMessage());
throw e;
}
updateProgress(counter.incrementAndGet(), total);
});
}
getConfService().set(ContractService.CONTRACT_LATEST_ID, String.valueOf(reference.get()));
}
private void syncByLatestDate(MessageHolder holder) {
String strDateTime = getConfService().getString(ContractService.CONTRACT_LATEST_DATE);
LocalDateTime latestDateTime = null;
if (StringUtils.hasText(strDateTime)) {
try {
latestDateTime = LocalDateTime.parse(strDateTime);
} catch (Exception ignored) {
}
}
if (latestDateTime == null) {
latestDateTime = LocalDateTime.of(2025, 1, 1, 0, 0, 0);
}
updateTitle("用友U8系统-同步合同,从 " + latestDateTime + " 开始");
Long total = repository.countAllContracts(latestDateTime);
updateTitle("用友U8系统-同步合同,从 " + latestDateTime + " 开始,合计 " + total + "");
if (logger.isDebugEnabled()) {
logger.debug("from latest date {}, have {} record.", latestDateTime, total);
}
AtomicInteger counter = new AtomicInteger(0);
AtomicReference<LocalDateTime> reference = new AtomicReference<>(latestDateTime);
try (Stream<Map<String, Object>> stream = repository.queryAllContractForStream(latestDateTime)) {
stream.forEach(rs -> {
if (isCancelled()) {
updateMessage("Cancelled");
return;
}
MessageHolder subHolder = holder.sub(counter.get() + " / " + total + "> ");
try {
Timestamp dtDate = (Timestamp) rs.get("dtDate");
repairFromCMList(rs, subHolder);
if (dtDate != null) {
LocalDateTime latest = reference.get();
LocalDateTime localDate = dtDate.toLocalDateTime();
if (latest == null || localDate.isAfter(latest)) {
reference.set(localDate);
}
}
} catch (Exception e) {
logger.error("Contract sync failure {}, data = {}", e.getMessage(), rs, e);
updateMessage(e.getMessage());
throw e;
}
updateProgress(counter.incrementAndGet(), total);
});
}
getConfService().set(ContractService.CONTRACT_LATEST_DATE, String.valueOf(reference.get()));
}
@Override
protected void repair(MessageHolder holder) {
updateTitle("用友U8系统-同步合同");
repository = SpringApp.getBean(YongYouU8Repository.class);
if (useLatestId) {
syncByLatestId(holder);
} else {
syncByLatestDate(holder);
}
}
}

View File

@@ -0,0 +1,112 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.contract.model.ContractType;
import com.ecep.contract.manager.ds.contract.service.ContractTypeService;
import javafx.concurrent.Task;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import org.springframework.beans.BeansException;
/**
* 同步合同类型
*/
public class ContractTypeSyncTask extends Task<Object> {
private static final Logger logger = LoggerFactory.getLogger(ContractTypeSyncTask.class);
@Setter
private ContractTypeService contractTypeService;
public ContractTypeSyncTask() {
updateTitle("用友U8系统-同步合同类型信息");
}
ContractTypeService getContractTypeService() {
if (contractTypeService == null) {
contractTypeService = SpringApp.getBean(ContractTypeService.class);
}
return contractTypeService;
}
@Override
protected Object call() throws Exception {
YongYouU8Repository repository = null;
try {
repository = SpringApp.getBean(YongYouU8Repository.class);
} catch (BeansException e) {
logger.error("can't get bean of YongYouU8Repository", e);
return null;
}
AtomicInteger counter = new AtomicInteger(0);
updateMessage("读取 U8 系统 CM_Type,CM_TypeClass 数据表...");
List<Map<String, Object>> list = repository.queryAllContractType();
int size = list.size();
updateMessage("总共读取 CM_Type,CM_TypeClass 数据 " + size + "");
for (Map<String, Object> map : list) {
if (isCancelled()) {
updateMessage("Cancelled");
return null;
}
sync(map, msg -> {
updateMessage(counter.get() + "/" + size + ">" + msg);
});
// 更新进度
updateProgress(counter.incrementAndGet(), size);
}
return null;
}
private void sync(Map<String, Object> map, Consumer<String> consumer) {
boolean modified = false;
String typeCode = (String) map.get("cTypeCode");
String typeName = (String) map.get("cTypeName");
String typeTitle = (String) map.get("cCharacter");
String typeCatalog = (String) map.get("cClassName");
String typeDirection = (String) map.get("cDirection");
ContractTypeService typeService = getContractTypeService();
ContractType contractType = typeService.findByCode(typeCode);
if (contractType == null) {
contractType = new ContractType();
consumer.accept("新建合同类型:" + typeCode);
modified = true;
}
if (!Objects.equals(contractType.getCode(), typeCode)) {
contractType.setCode(typeCode);
modified = true;
}
if (!Objects.equals(contractType.getName(), typeName)) {
contractType.setName(typeName);
modified = true;
}
if (!Objects.equals(contractType.getTitle(), typeTitle)) {
contractType.setTitle(typeTitle);
modified = true;
}
if (!Objects.equals(contractType.getCatalog(), typeCatalog)) {
contractType.setTitle(typeTitle);
modified = true;
}
if (!Objects.equals(contractType.getDirection(), typeDirection)) {
contractType.setTitle(typeTitle);
modified = true;
}
if (modified) {
typeService.save(contractType);
consumer.accept("更新" + contractType.getName() + " 信息");
}
}
}

View File

@@ -0,0 +1,70 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.customer.model.CustomerCatalog;
import com.ecep.contract.manager.ds.customer.service.CompanyCustomerService;
import javafx.concurrent.Task;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 同步客户分类
*/
public class CustomerClassSyncTask extends Task<Object> {
public CustomerClassSyncTask() {
updateTitle("用友U8系统-同步客户分类信息");
}
@Override
protected Object call() throws Exception {
YongYouU8Service service = SpringApp.getBean(YongYouU8Service.class);
CompanyCustomerService customerService = SpringApp.getBean(CompanyCustomerService.class);
AtomicInteger counter = new AtomicInteger(0);
updateMessage("读取 U8 系统 CustomerClass 数据表...");
List<Map<String, Object>> list = service.queryAllCustomerClass();
int size = list.size();
updateMessage("总共读取 CustomerClass 数据 " + size + "");
for (Map<String, Object> map : list) {
if (isCancelled()) {
updateMessage("Cancelled");
return null;
}
boolean modified = false;
String code = (String) map.get("cCCCode");
String name = (String) map.get("cCCName");
CustomerCatalog customerCatalog = customerService.findCatalogByCode(code);
if (customerCatalog == null) {
customerCatalog = new CustomerCatalog();
updateMessage("新建客户分类:" + code);
modified = true;
}
if (!Objects.equals(customerCatalog.getCode(), code)) {
customerCatalog.setCode(code);
modified = true;
}
if (!Objects.equals(customerCatalog.getName(), name)) {
customerCatalog.setName(name);
modified = true;
}
if (modified) {
customerService.save(customerCatalog);
updateMessage("更新" + customerCatalog.getName() + " 信息");
}
// 更新进度
updateProgress(counter.incrementAndGet(), size);
}
return null;
}
}

View File

@@ -0,0 +1,144 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.u8.ctx.CompanyCtx;
import com.ecep.contract.manager.cloud.u8.ctx.CustomerCtx;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.contract.tasker.AbstContractRepairTasker;
import com.ecep.contract.manager.ds.customer.model.CompanyCustomer;
import com.ecep.contract.manager.ds.customer.model.CompanyCustomerEntity;
import com.ecep.contract.manager.ds.customer.service.CompanyCustomerService;
import com.ecep.contract.manager.ui.MessageHolder;
import lombok.Setter;
import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import java.time.Instant;
import java.time.LocalDate;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
/**
* 同步客户任务
*/
public class CustomerSyncTask extends AbstContractRepairTasker {
private static final Logger logger = LoggerFactory.getLogger(CustomerSyncTask.class);
private YongYouU8Repository repository;
private final CustomerCtx customerCtx = new CustomerCtx();
@Setter
private YongYouU8Service yongYouU8Service;
public CustomerSyncTask() {
updateTitle("用友U8系统-同步客户");
}
private CompanyCustomerService getCompanyCustomerService() {
return customerCtx.getCompanyCustomerService();
}
@Override
protected void repair(MessageHolder holder) {
try {
yongYouU8Service = getBean(YongYouU8Service.class);
} catch (BeansException e) {
holder.warn("未启用 " + YongYouU8Service.NAME + " 服务");
return;
}
repository = SpringApp.getBean(YongYouU8Repository.class);
yongYouU8Service.initialize(customerCtx);
AtomicInteger counter = new AtomicInteger(0);
Long total = repository.countAllCustomers();
updateTitle("用友U8系统-同步客户,合计 " + total + "");
try (Stream<Map<String, Object>> stream = repository.queryAllCustomerForStream()) {
stream.forEach(rs -> {
if (isCancelled()) {
updateMessage("Cancelled");
return;
}
try {
String cusCode = (String) rs.get("cCusCode");
MessageHolder subHolder = holder.sub(counter.get() + " / " + total + "> " + cusCode + " ");
boolean modified = false;
CompanyCustomerEntity entity = customerCtx.findOrCreateByCode(rs, cusCode, subHolder);
Map<String, Object> map = repository.findCustomerByCusCode(entity.getCode());
if (map == null) {
subHolder.error("客户项不存在:" + cusCode);
return;
}
if (customerCtx.applyEntityDetail(entity, map, subHolder)) {
modified = true;
}
if (modified) {
entity = customerCtx.getCompanyCustomerEntityService().save(entity);
}
updateCompanyNameAndAbbName(entity, subHolder);
updateCloudYu(entity);
} catch (Exception e) {
logger.error("Customer sync failure {}, data = {}", e.getMessage(), rs, e);
updateMessage(e.getMessage());
throw e;
}
updateProgress(counter.incrementAndGet(), total);
});
}
}
private void updateCloudYu(CompanyCustomerEntity entity) {
CompanyCustomer customer = entity.getCustomer();
if (customer == null) {
return;
}
if (!Hibernate.isInitialized(customer)) {
customer = getCompanyCustomerService().findById(customer.getId());
}
Company company = customer.getCompany();
if (company == null) {
return;
}
CloudYu cloudYu = yongYouU8Service.getOrCreateCloudYu(company);
if (cloudYu == null) {
return;
}
cloudYu.setCustomerUpdateDate(LocalDate.now());
cloudYu.setCloudLatest(Instant.now());
cloudYu.setExceptionMessage("");
yongYouU8Service.save(cloudYu);
}
private void updateCompanyNameAndAbbName(CompanyCustomerEntity entity, MessageHolder holder) {
CompanyService companyService = customerCtx.getCompanyService();
CompanyCustomer customer = entity.getCustomer();
if (customer == null) {
return;
}
if (!Hibernate.isInitialized(customer)) {
customer = getCompanyCustomerService().findById(customer.getId());
}
Company company = customer.getCompany();
if (company == null) {
return;
}
if (!Hibernate.isInitialized(company)) {
company = companyService.findById(company.getId());
}
boolean modified = false;
CompanyCtx companyCtx = customerCtx.getCompanyCtx();
if (companyCtx.updateCompanyNameIfAbsent(company, entity.getName(), holder)) {
modified = true;
}
if (companyCtx.updateCompanyAbbNameIfAbsent(company, entity.getAbbName(), holder)) {
modified = true;
}
if (modified) {
companyService.save(company);
}
}
}

View File

@@ -0,0 +1,155 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.other.model.Department;
import com.ecep.contract.manager.ds.other.model.Employee;
import com.ecep.contract.manager.ds.other.service.DepartmentService;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.Tasker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 用友U8系统-同步员工信息
*/
public class EmployeesSyncTask extends Tasker<Object> {
private static final Logger logger = LoggerFactory.getLogger(EmployeesSyncTask.class);
private final AtomicInteger counter = new AtomicInteger(0);
DepartmentService departmentService;
public EmployeesSyncTask() {
updateTitle("用友U8系统-同步员工信息");
}
DepartmentService getDepartmentService() {
if (departmentService == null) {
departmentService = SpringApp.getBean(DepartmentService.class);
}
return departmentService;
}
@Override
protected Object execute(MessageHolder holder) throws Exception {
YongYouU8Service service = SpringApp.getBean(YongYouU8Service.class);
holder.debug("读取 U8 系统 Person 数据表...");
List<Map<String, Object>> list = service.queryAllPerson();
int size = list.size();
holder.debug("总共读取 Person 数据 " + size + "");
for (Map<String, Object> rs : list) {
if (isCancelled()) {
holder.debug("Cancelled");
return null;
}
MessageHolder sub = holder.sub(counter.get() + "/" + size + ">");
sync(rs, sub);
// 更新进度
updateProgress(counter.incrementAndGet(), size);
}
return null;
}
private void sync(Map<String, Object> rs, MessageHolder holder) {
String personCode = (String) rs.get("cPersonCode");
String personName = (String) rs.get("cPersonName");
String departmentCode = (String) rs.get("cDepCode");
String personEmail = (String) rs.get("cPersonEmail");
String personPhone = (String) rs.get("cPersonPhone");
java.sql.Timestamp personValidDate = (java.sql.Timestamp) rs.get("dPValidDate");
java.sql.Timestamp personInValidDate = (java.sql.Timestamp) rs.get("dPInValidDate");
boolean modified = false;
Employee employee = getEmployeeService().findByCode(personCode);
// 按员工代码未匹配时,尝试使用名字去匹配
if (employee == null) {
employee = getEmployeeService().findByName(personName);
if (employee == null) {
employee = new Employee();
employee.setCode(personCode);
employee.setName(personName);
employee.setActive(false);
employee.setCreated(LocalDate.now());
holder.info("创建员工:" + personCode + ", 姓名:" + personName + ".");
// consumer.accept("员工编号:" + personCode + ", 姓名:" + personName + ", 本地未创建");
// return;
}
employee.setCode(personCode);
modified = true;
}
MessageHolder subHolder = holder.sub(personName + ": ");
if (!StringUtils.hasText(employee.getName())) {
employee.setName(personName);
modified = true;
}
if (StringUtils.hasText(departmentCode)) {
Department departmentByCode = getDepartmentService().findByCode(departmentCode);
if (departmentByCode == null) {
subHolder.warn("部门代码:" + departmentCode + "未匹配到部门");
} else {
if (!Objects.equals(employee.getDepartment(), departmentByCode)) {
employee.setDepartment(departmentByCode);
subHolder.info("更新部门:" + departmentByCode.getName());
modified = true;
}
}
}
if (StringUtils.hasText(personPhone)) {
if (!Objects.equals(personPhone, employee.getPhone())) {
employee.setPhone(personPhone);
subHolder.info("更新电话:" + personPhone);
modified = true;
}
}
if (StringUtils.hasText(personEmail)) {
if (!Objects.equals(personEmail, employee.getEmail())) {
employee.setEmail(personEmail);
subHolder.info("更新Email" + personEmail);
modified = true;
}
}
if (personValidDate != null) {
LocalDate localDate = personValidDate.toLocalDateTime().toLocalDate();
if (!Objects.equals(localDate, employee.getEntryDate())) {
employee.setEntryDate(localDate);
subHolder.info("更新入职日期:" + localDate);
modified = true;
}
}
if (personInValidDate != null) {
LocalDate localDate = personInValidDate.toLocalDateTime().toLocalDate();
if (!Objects.equals(localDate, employee.getLeaveDate())) {
employee.setLeaveDate(localDate);
subHolder.info("更新离职日期:" + localDate);
modified = true;
}
}
if (modified) {
getEmployeeService().save(employee);
subHolder.info("更新保存");
} else {
subHolder.debug("无更新");
}
}
}

View File

@@ -0,0 +1,61 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.ds.other.service.SysConfService;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
@Lazy
@Component
@ConditionalOnBean(YongYouU8Service.class)
public class U8DataSourceFactory {
@Lazy
@Autowired
private SysConfService service;
public U8DataSourceFactory() {
System.out.println("U8DataSourceFactory.U8DataSourceFactory");
}
@Lazy
@Bean
// @ConfigurationProperties(prefix = "u8.datasource")
public DataSource MSSQL_Server() {
System.out.println("U8DataSourceFactory.MSSQL_Server");
String host = service.get("u8.db.server.ip", "192.168.1.1");
String database = service.get("u8.db.database", "UF_DATA");
String username = service.get("u8.db.server.name", "sa");
String password = service.get("u8.db.server.password", "");
boolean encrypt = service.get("u8.db.server.encrypt", false);
boolean trustServerCertificate = service.get("u8.db.server.trustServerCertificate", true);
String url = "jdbc:sqlserver://" +
host +
";databaseName=" +
database +
";encrypt=" +
encrypt +
";trustServerCertificate=" +
trustServerCertificate
// + ";sslProtocol=TLSv1"
;
HikariDataSource source = DataSourceBuilder.create()
.type(HikariDataSource.class)
.url(url)
.username(username)
.password(password)
.driverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver")
.build();
source.setMinimumIdle(0);
return source;
}
}

View File

@@ -0,0 +1,70 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.vendor.model.VendorCatalog;
import com.ecep.contract.manager.ds.vendor.repository.VendorClassRepository;
import javafx.concurrent.Task;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 同步供应商分类
*/
public class VendorClassSyncTask extends Task<Object> {
public VendorClassSyncTask() {
updateTitle("用友U8系统-同步供应商分类信息");
}
@Override
protected Object call() throws Exception {
YongYouU8Service service = SpringApp.getBean(YongYouU8Service.class);
VendorClassRepository groupRepository = SpringApp.getBean(VendorClassRepository.class);
AtomicInteger counter = new AtomicInteger(0);
updateMessage("读取 U8 系统 VendorClass 数据表...");
List<Map<String, Object>> list = service.queryAllVendorClass();
int size = list.size();
updateMessage("总共读取 VendorClass 数据 " + size + "");
for (Map<String, Object> map : list) {
if (isCancelled()) {
updateMessage("Cancelled");
return null;
}
boolean modified = false;
String code = (String) map.get("cVCCode");
String name = (String) map.get("cVCName");
VendorCatalog vendorCatalog = groupRepository.findByCode(code).orElse(null);
if (vendorCatalog == null) {
vendorCatalog = new VendorCatalog();
updateMessage("新建供应商分类:" + code);
modified = true;
}
if (!Objects.equals(vendorCatalog.getCode(), code)) {
vendorCatalog.setCode(code);
modified = true;
}
if (!Objects.equals(vendorCatalog.getName(), name)) {
vendorCatalog.setName(name);
modified = true;
}
if (modified) {
groupRepository.save(vendorCatalog);
updateMessage("更新" + vendorCatalog.getName() + " 信息");
}
// 更新进度
updateProgress(counter.incrementAndGet(), size);
}
return null;
}
}

View File

@@ -0,0 +1,157 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.u8.ctx.CompanyCtx;
import com.ecep.contract.manager.cloud.u8.ctx.VendorCtx;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.contract.tasker.AbstContractRepairTasker;
import com.ecep.contract.manager.ds.vendor.model.CompanyVendor;
import com.ecep.contract.manager.ds.vendor.model.CompanyVendorEntity;
import com.ecep.contract.manager.ds.vendor.service.CompanyVendorEntityService;
import com.ecep.contract.manager.ds.vendor.service.CompanyVendorService;
import com.ecep.contract.manager.ui.MessageHolder;
import lombok.Setter;
import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import java.time.Instant;
import java.time.LocalDate;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
/**
* 供应商同步任务
*/
public class VendorSyncTask extends AbstContractRepairTasker {
private static final Logger logger = LoggerFactory.getLogger(VendorSyncTask.class);
private final VendorCtx vendorCtx = new VendorCtx();
private CompanyVendorService companyVendorService;
private CompanyVendorEntityService vendorEntityService;
private YongYouU8Repository repository;
@Setter
private YongYouU8Service yongYouU8Service;
public VendorSyncTask() {
updateTitle("用友U8系统-同步供应商");
}
private CompanyVendorService getCompanyVendorService() {
if (companyVendorService == null) {
companyVendorService = SpringApp.getBean(CompanyVendorService.class);
}
return companyVendorService;
}
private CompanyVendorEntityService getVendorEntityService() {
if (vendorEntityService == null) {
vendorEntityService = SpringApp.getBean(CompanyVendorEntityService.class);
}
return vendorEntityService;
}
@Override
protected void repair(MessageHolder holder) {
try {
yongYouU8Service = getBean(YongYouU8Service.class);
} catch (BeansException e) {
holder.warn("未启用 " + YongYouU8Service.NAME + " 服务");
return;
}
repository = SpringApp.getBean(YongYouU8Repository.class);
yongYouU8Service.initialize(vendorCtx);
AtomicInteger counter = new AtomicInteger(0);
Long total = repository.countAllVendors();
updateTitle("用友U8系统-同步供应商,合计 " + total + "");
try (Stream<Map<String, Object>> stream = repository.queryAllVendorForStream()) {
stream.forEach(rs -> {
if (isCancelled()) {
updateMessage("Cancelled");
return;
}
try {
String venCode = (String) rs.get("cVenCode");
MessageHolder subHolder = holder.sub(counter.get() + " / " + total + "> " + venCode + " ");
boolean modified = false;
CompanyVendorEntity entity = vendorCtx.findOrCreateByCode(venCode, subHolder);
Map<String, Object> map = repository.findVendorByVendCode(entity.getCode());
if (map == null) {
subHolder.error("供应商项不存在:" + venCode);
return;
}
if (vendorCtx.applyEntityDetail(entity, map, subHolder)) {
modified = true;
}
if (modified) {
entity = getVendorEntityService().save(entity);
}
updateCompanyNameAndAbbName(entity, subHolder);
updateCloudYu(entity);
} catch (Exception e) {
logger.error("Vendor sync failure {}, data = {}", e.getMessage(), rs, e);
updateMessage(e.getMessage());
throw e;
}
updateProgress(counter.incrementAndGet(), total);
});
}
}
private void updateCloudYu(CompanyVendorEntity entity) {
CompanyVendor vendor = entity.getVendor();
if (vendor == null) {
return;
}
if (!Hibernate.isInitialized(vendor)) {
vendor = getCompanyVendorService().findById(vendor.getId());
}
Company company = vendor.getCompany();
if (company == null) {
return;
}
CloudYu cloudYu = yongYouU8Service.getOrCreateCloudYu(company);
if (cloudYu == null) {
return;
}
cloudYu.setVendorUpdateDate(LocalDate.now());
cloudYu.setCloudLatest(Instant.now());
cloudYu.setExceptionMessage("");
yongYouU8Service.save(cloudYu);
}
private void updateCompanyNameAndAbbName(CompanyVendorEntity entity, MessageHolder holder) {
CompanyService companyService = vendorCtx.getCompanyService();
CompanyVendor vendor = entity.getVendor();
if (vendor == null) {
return;
}
if (!Hibernate.isInitialized(vendor)) {
vendor = getCompanyVendorService().findById(vendor.getId());
}
Company company = vendor.getCompany();
if (company == null) {
return;
}
if (!Hibernate.isInitialized(company)) {
company = companyService.findById(company.getId());
}
boolean modified = false;
CompanyCtx companyCtx = vendorCtx.getCompanyCtx();
if (companyCtx.updateCompanyNameIfAbsent(company, entity.getName(), holder)) {
modified = true;
}
if (companyCtx.updateCompanyAbbNameIfAbsent(company, entity.getAbbName(), holder)) {
modified = true;
}
if (modified) {
companyService.save(company);
}
}
}

View File

@@ -0,0 +1,135 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.company.controller.CompanyTableCell;
import com.ecep.contract.manager.ds.company.controller.CompanyWindowController;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ui.AbstEntityManagerSkin;
import com.ecep.contract.manager.ui.ManagerSkin;
import com.ecep.contract.manager.ui.util.LocalDateTimeTableCell;
import jakarta.persistence.criteria.Path;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import lombok.Setter;
import org.hibernate.Hibernate;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;
import java.util.List;
public class YongYouU8ManagerSkin
extends AbstEntityManagerSkin<CloudYu, CloudYuInfoViewModel, YongYouU8ManagerSkin, YongYouU8ManagerWindowController>
implements ManagerSkin {
@Setter
private YongYouU8Service u8Service;
@Setter
private CompanyService companyService;
public YongYouU8ManagerSkin(YongYouU8ManagerWindowController controller) {
super(controller);
}
YongYouU8Service getU8Service() {
if (u8Service == null) {
u8Service = SpringApp.getBean(YongYouU8Service.class);
}
return u8Service;
}
CompanyService getCompanyService() {
if (companyService == null) {
companyService = SpringApp.getBean(CompanyService.class);
}
return companyService;
}
@Override
protected List<CloudYuInfoViewModel> loadTableData() {
String searchText = controller.searchKeyField.getText();
Specification<CloudYu> spec = null;
if (StringUtils.hasText(searchText)) {
Specification<CloudYu> companySpec = (root, query, builder) -> {
Path<Object> company = root.get("company");
return builder.or(
builder.like(company.get("name"), "%" + searchText + "%"),
builder.like(company.get("shortName"), "%" + searchText + "%")
);
};
Specification<CloudYu> cloudIdSpec = (root, query, builder) -> {
return builder.like(root.get("cloudId"), "%" + searchText + "%");
};
Specification<CloudYu> exceptionSpec = (root, query, builder) -> {
return builder.like(root.get("exceptionMessage"), "%" + searchText + "%");
};
spec = Specification.anyOf(companySpec, cloudIdSpec, exceptionSpec);
}
Page<CloudYu> page = getU8Service().findAll(spec, getPageable());
updateFooter(page);
return page.map(CloudYuInfoViewModel::from).toList();
}
@Override
public void initializeTable() {
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
controller.companyColumn.setCellValueFactory(param -> param.getValue().getCompany());
controller.companyColumn.setCellFactory(param -> new CompanyTableCell<>(getCompanyService()));
controller.cloudIdColumn.setCellValueFactory(param -> param.getValue().getCloudId());
controller.latestUpdateColumn.setCellValueFactory(param -> param.getValue().getLatest());
controller.latestUpdateColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
controller.cloudLatestColumn.setCellValueFactory(param -> param.getValue().getCloudLatest());
controller.cloudLatestColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
controller.descriptionColumn.setCellValueFactory(param -> param.getValue().getVendorCode());
}
@Override
protected void createContextMenu(ContextMenu contextMenu) {
MenuItem item2 = new MenuItem("刷新");
item2.setOnAction(this::onTableRefreshAction);
MenuItem item3 = new MenuItem("清空备注");
item3.setOnAction(this::onTableClearDescriptionAction);
contextMenu.getItems().addAll(item2, item3);
}
/**
* 请空选择行的注释
*
* @param event event
*/
public void onTableClearDescriptionAction(ActionEvent event) {
ObservableList<CloudYuInfoViewModel> selectedItems = getTableView().getSelectionModel().getSelectedItems();
if (selectedItems.isEmpty()) {
return;
}
for (CloudYuInfoViewModel selectedItem : selectedItems) {
CloudYu cloudYu = getU8Service().findById(selectedItem.getId().get());
selectedItem.getCustomerCode().set("");
if (selectedItem.copyTo(cloudYu)) {
CloudYu saved = getU8Service().save(cloudYu);
selectedItem.update(saved);
}
}
}
@Override
protected void onTableRowDoubleClickedAction(CloudYuInfoViewModel item) {
Company company = item.getCompany().get();
if (!Hibernate.isInitialized(item)) {
company = getCompanyService().findById(company.getId());
}
CompanyWindowController.show(company, getTableView().getScene().getWindow());
}
}

View File

@@ -0,0 +1,191 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.CloudBaseInfo;
import com.ecep.contract.manager.cloud.CloudInfo;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ui.AbstManagerWindowController;
import com.ecep.contract.manager.ui.FxmlPath;
import com.ecep.contract.manager.ui.Message;
import com.ecep.contract.manager.ui.ViewModelService;
import com.ecep.contract.manager.util.UITools;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.scene.control.TableColumn;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Consumer;
@Lazy
@Scope("prototype")
@Component
@FxmlPath("/ui/cloud/u8_manager.fxml")
public class YongYouU8ManagerWindowController
extends AbstManagerWindowController<CloudYu, CloudYuInfoViewModel, YongYouU8ManagerSkin> {
private static final Logger logger = LoggerFactory.getLogger(YongYouU8ManagerWindowController.class);
public static void show() {
show(YongYouU8ManagerWindowController.class, null);
}
@Autowired
private ScheduledExecutorService scheduledExecutorService;
public TableColumn<CloudYuInfoViewModel, Number> idColumn;
public TableColumn<CloudYuInfoViewModel, LocalDateTime> latestUpdateColumn;
public TableColumn<CloudYuInfoViewModel, Company> companyColumn;
public TableColumn<CloudYuInfoViewModel, String> cloudIdColumn;
public TableColumn<CloudYuInfoViewModel, LocalDateTime> cloudLatestColumn;
public TableColumn<CloudYuInfoViewModel, String> descriptionColumn;
@Override
public YongYouU8Service getViewModelService() {
return getSkin().getU8Service();
}
@Override
protected YongYouU8ManagerSkin createDefaultSkin() {
return new YongYouU8ManagerSkin(this);
}
@Override
public void show(Stage stage) {
super.show(stage);
getTitle().set("数据源用友U8");
}
/**
* 数据迁移,从 CloudInfo 迁移到 CloudRk
*/
public void onDateTransferAction(ActionEvent event) {
CompletableFuture.runAsync(() -> {
com.ecep.contract.manager.cloud.CloudInfoRepository cloudInfoRepository = SpringApp.getBean(com.ecep.contract.manager.cloud.CloudInfoRepository.class);
YongYouU8Service u8Service = SpringApp.getBean(YongYouU8Service.class);
cloudInfoRepository.findAll().forEach(v -> {
try {
CloudYu cloudYu = u8Service.getOrCreateCloudYu(v);
if (copyTo(v, cloudYu)) {
u8Service.save(cloudYu);
}
} catch (Exception e) {
setStatus(e.getMessage());
e.printStackTrace();
}
});
});
}
boolean copyTo(CloudInfo v, CloudBaseInfo cloudRk) {
boolean modified = false;
if (!Objects.equals(cloudRk.getLatestUpdate(), v.getLatestUpdate())) {
cloudRk.setLatestUpdate(v.getLatestUpdate());
modified = true;
}
if (!Objects.equals(cloudRk.getCloudId(), v.getCloudId())) {
cloudRk.setCloudId(v.getCloudId());
modified = true;
}
if (!Objects.equals(cloudRk.getCompany(), v.getCompany())) {
cloudRk.setCompany(v.getCompany());
modified = true;
}
return modified;
}
private <T extends Task<Object>> void initializeTask(T task, String prefix, Consumer<String> consumer) {
task.setOnScheduled(e -> {
consumer.accept("正在从用友U8同步" + prefix + ",请稍后...");
});
task.setOnRunning(e -> {
consumer.accept("开始同步" + prefix + "...");
});
task.setOnSucceeded(e -> {
consumer.accept(prefix + "同步完成...");
});
task.exceptionProperty().addListener((observable, oldValue, newValue) -> {
consumer.accept(newValue.getMessage());
logger.error("同步{}发生异常", prefix, newValue);
});
scheduledExecutorService.submit(task);
consumer.accept("同步任务已创建...");
}
public void onPersonSyncAction(ActionEvent event) {
EmployeesSyncTask task = new EmployeesSyncTask();
UITools.showTaskDialogAndWait("员工数据同步", task, null);
}
public void onContractSyncAction(ActionEvent event) {
ContractSyncTask task = new ContractSyncTask();
UITools.showTaskDialogAndWait("合同数据增量同步", task, null);
}
public void onContractAllSyncAction(ActionEvent event) {
ContractSyncAllTask task = new ContractSyncAllTask();
UITools.showTaskDialogAndWait("合同数据全量同步", task, null);
}
public void onVendorSyncAction(ActionEvent event) {
VendorSyncTask task = new VendorSyncTask();
UITools.showTaskDialogAndWait("供应商数据同步", task, null);
}
public void onCustomerSyncAction(ActionEvent event) {
CustomerSyncTask task = new CustomerSyncTask();
UITools.showTaskDialogAndWait("客户数据同步", task, null);
}
public void onContractGroupSyncAction(ActionEvent event) {
Task<Object> task = new ContractGroupSyncTask();
UITools.showTaskDialogAndWait("合同分组数据同步", task, consumer -> {
initializeTask(task, "合同分组数据", msg -> consumer.accept(Message.info(msg)));
});
}
public void onContractTypeSyncAction(ActionEvent event) {
Task<Object> task = new ContractTypeSyncTask();
UITools.showTaskDialogAndWait("合同分类数据同步", task, consumer -> {
initializeTask(task, "合同分类数据", msg -> consumer.accept(Message.info(msg)));
});
}
public void onContractKindSyncAction(ActionEvent event) {
Task<Object> task = new ContractKindSyncTask();
UITools.showTaskDialogAndWait("合同类型数据同步", task, consumer -> {
initializeTask(task, "合同类型数据", msg -> consumer.accept(Message.info(msg)));
});
}
public void onVendorClassSyncAction(ActionEvent event) {
Task<Object> task = new VendorClassSyncTask();
UITools.showTaskDialogAndWait("供应商分类数据同步", task, consumer -> {
initializeTask(task, "供应商分类数据", msg -> consumer.accept(Message.info(msg)));
});
}
public void onCustomerClassSyncAction(ActionEvent event) {
Task<Object> task = new CustomerClassSyncTask();
UITools.showTaskDialogAndWait("客户分类数据同步", task, consumer -> {
initializeTask(task, "客户分类数据", msg -> consumer.accept(Message.info(msg)));
});
}
}

View File

@@ -0,0 +1,377 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.ds.contract.ContractPayWay;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.ColumnMapRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
@Lazy
@Repository
@ConditionalOnBean(YongYouU8Service.class)
public class YongYouU8Repository {
private JdbcTemplate jdbcTemplate;
@Lazy
@Autowired
@Qualifier("MSSQL_Server")
private DataSource dataSource;
private JdbcTemplate getJdbcTemplate() {
if (jdbcTemplate == null) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
return jdbcTemplate;
}
/**
* 返回 U8 系统中 供应商总数
*
* @return 供应商总数
*/
public Long countAllVendors() {
return getJdbcTemplate().queryForObject("select count(*) from Vendor", Long.class);
}
/**
* 以流式返回所有供应商数据
*
* @return Stream 数据流
*/
public Stream<Map<String, Object>> queryAllVendorForStream() {
return getJdbcTemplate().queryForStream(
"select cVenCode,cVenName,cVenAbbName," +
"cVCCode,cVenAddress,cast(dVenDevDate as DATE) as venDevDate," +
"cVenBank, cVenAccount, cCreatePerson,cModifyPerson,dModifyDate " +
"from Vendor",
new ColumnMapRowMapper()
);
}
/**
* 以 U8 供应商 的代码查询 供应商
*
* @param vendCode U8 供应商 的代码vendCode 唯一
* @return 字段和值的Map集合, 没找到匹配的记录时返回null
*/
public Map<String, Object> findVendorByVendCode(String vendCode) {
try {
return getJdbcTemplate().queryForObject("select cVenCode,cVenName,cVenAbbName," +
"cVCCode,cVenAddress," +
"cast(dVenDevDate as DATE) as devDate,dModifyDate," +
"cVenBank,cVenAccount,cCreatePerson, cModifyPerson " +
"from Vendor where cVenCode=?", new ColumnMapRowMapper(), vendCode);
} catch (EmptyResultDataAccessException e) {
return null;
} catch (Exception e) {
throw new RuntimeException(vendCode, e);
}
}
/**
* 返回 U8 系统中 客户总数
*
* @return 客户总数
*/
public Long countAllCustomers() {
return getJdbcTemplate().queryForObject("select count(*) from Customer", Long.class);
}
/**
* 以流式返回所有客户数据
*
* @return Stream 数据流
*/
public Stream<Map<String, Object>> queryAllCustomerForStream() {
return getJdbcTemplate().queryForStream(
"select cCusCode,cCusName,cCusAbbName," +
"cCCCode,cCusAddress,cast(dCusDevDate as DATE) as cusDevDate," +
"cCusBank,cCusAccount, cCreatePerson,cModifyPerson,dModifyDate " +
"from Customer",
new ColumnMapRowMapper()
);
}
/**
* 以 U8 客户 的代码查询 客户
*
* @param cusCode U8 客户 的代码cusCode 唯一
* @return 字段和值的Map集合
*/
public Map<String, Object> findCustomerByCusCode(String cusCode) {
return getJdbcTemplate().queryForObject("select cCusCode,cCusName,cCusAbbName," +
"cCCCode,cCusAddress," +
"cast(dCusDevDate as DATE) as devDate,dModifyDate," +
"cCusBank,cCusAccount,cCreatePerson,cModifyPerson " +
"from Customer where cCusCode=?", new ColumnMapRowMapper(), cusCode);
}
/**
* 返回 U8 系统中 合同总数
* 在U8中合同在多个地方存在CM_List CM_Contract_A,CM_Contract_B,CM_Contract_C
*
* @return 合同总数
*/
public Long countAllContracts(int latestId) {
return getJdbcTemplate().queryForObject("select count(*) from CM_List where ID>?", Long.class, latestId);
}
public Long countAllContracts(LocalDateTime dateTime) {
return getJdbcTemplate().queryForObject("select count(*) from CM_List where dtDate>?", Long.class, dateTime);
}
public Long countAllContracts() {
return getJdbcTemplate().queryForObject("select count(*) from CM_List", Long.class);
}
public Long countAllContractB() {
return getJdbcTemplate().queryForObject("select count(*) from CM_Contract_B", Long.class);
}
public Long countAllContractB(LocalDate latestDate) {
return getJdbcTemplate().queryForObject(
"select count(*) " +
"from CM_Contract_B " +
"where strSetupDate>=? or (dtVaryDate is not null and dtVaryDate>=?)"
, Long.class, latestDate, latestDate);
}
public Stream<Map<String, Object>> queryAllContractForStream() {
return getJdbcTemplate().queryForStream(
"select * from CM_List", new ColumnMapRowMapper()
);
}
public Stream<Map<String, Object>> queryAllContractForStream(int latestId) {
return getJdbcTemplate().queryForStream(
"select * from CM_List where ID > ?",
new ColumnMapRowMapper(),
latestId
);
}
public Stream<Map<String, Object>> queryAllContractForStream(LocalDateTime dateTime) {
return getJdbcTemplate().queryForStream(
"select * from CM_List where dtDate > ?",
new ColumnMapRowMapper(),
dateTime
);
}
public Stream<Map<String, Object>> queryAllContractBForStream() {
return getJdbcTemplate().queryForStream(
"select GUID,strContractID,strContractName,strContractType,strParentID,strContractKind,strWay," +
"strContractGrp,strContractDesc,strBisectionUnit," +
// 时间
"strContractOrderDate,strContractStartDate,strContractEndDate," +
// 创建人和时间
"strSetupPerson,strSetupDate," +
// 生效人和时间
"strInurePerson,strInureDate," +
// 修改人和时间
"strVaryPerson,dtVaryDate," +
// 业务员
"strPersonID, " +
"dblTotalCurrency,dblExecCurrency,dblTotalQuantity,dblExecQuqantity " +
"from CM_Contract_B ",
new ColumnMapRowMapper()
);
}
public Stream<Map<String, Object>> queryAllContractBForStream(LocalDate latestDate) {
return getJdbcTemplate().queryForStream(
"select GUID,strContractID,strContractName,strContractType,strParentID,strContractKind,strWay," +
"strContractGrp,strContractDesc,strBisectionUnit," +
// 时间
"strContractOrderDate,strContractStartDate,strContractEndDate," +
// 创建人和时间
"strSetupPerson,strSetupDate," +
// 生效人和时间
"strInurePerson,strInureDate," +
// 修改人和时间
"strVaryPerson,dtVaryDate," +
// 业务员
"strPersonID, " +
"dblTotalCurrency,dblExecCurrency,dblTotalQuantity,dblExecQuqantity " +
"from CM_Contract_B where strSetupDate>=? or (dtVaryDate is not null and dtVaryDate>=?)",
new ColumnMapRowMapper(), latestDate, latestDate
);
}
/**
* 从 CM_Contract_B 表中,检索 strBisectionUnit 是 unit 的记录
*
* @param unit 单位编码
* @param payWay 付款方向,付 或 收
*/
public Stream<Map<String, Object>> queryAllContractByUnitForStream(String unit, ContractPayWay payWay) {
return getJdbcTemplate().queryForStream(
"select GUID,strContractID,strContractName,strContractType,strParentID,strContractKind,strWay," +
"strContractGrp, strContractDesc,strBisectionUnit," +
// 时间
"strContractOrderDate,strContractStartDate,strContractEndDate," +
// 创建人和时间
"strSetupPerson,strSetupDate," +
// 生效人和时间
"strInurePerson,strInureDate," +
// 修改人和时间
"strVaryPerson,dtVaryDate," +
// 业务员
"strPersonID, " +
"dblTotalCurrency,dblExecCurrency,dblTotalQuantity,dblExecQuqantity " +
"from CM_Contract_B where strBisectionUnit=? and strWay=?",
new ColumnMapRowMapper(), unit, payWay.getText()
);
}
public Map<String, Object> queryContractDetail(String guid) {
return getJdbcTemplate().queryForObject("select GUID,strContractID,strContractName,strContractType,strParentID,strContractKind,strWay," +
"strContractGrp, strContractDesc,strBisectionUnit," +
// 时间
"strContractOrderDate,strContractStartDate,strContractEndDate," +
// 创建人和时间
"strSetupPerson,strSetupDate," +
// 生效人和时间
"strInurePerson,strInureDate," +
// 修改人和时间
"strVaryPerson,dtVaryDate," +
// 业务员
"strPersonID, " +
"dblTotalCurrency,dblExecCurrency,dblTotalQuantity,dblExecQuqantity " +
" from CM_Contract_B where GUID = ?", new ColumnMapRowMapper(), guid);
}
/**
* 合计合同的执行数量、金额、 不含税金额
*
* @param code 合同号
* @return Map<String, Object>
*/
public Map<String, Object> sumContractExec(String code) {
return getJdbcTemplate().queryForObject("select sum(decCount) as execQuantity, sum(decRateMoney) as execAmount, sum(decNoRateMoney) as execUnTaxAmount " +
"from CM_ExecInterface " +
"where cContractID = ?;", new ColumnMapRowMapper(), code);
}
public List<Map<String, Object>> findAllContractExecByContractCode(String code) {
return getJdbcTemplate().queryForList("select * from CM_ExecInterface where cContractID=?", code);
}
public List<Map<String, Object>> findAllContractItemByContractCode(String code) {
return getJdbcTemplate().queryForList("select * from CM_Contract_Item_B where strContractID=?", code);
}
public List<Map<String, Object>> findAllContractPayPlanByContractCode(String code) {
return getJdbcTemplate().queryForList("select * from CM_Contract_Pay where strContractID=?", code);
}
public Map<String, Object> querySalesOrderDetail(String code) {
return getJdbcTemplate().queryForObject("select * " +
" from SO_SOMain where cSOCode = ?", new ColumnMapRowMapper(), code);
}
public List<Map<String, Object>> findAllSalesOrderItemByContractCode(String code) {
return getJdbcTemplate().queryForList("select * from SO_SODetails where cContractID=?", code);
}
public Map<String, Object> queryPurchaseOrderDetail(Integer code) {
return getJdbcTemplate().queryForObject("select * " +
" from PO_Pomain where POID = ?", new ColumnMapRowMapper(), code);
}
/**
* 采购合同项
*
* @param code 采购合同号
* @return List<Map < String, Object>>
*/
public List<Map<String, Object>> findAllPurchaseOrderItemByContractCode(String code) {
return getJdbcTemplate().queryForList("select * from PO_Podetails where ContractCode=?", code);
}
/**
* 查询存货档案数据
*
* @param code 存货编码
* @return Map<String, Object>
*/
public Map<String, Object> queryInventoryDetail(String code) {
return getJdbcTemplate().queryForObject("select I.*, U.cComUnitName from Inventory as I left join ComputationUnit as U on I.cComUnitCode=U.cComunitCode where cInvCode = ?", new ColumnMapRowMapper(), code);
}
public List<Map<String, Object>> queryAllPerson() {
return getJdbcTemplate().queryForList("select * from Person;");
}
public List<Map<String, Object>> queryAllContractGroup() {
return getJdbcTemplate().queryForList("select cGroupID, cGroupName,cRemark from CM_Group;");
}
public List<Map<String, Object>> queryAllContractType() {
return getJdbcTemplate().queryForList(
"select cTypeCode, cTypeName, CM_TypeClass.cClassName, cCharacter, cDirection " +
"from CM_Type left join CM_TypeClass on CM_Type.cClassCode = CM_TypeClass.cClassCode;");
}
public List<Map<String, Object>> queryAllContractKind() {
return getJdbcTemplate().queryForList("select KindID,KindName,Description from CM_Kind;");
}
public List<Map<String, Object>> queryAllVendorClass() {
return getJdbcTemplate().queryForList("select cVCCode, cVCName, iVCGrade from VendorClass;");
}
public List<Map<String, Object>> queryAllCustomerClass() {
return getJdbcTemplate().queryForList("select cCCCode, cCCName, iCCGrade from CustomerClass;");
}
public List<Map<String, Object>> findAllPurchaseBillVoucherByVendorCode(String code) {
return getJdbcTemplate().queryForList("select * from PurBillVouch where cVenCode=?", code);
}
public Map<String, Object> findPurchaseBillVoucherById(Integer pbvId) {
return getJdbcTemplate().queryForObject("select * from PurBillVouch where PBVID = ?", new ColumnMapRowMapper(), pbvId);
}
public List<Map<String, Object>> findAllPurchaseBillVoucherItemByPbvId(int pbvId) {
return getJdbcTemplate().queryForList("select * from PurBillVouchs where PBVID=?", pbvId);
}
/**
* 通过合同编号查询采购
*
* @param contractCode 合同编号
*/
public List<Map<String, Object>> findAllPurchaseBillVoucherItemByContractCode(String contractCode) {
return getJdbcTemplate().queryForList("select * from PurBillVouchs where ContractCode=?", contractCode);
}
public List<Map<String, Object>> findAllSalesBillVoucherByCustomerCode(String code) {
return getJdbcTemplate().queryForList("select * from SaleBillVouch where cCusCode=?", code);
}
public List<Map<String, Object>> findAllSalesBillVoucherBySalesOrderCode(String code) {
return getJdbcTemplate().queryForList("select * from SaleBillVouch where cSOCode=?", code);
}
public List<Map<String, Object>> findAllSalesBillVoucherItemBySBVID(int sbvid) {
return getJdbcTemplate().queryForList("select * from SaleBillVouchs where SBVID=?", sbvid);
}
}

View File

@@ -0,0 +1,233 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.Desktop;
import com.ecep.contract.manager.cloud.CloudInfo;
import com.ecep.contract.manager.cloud.u8.ctx.AbstractYongYouU8Ctx;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.customer.service.CompanyCustomerService;
import com.ecep.contract.manager.ds.other.service.EmployeeService;
import com.ecep.contract.manager.ds.vendor.service.CompanyVendorService;
import com.ecep.contract.manager.ui.ViewModelService;
import com.ecep.contract.manager.ui.task.MonitoredTask;
import javafx.application.Platform;
import javafx.concurrent.Task;
import org.controlsfx.control.TaskProgressView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
@Lazy
@Service
@ConditionalOnProperty(name = "cloud.u8.enabled", havingValue = "true")
public class YongYouU8Service implements ViewModelService<CloudYu, CloudYuInfoViewModel> {
private static final Logger logger = LoggerFactory.getLogger(YongYouU8Service.class);
public static final String NAME = "用友U8";
@Lazy
@Autowired
private YongYouU8Repository repository;
@Lazy
@Autowired
private CompanyService companyService;
@Lazy
@Autowired
private CompanyVendorService companyVendorService;
@Lazy
@Autowired
private CloudYuRepository cloudYuRepository;
@Lazy
@Autowired
private EmployeeService employeeService;
@Lazy
@Autowired
private CompanyCustomerService companyCustomerService;
public YongYouU8Service() {
}
public CloudYu findById(Integer id) {
return cloudYuRepository.findById(id).orElse(null);
}
/**
* 创建
*
* @param info 供应商信息
* @return 供应商对象
*/
public CloudYu getOrCreateCloudYu(CloudInfo info) {
Optional<CloudYu> optional = cloudYuRepository.findById(info.getId());
return optional.orElseGet(() -> getOrCreateCloudYu(info.getCompany()));
}
/**
* 创建或获取供应商云信息
*
* @param company 公司
* @return 供应商云信息
*/
public CloudYu getOrCreateCloudYu(Company company) {
Integer companyId = company.getId();
List<CloudYu> list = cloudYuRepository.findAllByCompanyId(companyId);
if (list.isEmpty()) {
CloudYu cloudYu = new CloudYu();
cloudYu.setCompany(company);
cloudYu.setExceptionMessage("");
cloudYu.setVendorUpdateDate(null);
cloudYu.setCustomerUpdateDate(null);
cloudYu.setCloudLatest(null);
return cloudYuRepository.save(cloudYu);
}
// 只有匹配到一条有 CloudId 的记录
if (list.size() == 1) {
// 保留匹配的记录,其他删除
CloudYu rk = list.removeFirst();
list.remove(rk);
cloudYuRepository.deleteAll(list);
return rk;
}
return list.getFirst();
}
/**
* 生成定时同步任务
*
* @param taskProgressView 任务视图
*/
public void scheduledTasks(TaskProgressView<Task<?>> taskProgressView) {
ScheduledExecutorService executorService = Desktop.instance.getExecutorService();
executorService.scheduleAtFixedRate(() -> {
ContractSyncTask task = new ContractSyncTask();
MonitoredTask<Object> registerTask = Desktop.instance.getTaskMonitorCenter().registerTask(task);
executorService.schedule(registerTask, 5, TimeUnit.SECONDS);
}, 3, TimeUnit.MINUTES.toSeconds(15), TimeUnit.SECONDS);
executorService.scheduleAtFixedRate(() -> {
// 1小时运行一次同步供应商任务
VendorSyncTask vendorTask = new VendorSyncTask();
MonitoredTask<Object> registerVendorTask = Desktop.instance.getTaskMonitorCenter().registerTask(vendorTask);
executorService.schedule(registerVendorTask, 60, TimeUnit.SECONDS);
// 1小时运行一次同步客户任务
CustomerSyncTask customerTask = new CustomerSyncTask();
MonitoredTask<Object> registerCustomerTask = Desktop.instance.getTaskMonitorCenter()
.registerTask(customerTask);
executorService.schedule(registerCustomerTask, 60, TimeUnit.SECONDS);
}, 3, TimeUnit.HOURS.toSeconds(1), TimeUnit.SECONDS);
}
/**
* 保存 Cloud Yu
*
* @param cloudYu Cloud Yu 对象
* @return 更新的 Cloud Yu
*/
public CloudYu save(CloudYu cloudYu) {
return cloudYuRepository.save(cloudYu);
}
@Override
public void delete(CloudYu entity) {
cloudYuRepository.delete(entity);
}
public void deleteByCompany(Company company) {
int deleted = cloudYuRepository.deleteAllByCompany(company);
if (deleted > 0) {
if (logger.isInfoEnabled()) {
logger.info("Delete {} records by company:#{}", deleted, company.getId());
}
}
}
public void resetTo(Company from, Company to) {
List<CloudYu> list = cloudYuRepository.findAllByCompanyId(from.getId());
for (CloudYu item : list) {
item.setCompany(to);
}
cloudYuRepository.saveAll(list);
}
public Page<CloudYu> findAll(Specification<CloudYu> spec, Pageable pageable) {
return cloudYuRepository.findAll(spec, pageable);
}
@Override
public Specification<CloudYu> getSpecification(String searchText) {
if (!StringUtils.hasText(searchText)) {
return null;
}
return (root, query, builder) -> {
return builder.like(root.get("cloudId"), "%" + searchText + "%");
};
}
public List<Map<String, Object>> queryAllContractKind() {
return repository.queryAllContractKind();
}
public List<Map<String, Object>> queryAllVendorClass() {
return repository.queryAllVendorClass();
}
public List<Map<String, Object>> queryAllCustomerClass() {
return repository.queryAllCustomerClass();
}
public List<Map<String, Object>> queryAllContractType() {
return repository.queryAllContractType();
}
public List<Map<String, Object>> queryAllContractGroup() {
return repository.queryAllContractGroup();
}
public Long countAllCustomers() {
return repository.countAllCustomers();
}
public Stream<Map<String, Object>> queryAllCustomerForStream() {
return repository.queryAllCustomerForStream();
}
public List<Map<String, Object>> queryAllPerson() {
return repository.queryAllPerson();
}
public Map<String, Object> findVendorByVendCode(String unit) {
return repository.findVendorByVendCode(unit);
}
public Map<String, Object> findCustomerByCusCode(String unit) {
return repository.findCustomerByCusCode(unit);
}
public void initialize(AbstractYongYouU8Ctx ctx) {
ctx.setRepository(repository);
ctx.setCompanyService(companyService);
ctx.setEmployeeService(employeeService);
ctx.setCompanyVendorService(companyVendorService);
ctx.setCompanyCustomerService(companyCustomerService);
}
}

View File

@@ -0,0 +1,216 @@
package com.ecep.contract.manager.cloud.u8.ctx;
import com.ecep.contract.manager.cloud.AbstractCtx;
import com.ecep.contract.manager.cloud.u8.YongYouU8Repository;
import com.ecep.contract.manager.cloud.u8.YongYouU8Service;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.customer.model.CompanyCustomer;
import com.ecep.contract.manager.ds.customer.model.CompanyCustomerEntity;
import com.ecep.contract.manager.ds.customer.service.CompanyCustomerEntityService;
import com.ecep.contract.manager.ds.customer.service.CompanyCustomerService;
import com.ecep.contract.manager.ds.other.model.Employee;
import com.ecep.contract.manager.ds.other.service.EmployeeService;
import com.ecep.contract.manager.ds.vendor.model.CompanyVendor;
import com.ecep.contract.manager.ds.vendor.model.CompanyVendorEntity;
import com.ecep.contract.manager.ds.vendor.service.CompanyVendorEntityService;
import com.ecep.contract.manager.ds.vendor.service.CompanyVendorService;
import com.ecep.contract.manager.ui.MessageHolder;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.Hibernate;
import org.springframework.beans.BeansException;
import org.springframework.util.StringUtils;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static com.ecep.contract.manager.SpringApp.getBean;
public class AbstractYongYouU8Ctx extends AbstractCtx {
@Getter
@Setter
YongYouU8Repository repository;
@Setter
CompanyService companyService;
@Setter
EmployeeService employeeService;
@Setter
CompanyCustomerService companyCustomerService;
@Setter
CompanyCustomerEntityService companyCustomerEntityService;
@Setter
CompanyVendorService companyVendorService;
@Setter
CompanyVendorEntityService companyVendorEntityService;
public void from(AbstractYongYouU8Ctx parent) {
repository = parent.repository;
companyService = parent.companyService;
employeeService = parent.employeeService;
companyCustomerService = parent.companyCustomerService;
companyVendorService = parent.companyVendorService;
}
public void initializeRepository(MessageHolder holder) {
if (repository != null) {
return;
}
try {
repository = getBean(YongYouU8Repository.class);
} catch (BeansException e) {
holder.warn("未启用 " + YongYouU8Service.NAME + " 服务");
}
}
public CompanyService getCompanyService() {
if (companyService == null) {
companyService = getBean(CompanyService.class);
}
return companyService;
}
EmployeeService getEmployeeService() {
if (employeeService == null) {
employeeService = getBean(EmployeeService.class);
}
return employeeService;
}
public CompanyCustomerService getCompanyCustomerService() {
if (companyCustomerService == null) {
companyCustomerService = getBean(CompanyCustomerService.class);
}
return companyCustomerService;
}
public CompanyCustomerEntityService getCompanyCustomerEntityService() {
if (companyCustomerEntityService == null) {
companyCustomerEntityService = getBean(CompanyCustomerEntityService.class);
}
return companyCustomerEntityService;
}
public CompanyVendorService getCompanyVendorService() {
if (companyVendorService == null) {
companyVendorService = getBean(CompanyVendorService.class);
}
return companyVendorService;
}
public CompanyVendorEntityService getCompanyVendorEntityService() {
if (companyVendorEntityService == null) {
companyVendorEntityService = getBean(CompanyVendorEntityService.class);
}
return companyVendorEntityService;
}
boolean updateEmployeeByCode(Supplier<Employee> getter, Consumer<Employee> setter, String code, MessageHolder holder, String topic) {
if (StringUtils.hasText(code)) {
Employee employee = getEmployeeService().findByCode(code);
if (employee != null) {
if (!Objects.equals(getter.get(), employee)) {
setter.accept(employee);
holder.info(topic + "更新为 " + employee.getName());
return true;
}
}
}
return false;
}
boolean updateEmployeeByName(Supplier<Employee> getter, Consumer<Employee> setter, String name, MessageHolder holder, String topic) {
if (StringUtils.hasText(name)) {
Employee employee = getEmployeeService().findByName(name);
if (employee != null) {
if (!Objects.equals(getter.get(), employee)) {
setter.accept(employee);
holder.info(topic + "更新为 " + employee.getName());
return true;
}
}
}
return false;
}
boolean updateCompanyByCustomerCode(Supplier<Company> getter, Consumer<Company> setter, String customerCode, MessageHolder holder, String topic) {
Company company = null;
if (StringUtils.hasText(customerCode)) {
CompanyCustomerEntityService customerEntityService = getCompanyCustomerEntityService();
CompanyCustomerService customerService = getCompanyCustomerService();
CompanyCustomerEntity entity = customerEntityService.findByCustomerCode(customerCode);
if (entity == null) {
holder.warn("无效" + topic + "" + customerCode);
} else {
CompanyCustomer customer = entity.getCustomer();
if (customer == null) {
holder.warn("无效" + topic + "" + customerCode);
} else {
if (!Hibernate.isInitialized(customer)) {
customer = customerService.findById(customer.getId());
}
company = customer.getCompany();
}
}
}
if (company == null) {
setter.accept(null);
holder.warn("无效" + topic + "" + customerCode);
return true;
} else {
if (!Objects.equals(getter.get(), company)) {
setter.accept(company);
if (!Hibernate.isInitialized(company)) {
company = getCompanyService().findById(company.getId());
}
holder.info(topic + "修改为: " + company.getName());
return true;
}
}
return false;
}
boolean updateCompanyByVendorCode(Supplier<Company> getter, Consumer<Company> setter, String vendorCode, MessageHolder holder, String topic) {
Company company = null;
if (StringUtils.hasText(vendorCode)) {
CompanyVendorEntityService vendorEntityService = getCompanyVendorEntityService();
CompanyVendorService customerService = getCompanyVendorService();
CompanyVendorEntity entity = vendorEntityService.findByCode(vendorCode);
if (entity == null) {
holder.warn("无效" + topic + "" + vendorCode);
} else {
CompanyVendor customer = entity.getVendor();
if (customer == null) {
holder.warn("无效" + topic + "" + vendorCode);
} else {
if (!Hibernate.isInitialized(customer)) {
customer = customerService.findById(customer.getId());
}
company = customer.getCompany();
}
}
}
if (company == null) {
setter.accept(null);
holder.warn("无效" + topic + "" + vendorCode);
return true;
} else {
if (!Objects.equals(getter.get(), company)) {
setter.accept(company);
if (!Hibernate.isInitialized(company)) {
company = getCompanyService().findById(company.getId());
}
holder.info(topic + "修改为: " + company.getName());
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,24 @@
package com.ecep.contract.manager.cloud.u8.ctx;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.service.CompanyBankAccountService;
import com.ecep.contract.manager.ui.MessageHolder;
import lombok.Setter;
import static com.ecep.contract.manager.SpringApp.getBean;
public class CompanyBankAccountCtx extends AbstractYongYouU8Ctx {
@Setter
private CompanyBankAccountService companyBankAccountService;
CompanyBankAccountService getCompanyBankAccountService() {
if (companyBankAccountService == null) {
companyBankAccountService = getBean(CompanyBankAccountService.class);
}
return companyBankAccountService;
}
public void updateBankAccount(Company company, String bank, String bankAccount, MessageHolder holder) {
getCompanyBankAccountService().updateBankAccount(company, bank, bankAccount, holder);
}
}

View File

@@ -0,0 +1,128 @@
package com.ecep.contract.manager.cloud.u8.ctx;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.u8.YongYouU8Service;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.model.CompanyOldName;
import com.ecep.contract.manager.ds.company.service.CompanyOldNameService;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.other.service.SysConfService;
import com.ecep.contract.manager.ui.MessageHolder;
import lombok.Setter;
import org.springframework.util.StringUtils;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import static com.ecep.contract.manager.SpringApp.getBean;
public class CompanyCtx extends AbstractYongYouU8Ctx {
public static final String AUTO_CREATE_COMPANY_AFTER = "cloud.u8.auto-create-company-after";
@Setter
private CompanyOldNameService companyOldNameService;
CompanyOldNameService getCompanyOldNameService() {
if (companyOldNameService == null) {
companyOldNameService = getBean(CompanyOldNameService.class);
}
return companyOldNameService;
}
public boolean updateCompanyNameIfAbsent(Company company, String name, MessageHolder holder) {
if (!StringUtils.hasText(name)) {
return false;
}
if (StringUtils.hasText(company.getName())) {
if (Objects.equals(company.getName(), name)) {
return false;
}
appendOldNameIfAbsent(company, name, false, holder);
return false;
} else {
return updateText(company::getName, company::setName, name, holder, "公司名称");
}
}
public boolean updateCompanyAbbNameIfAbsent(Company company, String abbName, MessageHolder holder) {
if (!StringUtils.hasText(abbName)) {
return false;
}
// 简称与公司名相同,跳过
if (Objects.equals(company.getName(), abbName)) {
return false;
}
if (StringUtils.hasText(company.getShortName())) {
if (Objects.equals(company.getShortName(), abbName)) {
return false;
}
appendOldNameIfAbsent(company, abbName, true, holder);
return false;
} else {
return updateText(company::getShortName, company::setShortName, abbName, holder, "公司简称");
}
}
private void appendOldNameIfAbsent(Company company, String name, boolean ambiguity, MessageHolder holder) {
List<CompanyOldName> oldNames = getCompanyOldNameService().findAllByCompanyAndName(company, name);
if (oldNames.isEmpty()) {
CompanyOldName companyOldName = getCompanyOldNameService().createNew(company, name, ambiguity);
companyOldName.setMemo("来自" + YongYouU8Service.NAME);
getCompanyOldNameService().save(companyOldName);
holder.info("新增曾用名:" + name);
}
}
public boolean syncCompany(Company company, MessageHolder holder) {
return false;
}
public Company findOrCreateByNameOrAbbName(String name, String abbName, LocalDate developDate, MessageHolder holder) {
Company company = getCompanyService().findAndRemoveDuplicateCompanyByNameOrAbbName(name, abbName);
if (company != null) {
return company;
}
// 判断是否是个人
holder.warn("企业库中找不到" + name + "" + abbName + " 的企业");
// 推测个人用户,归入散户
if (name.length() < 4 && !name.contains("公司")) {
company = getCompanyService().findByName("散户");
if (company == null) {
return null;
}
holder.info(name + " 个人用户归集到散户");
return company;
}
// 尝试创建公司
company = autoCreateNewCompanyAfter(developDate, name, abbName, holder);
if (company != null) {
holder.info("自动创建公司:" + company.getName());
}
return null;
}
private Company autoCreateNewCompanyAfter(LocalDate devDate, String name, String abbName, MessageHolder holder) {
if (devDate == null) {
holder.warn("开发时间未知,不创建公司");
return null;
}
CompanyService companyService = getCompanyService();
String autoCreateAfter = SpringApp.getBean(SysConfService.class).getString(AUTO_CREATE_COMPANY_AFTER);
// 当配置存在,且开发时间小于指定时间,不创建
if (StringUtils.hasText(autoCreateAfter)) {
LocalDate miniDate = LocalDate.parse(autoCreateAfter);
if (devDate.isBefore(miniDate)) {
// 创建时间小于指定时间,不创建
holder.warn(name + " 的开发时间 " + devDate + "" + miniDate + " 之前的, 按规定不创建, 如有需要请手动创建");
return null;
}
}
Company com = companyService.createNewCompany(name);
com.setShortName(abbName);
return companyService.save(com);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,301 @@
package com.ecep.contract.manager.cloud.u8.ctx;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.old.OldVersionService;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.customer.model.CompanyCustomer;
import com.ecep.contract.manager.ds.customer.model.CompanyCustomerEntity;
import com.ecep.contract.manager.ds.customer.model.CustomerCatalog;
import com.ecep.contract.manager.ds.customer.service.CompanyCustomerEntityService;
import com.ecep.contract.manager.ui.MessageHolder;
import lombok.Setter;
import org.hibernate.Hibernate;
import org.springframework.util.StringUtils;
import java.time.Instant;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class CustomerCtx extends AbstractYongYouU8Ctx {
private static final String AUTO_CREATE_CUSTOMER_AFTER = "cloud.u8.auto-create-customer-after";
@Setter
private CompanyCtx companyCtx;
@Setter
private ContractCtx contractCtx;
@Setter
private CompanyBankAccountCtx companyBankAccountCtx;
@Setter
private CompanyCustomerEntityService customerEntityService;
public CompanyCtx getCompanyCtx() {
if (companyCtx == null) {
companyCtx = new CompanyCtx();
companyCtx.from(this);
}
return companyCtx;
}
ContractCtx getContractCtx() {
if (contractCtx == null) {
contractCtx = new ContractCtx();
contractCtx.from(this);
}
return contractCtx;
}
CompanyBankAccountCtx getCompanyBankAccountCtx() {
if (companyBankAccountCtx == null) {
companyBankAccountCtx = new CompanyBankAccountCtx();
companyBankAccountCtx.from(this);
}
return companyBankAccountCtx;
}
CompanyCustomerEntityService getCustomerEntityService() {
if (customerEntityService == null) {
customerEntityService = SpringApp.getBean(CompanyCustomerEntityService.class);
}
return customerEntityService;
}
/**
* 更新客户相关项
*
* @param item
* @param unitCode
* @param holder
*/
public CompanyCustomerEntity updateCustomerEntityDetailByCode(CompanyCustomerEntity item, String unitCode, MessageHolder holder) {
if (applyEntityDetail(item, repository.findCustomerByCusCode(unitCode), holder)) {
item = save(item);
}
return item;
}
public boolean applyEntityDetail(CompanyCustomerEntity item, Map<String, Object> map, MessageHolder holder) {
String name = (String) map.get("cCusName");
String abbName = (String) map.get("cCusAbbName");
String cusCode = (String) map.get("cCusCode");
String classCode = (String) map.get("cCCCode");
String createPerson = (String) map.get("cCreatePerson");
String modifyPerson = (String) map.get("cModifyPerson");
java.sql.Date devDate = (java.sql.Date) map.get("devDate");
java.sql.Timestamp modifyDate = (java.sql.Timestamp) map.get("dModifyDate");
String bank = (String) map.get("cCusBank");
String bankAccount = (String) map.get("cCusAccount");
boolean modified = false;
if (updateText(item::getName, item::setName, name, holder, "名称")) {
modified = true;
}
if (updateText(item::getAbbName, item::setAbbName, abbName, holder, "简称")) {
modified = true;
}
if (updateText(item::getCode, item::setCode, cusCode, holder, "客户编号")) {
modified = true;
}
if (updateCustomerCatalog(item::getCatalog, item::setCatalog, classCode, holder, "分类")) {
modified = true;
}
if (updateEmployeeByName(item::getCreator, item::setCreator, createPerson, holder, "创建人")) {
modified = true;
}
if (updateEmployeeByName(item::getModifier, item::setModifier, modifyPerson, holder, "修改人")) {
modified = true;
}
if (updateLocalDate(item::getDevelopDate, item::setDevelopDate, devDate, holder, "发展日期")) {
modified = true;
}
if (updateLocalDate(item::getModifyDate, item::setModifyDate, modifyDate, holder, "修改日期")) {
modified = true;
}
if (modified) {
LocalDate today = LocalDate.now();
if (item.getUpdatedDate() == null || item.getUpdatedDate().isBefore(today)) {
item.setUpdatedDate(today);
holder.info("更新日期更新为 " + today);
}
}
CompanyCustomer customer = item.getCustomer();
if (customer == null) {
// 如果没有关联客户,则根据供应商名称或别名查找公司
Company company = findOrCreateCompanyByCustomerEntity(item, holder);
if (company != null) {
// 找到客户
customer = getCompanyCustomerService().findByCompany(company);
if (customer == null) {
customer = createCustomerByCustomerEntity(item, holder);
if (customer != null) {
customer.setCompany(company);
customer = getCompanyCustomerService().save(customer);
}
}
if (customer != null) {
item.setCustomer(customer);
modified = true;
}
}
}
if (customer != null) {
if (!Hibernate.isInitialized(customer)) {
customer = getCompanyCustomerService().findById(customer.getId());
}
Company company = customer.getCompany();
if (company != null) {
getCompanyBankAccountCtx().updateBankAccount(company, bank, bankAccount, holder);
}
}
return modified;
}
private boolean updateCustomerCatalog(Supplier<CustomerCatalog> getter, Consumer<CustomerCatalog> setter, String catalogCode, MessageHolder holder, String topic) {
CustomerCatalog catalog = null;
if (StringUtils.hasText(catalogCode)) {
catalog = getCompanyCustomerService().findCatalogByCode(catalogCode);
}
if (catalog == null) {
setter.accept(null);
holder.warn("无效" + topic + "" + catalogCode);
return true;
} else {
if (!Objects.equals(getter.get(), catalog)) {
if (!Hibernate.isInitialized(catalog)) {
catalog = getCompanyCustomerService().findCatalogByCode(catalogCode);
}
setter.accept(catalog);
holder.info(topic + "修改为: " + catalog.getName());
return true;
}
}
return false;
}
public boolean syncCustomer(Company company, MessageHolder holder) {
CompanyCustomer companyCustomer = getCompanyCustomerService().findByCompany(company);
if (companyCustomer == null) {
holder.error("客户未创建, 如需要请手动创建.");
return false;
}
// 检索相关项
List<CompanyCustomerEntity> entities = getCustomerEntityService().findAllByCustomer(companyCustomer);
if (entities.isEmpty()) {
holder.error("客户未关联任何相关项");
return false;
}
boolean updated = false;
boolean companyModified = false;
// 更新相关项
for (CompanyCustomerEntity entity : entities) {
if (!StringUtils.hasText(entity.getCode())) {
holder.warn("相关项:" + entity.getCode() + " 无效,跳过");
continue;
}
if (applyEntityDetail(entity, repository.findCustomerByCusCode(entity.getCode()), holder)) {
entity = getCustomerEntityService().save(entity);
}
if (getCompanyCtx().updateCompanyNameIfAbsent(company, entity.getName(), holder)) {
companyModified = true;
}
if (getCompanyCtx().updateCompanyAbbNameIfAbsent(company, entity.getAbbName(), holder)) {
companyModified = true;
}
}
if (companyModified) {
company = getCompanyService().save(company);
updated = true;
}
// 更新客户的开发日期
if (updateCustomerDevelopDate(companyCustomer, entities, holder)) {
companyCustomer = getCompanyCustomerService().save(companyCustomer);
updated = true;
}
for (CompanyCustomerEntity entity : entities) {
if (getContractCtx().syncByCustomerEntity(companyCustomer, entity, holder)) {
updated = true;
}
}
return updated;
}
private boolean updateCustomerDevelopDate(CompanyCustomer companyCustomer, List<CompanyCustomerEntity> entities, MessageHolder holder) {
LocalDate developDate = null;
for (CompanyCustomerEntity entity : entities) {
// 取最早的开发日期
if (developDate == null || entity.getDevelopDate().isBefore(developDate)) {
developDate = entity.getDevelopDate();
}
}
return updateLocalDate(companyCustomer::getDevelopDate, companyCustomer::setDevelopDate, developDate, holder, "开发日期");
}
public CompanyCustomerEntity findOrCreateByCode(Map<String, Object> rs, String cusCode, MessageHolder subHolder) {
CompanyCustomerEntityService customerEntityService = getCompanyCustomerEntityService();
CompanyCustomerEntity entity = customerEntityService.findByCustomerCode(cusCode);
if (entity == null) {
entity = new CompanyCustomerEntity();
entity.setCode(cusCode);
entity = customerEntityService.save(entity);
subHolder.info("创建客户相关项:" + cusCode);
}
return entity;
}
private CompanyCustomer createCustomerByCustomerEntity(CompanyCustomerEntity entity, MessageHolder holder) {
LocalDate developDate = entity.getDevelopDate();
if (developDate == null) {
holder.warn(entity.getName() + " 没有设置开发日期,跳过");
return null;
}
// 创建发展日期从2023年1月1日后的
LocalDate start = LocalDate.of(2023, 1, 1);
String autoCreateAfter = getConfService().getString(AUTO_CREATE_CUSTOMER_AFTER);
if (StringUtils.hasText(autoCreateAfter)) {
start = LocalDate.parse(autoCreateAfter);
}
if (developDate.isBefore(start)) {
// start 之前的不自动创建
holder.warn(entity.getName() + " 的发展日期 " + developDate + "" + start + " 之前的, 按规定不自动创建客户, 如有需要请手动创建");
return null;
}
CompanyCustomer companyCustomer = new CompanyCustomer();
int nextId = SpringApp.getBean(OldVersionService.class).newCompanyCustomer(entity.getName());
companyCustomer.setId(nextId);
companyCustomer.setDevelopDate(developDate);
holder.info("新客户:" + entity.getName() + "分配编号:" + nextId);
companyCustomer.setCreated(Instant.now());
return companyCustomer;
}
private Company findOrCreateCompanyByCustomerEntity(CompanyCustomerEntity entity, MessageHolder holder) {
String name = entity.getName();
String abbName = entity.getAbbName();
return getCompanyCtx().findOrCreateByNameOrAbbName(name, abbName, entity.getDevelopDate(), holder);
}
public CompanyCustomerEntity save(CompanyCustomerEntity entity) {
return getCustomerEntityService().save(entity);
}
}

View File

@@ -0,0 +1,227 @@
package com.ecep.contract.manager.cloud.u8.ctx;
import com.ecep.contract.manager.cloud.u8.YongYouU8Service;
import com.ecep.contract.manager.ds.other.model.Inventory;
import com.ecep.contract.manager.ds.other.model.InventoryCatalog;
import com.ecep.contract.manager.ds.other.model.Price;
import com.ecep.contract.manager.ds.other.service.InventoryCatalogService;
import com.ecep.contract.manager.ds.other.service.InventoryService;
import com.ecep.contract.manager.ui.MessageHolder;
import lombok.Setter;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.util.StringUtils;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static com.ecep.contract.manager.SpringApp.getBean;
public class InventoryCtx extends AbstractYongYouU8Ctx {
@Setter
private InventoryService inventoryService;
@Setter
private InventoryCatalogService inventoryCatalogService;
public InventoryService getInventoryService() {
if (inventoryService == null) {
inventoryService = getBean(InventoryService.class);
}
return inventoryService;
}
public InventoryCatalogService getInventoryCatalogService() {
if (inventoryCatalogService == null) {
inventoryCatalogService = getBean(InventoryCatalogService.class);
}
return inventoryCatalogService;
}
private boolean applyInventoryDetail(Inventory item, Map<String, Object> map, MessageHolder holder) {
String catalogCode = (String) map.get("cInvCCode");
String name = (String) map.get("cInvName");
String spec = (String) map.get("cInvStd");
String unitCode = (String) map.get("cComUnitCode");
String unitName = (String) map.get("cComUnitName");
String createPerson = (String) map.get("cCreatePerson");
String modifyPerson = (String) map.get("cModifyPerson");
Timestamp createDate = (Timestamp) map.get("dSDate");
Timestamp modifyDate = (Timestamp) map.get("dModifyDate");
boolean modified = false;
Double outTaxRate = (Double) map.get("iTaxRate");
Double inTaxRate = (Double) map.get("iImpTaxRate");
// 参考成本
Double baseCostPrice = (Double) map.get("iInvSPrice");
// 最新成本
Double latestCostPrice = (Double) map.get("iInvNCost");
// 计划价/售价
Double plannedPrice = (Double) map.get("iInvRCost");
// 最低售价
Double lowestSalePrice = (Double) map.get("iInvLSCost");
// 参考售价
Double suggestedSalePrice = (Double) map.get("iInvSCost");
if (!item.isNameLock()) {
if (updateText(item::getName, item::setName, name, holder, "名称")) {
modified = true;
}
}
if (!item.isSpecificationLock()) {
if (updateText(item::getSpecification, item::setSpecification, spec, holder, "规格")) {
modified = true;
}
}
if (updateText(item::getUnit, item::setUnit, unitName, holder, "单位")) {
modified = true;
}
if (updatePrice(item.getPurchasePrice(), inTaxRate, latestCostPrice, holder, "采购")) {
modified = true;
}
if (updatePrice(item.getSalePrice(), outTaxRate, suggestedSalePrice, holder, "销售")) {
modified = true;
}
if (updateInventoryCatalog(item::getCatalog, item::setCatalog, catalogCode, holder, "类别")) {
modified = true;
}
if (updateEmployeeByName(item::getCreator, item::setCreator, createPerson, holder, "创建人")) {
modified = true;
}
if (updateLocalDate(item::getCreateTime, item::setCreateTime, createDate, holder, "创建时间")) {
modified = true;
}
if (updateEmployeeByName(item::getUpdater, item::setUpdater, modifyPerson, holder, "修改人")) {
modified = true;
}
if (updateLocalDateTime(item::getUpdateDate, item::setUpdateDate, modifyDate, holder, "修改时间")) {
modified = true;
}
return modified;
}
private boolean updatePrice(Price price, Double taxRate, Double preTaxPrice, MessageHolder holder, String title) {
boolean modified = false;
if (taxRate != null) {
if (updateNumber(price::getTaxRate, price::setTaxRate, taxRate.floatValue(), holder, title + "税率")) {
modified = true;
}
}
if (preTaxPrice != null) {
if (updateNumber(price::getPreTaxPrice, price::setPreTaxPrice, preTaxPrice, holder, title + "未税单价")) {
modified = true;
}
}
return modified;
}
public boolean syncInventoryDetailByCode(Inventory inventory, String inventoryCode, MessageHolder holder) {
if (repository == null) {
return false;
}
Map<String, Object> map = null;
try {
map = repository.queryInventoryDetail(inventoryCode);
} catch (NoSuchBeanDefinitionException e) {
holder.warn("未启用 " + YongYouU8Service.NAME + " 服务");
return false;
} catch (EmptyResultDataAccessException e) {
holder.error("无此存货:" + inventoryCode);
return false;
}
if (applyInventoryDetail(inventory, map, holder)) {
inventory.setUpdateDate(LocalDateTime.now());
return true;
}
return false;
}
/**
* 依据存货分类编号更新存货分类
*
* @param getter 获取的函数
* @param setter 设置的函数
* @param catalogCode 存货分类编号
* @param holder 消息处理对象
* @param topic 主题
* @return 是否更新
*/
private boolean updateInventoryCatalog(Supplier<InventoryCatalog> getter, Consumer<InventoryCatalog> setter, String catalogCode, MessageHolder holder, String topic) {
InventoryCatalog catalog = null;
if (StringUtils.hasText(catalogCode)) {
catalog = getInventoryCatalogService().findByCode(catalogCode);
}
if (catalog == null) {
setter.accept(null);
holder.warn("无效" + topic + "" + catalogCode);
return true;
} else {
if (!Objects.equals(getter.get(), catalog)) {
if (!Hibernate.isInitialized(catalog)) {
catalog = getInventoryCatalogService().findByCode(catalogCode);
}
setter.accept(catalog);
holder.info(topic + "修改为: " + catalog.getName());
return true;
}
}
return false;
}
/**
* 依据存货编号更新存货
*
* @param getter 获取的函数
* @param setter 设置的函数
* @param inventoryCode 存货编号
* @param holder 消息持有者
* @param topic 主题
* @return 是否更新
*/
public boolean syncInventoryDetailByCode(Supplier<Inventory> getter, Consumer<Inventory> setter, String inventoryCode, MessageHolder holder, String topic) {
if (!StringUtils.hasText(inventoryCode)) {
return false;
}
Inventory inventory = null;
InventoryService service = getInventoryService();
if (StringUtils.hasText(inventoryCode)) {
inventory = service.findByCode(inventoryCode);
if (inventory == null) {
inventory = service.createNewInstance();
inventory.setCode(inventoryCode);
if (syncInventoryDetailByCode(inventory, inventoryCode, holder)) {
inventory = getInventoryService().save(inventory);
} else {
return false;
}
}
}
if (inventory == null) {
setter.accept(null);
holder.warn("无效" + topic + "" + inventoryCode);
return true;
} else {
if (!Objects.equals(getter.get(), inventory)) {
if (!Hibernate.isInitialized(inventory)) {
inventory = service.findByCode(inventoryCode);
}
setter.accept(inventory);
holder.info(topic + "修改为: " + inventory.getName());
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,50 @@
package com.ecep.contract.manager.cloud.u8.ctx;
import com.ecep.contract.manager.ds.company.model.Invoice;
import com.ecep.contract.manager.ds.company.service.InvoiceService;
import com.ecep.contract.manager.ui.MessageHolder;
import lombok.Setter;
import org.springframework.util.StringUtils;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static com.ecep.contract.manager.SpringApp.getBean;
public class InvoiceCtx extends AbstractYongYouU8Ctx {
@Setter
private InvoiceService invoiceService;
InvoiceService getInvoiceService() {
if (invoiceService == null) {
invoiceService = getBean(InvoiceService.class);
}
return invoiceService;
}
public boolean updateInvoiceByNumber(Supplier<Invoice> getter, Consumer<Invoice> setter, String invoiceNumber, MessageHolder holder, String topic) {
// TODO 从U8系统中获取数据
Invoice invoice = null;
if (StringUtils.hasText(invoiceNumber)) {
invoice = getInvoiceService().findByCode(invoiceNumber);
if (invoice == null) {
invoice = new Invoice();
invoice.setCode(invoiceNumber);
invoice = getInvoiceService().save(invoice);
}
}
if (invoice == null) {
setter.accept(null);
holder.warn("无效" + topic + "" + invoiceNumber);
return true;
} else {
if (!Objects.equals(getter.get(), invoice)) {
setter.accept(invoice);
holder.info(topic + "修改为: " + invoice.getCode());
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,419 @@
package com.ecep.contract.manager.cloud.u8.ctx;
import com.ecep.contract.manager.cloud.u8.YongYouU8Service;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.model.Invoice;
import com.ecep.contract.manager.ds.contract.model.*;
import com.ecep.contract.manager.ds.contract.service.PurchaseBillVoucherItemService;
import com.ecep.contract.manager.ds.contract.service.PurchaseBillVoucherService;
import com.ecep.contract.manager.ds.contract.service.PurchaseOrderItemService;
import com.ecep.contract.manager.ds.contract.service.PurchaseOrdersService;
import com.ecep.contract.manager.ds.other.model.Inventory;
import com.ecep.contract.manager.ds.vendor.model.CompanyVendor;
import com.ecep.contract.manager.ds.vendor.model.CompanyVendorEntity;
import com.ecep.contract.manager.ui.MessageHolder;
import lombok.Setter;
import org.springframework.data.domain.Sort;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import static com.ecep.contract.manager.SpringApp.getBean;
public class PurchaseBillVoucherCtx extends AbstractYongYouU8Ctx {
@Setter
private PurchaseOrdersService purchaseOrdersService;
@Setter
private PurchaseOrderItemService purchaseOrderItemService;
@Setter
private PurchaseBillVoucherService purchaseBillVoucherService;
@Setter
private PurchaseBillVoucherItemService purchaseBillVoucherItemService;
InventoryCtx inventoryCtx;
InvoiceCtx invoiceCtx;
ContractCtx contractCtx;
PurchaseOrdersService getPurchaseOrdersService() {
if (purchaseOrdersService == null) {
purchaseOrdersService = getBean(PurchaseOrdersService.class);
}
return purchaseOrdersService;
}
PurchaseBillVoucherService getPurchaseBillVoucherService() {
if (purchaseBillVoucherService == null) {
purchaseBillVoucherService = getBean(PurchaseBillVoucherService.class);
}
return purchaseBillVoucherService;
}
private PurchaseOrderItemService getPurchaseOrderItemService() {
if (purchaseOrderItemService == null) {
purchaseOrderItemService = getBean(PurchaseOrderItemService.class);
}
return purchaseOrderItemService;
}
PurchaseBillVoucherItemService getPurchaseBillVoucherItemService() {
if (purchaseBillVoucherItemService == null) {
purchaseBillVoucherItemService = getBean(PurchaseBillVoucherItemService.class);
}
return purchaseBillVoucherItemService;
}
InventoryCtx getInventoryCtx() {
if (inventoryCtx == null) {
inventoryCtx = new InventoryCtx();
inventoryCtx.from(this);
}
return inventoryCtx;
}
InvoiceCtx getInvoiceCtx() {
if (invoiceCtx == null) {
invoiceCtx = new InvoiceCtx();
invoiceCtx.from(this);
}
return invoiceCtx;
}
ContractCtx getContractCtx() {
if (contractCtx == null) {
contractCtx = new ContractCtx();
contractCtx.from(this);
}
return contractCtx;
}
public void syncByCompany(Company company, MessageHolder holder) {
PurchaseBillVoucherService voucherService = getPurchaseBillVoucherService();
PurchaseBillVoucherItemService voucherItemService = getPurchaseBillVoucherItemService();
List<PurchaseBillVoucher> vouchers = voucherService.findAll((root, q, cb) -> {
return cb.equal(root.get("company"), company);
}, Sort.unsorted());
holder.debug("查找到 " + vouchers.size() + " 条专用发票记录在数据库中");
Map<Integer, PurchaseBillVoucher> voucherMap = vouchers.stream().collect(Collectors.toMap(PurchaseBillVoucher::getRefId, item -> item));
CompanyVendor vendor = getCompanyVendorService().findByCompany(company);
if (vendor != null) {
List<CompanyVendorEntity> entities = getCompanyVendorEntityService().findAllByVendor(vendor);
holder.debug(company.getName() + "" + entities.stream().map(CompanyVendorEntity::getCode).collect(Collectors.joining(", ")) + " 关联项");
for (CompanyVendorEntity entity : entities) {
// 查询 U8 数据库
List<Map<String, Object>> ds = repository.findAllPurchaseBillVoucherByVendorCode(entity.getCode());
holder.debug("供应商关联项: " + entity.getCode() + " 查找到 " + ds.size() + " 条专用发票记录在 " + YongYouU8Service.NAME);
for (Map<String, Object> map : ds) {
Integer pbvid = (Integer) map.get("PBVID");
if (pbvid == 0) {
holder.warn("跳过无效专用发票记录:缺少 PBVID");
continue;
}
holder.debug("发票 #" + pbvid);
PurchaseBillVoucher voucher = voucherMap.get(pbvid);
boolean voucherModified = false;
if (voucher == null) {
voucher = new PurchaseBillVoucher();
voucher.setCompany(company);
voucher.setRefId(pbvid);
voucherMap.put(pbvid, voucher);
voucherModified = true;
holder.info("新增发票记录");
}
if (applyPurchaseBillVoucherDetail(voucher, map, holder.sub("-- | "))) {
voucherModified = true;
}
if (voucherModified) {
voucher = voucherService.save(voucher);
voucherMap.put(pbvid, voucher);
}
}
}
}
List<PurchaseBillVoucherItem> items = voucherItemService.findAll((root, q, cb) -> {
return cb.equal(root.get("voucher").get("company"), company);
}, Sort.unsorted());
// 按 order 分组
Map<PurchaseBillVoucher, Map<Integer, PurchaseBillVoucherItem>> itemMap = items.stream().collect(Collectors.groupingBy(PurchaseBillVoucherItem::getVoucher,
Collectors.toMap(PurchaseBillVoucherItem::getRefId, item -> item)));
for (PurchaseBillVoucher voucher : voucherMap.values()) {
// 查询 U8 数据库
List<Map<String, Object>> ds = repository.findAllPurchaseBillVoucherItemByPbvId(voucher.getRefId());
holder.debug("专用发票#" + voucher.getRefId() + "查找到 " + ds.size() + "条条目记录在 " + YongYouU8Service.NAME);
Map<Integer, PurchaseBillVoucherItem> subItemMap = itemMap.computeIfAbsent(voucher, k -> new HashMap<>());
for (Map<String, Object> map : ds) {
Integer refId = (Integer) map.get("ID");
if (refId == 0) {
holder.warn("跳过无效专用发票记录:缺少 ID");
continue;
}
PurchaseBillVoucherItem item = subItemMap.remove(refId);
boolean itemModified = false;
if (item == null) {
item = new PurchaseBillVoucherItem();
item.setVoucher(voucher);
item.setRefId(refId);
itemModified = true;
holder.info("新增专用发票条目 #" + refId);
}
MessageHolder subHolder = holder.sub("-- | ");
if (applyPurchaseBillVoucherItemDetail(item, map, subHolder)) {
itemModified = true;
}
if (itemModified) {
item = voucherItemService.save(item);
}
}
for (PurchaseBillVoucherItem item : subItemMap.values()) {
holder.info("删除专用发票条目");
voucherItemService.delete(item);
}
}
}
public void syncByContract(Contract contract, MessageHolder holder) {
PurchaseBillVoucherService voucherService = getPurchaseBillVoucherService();
PurchaseBillVoucherItemService voucherItemService = getPurchaseBillVoucherItemService();
List<PurchaseBillVoucherItem> items = voucherItemService.findAll((root, q, cb) -> {
return cb.equal(root.get("contract"), contract);
}, Sort.unsorted());
Map<Integer, PurchaseBillVoucherItem> itemMap = items.stream().collect(Collectors.toMap(PurchaseBillVoucherItem::getRefId, item -> item));
// 查询 U8 数据库
List<Map<String, Object>> ds = repository.findAllPurchaseBillVoucherItemByContractCode(contract.getCode());
holder.debug("合同编号#" + contract.getCode() + "查找到 " + ds.size() + "条发票条目记录在 " + YongYouU8Service.NAME);
for (Map<String, Object> map : ds) {
Integer refId = (Integer) map.get("ID");
if (refId == 0) {
holder.warn("跳过无效专用发票记录:缺少 ID");
continue;
}
PurchaseBillVoucherItem item = itemMap.remove(refId);
boolean itemModified = false;
if (item == null) {
item = new PurchaseBillVoucherItem();
PurchaseBillVoucher voucher = this.updateVoucherByPBVID((Integer) map.get("PBVID"), holder);
item.setVoucher(voucher);
item.setRefId(refId);
itemModified = true;
holder.info("新增专用发票条目 #" + refId);
}
MessageHolder subHolder = holder.sub("-- | ");
if (applyPurchaseBillVoucherItemDetail(item, map, subHolder)) {
itemModified = true;
}
if (itemModified) {
item = voucherItemService.save(item);
}
}
}
private PurchaseBillVoucher updateVoucherByPBVID(Integer pbvId, MessageHolder holder) {
PurchaseBillVoucherService voucherService = getPurchaseBillVoucherService();
PurchaseBillVoucher voucher = voucherService.findByRefId(pbvId);
if (voucher != null) {
return voucher;
}
voucher = new PurchaseBillVoucher();
// 查询 U8 数据库
Map<String, Object> map = repository.findPurchaseBillVoucherById(pbvId);
applyPurchaseBillVoucherDetail(voucher, map, holder.sub("-- | "));
voucher = voucherService.save(voucher);
return voucher;
}
private boolean applyPurchaseBillVoucherDetail(PurchaseBillVoucher voucher, Map<String, Object> map, MessageHolder holder) {
String code = String.valueOf(map.get("PBVID"));
String vendorCode = (String) map.get("cVenCode");
String invoiceNumber = (String) map.get("cPBVCode");
String personCode = (String) map.get("cPersonCode");
String inCode = (String) map.get("cInCode");
Timestamp invoiceDate = (Timestamp) map.get("dPBVDate");
Timestamp voucherDate = (Timestamp) map.get("dVouDate");
BigDecimal amount = (BigDecimal) map.get("iSum");
String maker = (String) map.get("cPBVMaker");
String verifier = (String) map.get("cPBVVerifier");
Timestamp makeTime = (Timestamp) map.get("cmaketime");
Timestamp auditTime = (Timestamp) map.get("dverifysystime");
String description = (String) map.get("cPBVMemo");
boolean modified = false;
holder.debug("发票号码:" + invoiceNumber);
if (updateCompanyByVendorCode(voucher::getCompany, voucher::setCompany, vendorCode, holder, "供应商")) {
modified = true;
}
if (updateInvoice(voucher::getInvoice, voucher::setInvoice, invoiceNumber, holder, "发票")) {
modified = true;
}
if (voucher.getInvoice() != null) {
Invoice invoice = voucher.getInvoice();
if (updateLocalDate(invoice::getInvoiceDate, invoice::setInvoiceDate, voucherDate, holder, "开票日期")) {
invoice = getInvoiceCtx().getInvoiceService().save(invoice);
voucher.setInvoice(invoice);
}
}
if (updateEmployeeByCode(voucher::getEmployee, voucher::setEmployee, personCode, holder, "业务员")) {
modified = true;
}
if (updateEmployeeByName(voucher::getMaker, voucher::setMaker, maker, holder, "制单人")) {
modified = true;
}
if (updateEmployeeByName(voucher::getVerifier, voucher::setVerifier, verifier, holder, "审核人")) {
modified = true;
}
if (updateLocalDateTime(voucher::getMakerDate, voucher::setMakerDate, makeTime, holder, "制单时间")) {
modified = true;
}
if (updateLocalDateTime(voucher::getVerifierDate, voucher::setVerifierDate, auditTime, holder, "审核时间")) {
modified = true;
}
if (!Objects.equals(voucher.getDescription(), description)) {
voucher.setDescription(description);
holder.info("描述修改为: " + description);
modified = true;
}
return modified;
}
private boolean applyPurchaseBillVoucherItemDetail(PurchaseBillVoucherItem item, Map<String, Object> map, MessageHolder holder) {
String code = String.valueOf(map.get("ID"));
String inventoryCode = (String) map.get("cInvCode");
String contractCode = (String) map.get("ContractCode");
String title = (String) map.get("cInvCode");
double quantity = (double) map.get("iPBVQuantity");
BigDecimal taxRate = (BigDecimal) map.get("iOriTaxPrice");
BigDecimal taxPrice = (BigDecimal) map.get("iTaxPrice");
BigDecimal amount = (BigDecimal) map.get("iSum");
// RdsId
// 采购订单条目refId
Integer purchaseOrderItemId = (Integer) map.get("iPOsID");
String description = (String) map.get("cdescription");
Timestamp signDate = (Timestamp) map.get("dSignDate");
boolean modified = false;
holder.debug("条目:" + title + " x " + amount);
if (updateInventory(item::getInventory, item::setInventory, inventoryCode, holder, "商品")) {
modified = true;
}
if (updatePurchaseOrderItem(item::getOrderItem, item::setOrderItem, purchaseOrderItemId, holder, "采购订单条目")) {
modified = true;
}
if (updateContractByContractCode(item::getContract, item::setContract, contractCode, holder, "合同")) {
modified = true;
}
if (updateNumber(item::getPrice, item::setPrice, taxPrice, holder, "含税单价")) {
modified = true;
}
if (updateNumber(item::getQuantity, item::setQuantity, quantity, holder, "数量")) {
modified = true;
}
if (updateAppendText(item::getDescription, item::setDescription, description, holder, "描述")) {
modified = true;
}
return modified;
}
boolean updatePurchaseOrderItem(Supplier<PurchaseOrderItem> getter, Consumer<PurchaseOrderItem> setter, Integer orderItemRefId, MessageHolder holder, String topic) {
PurchaseOrderItem item = null;
if (orderItemRefId != null) {
item = getPurchaseOrderItemService().findByRefId(orderItemRefId);
}
if (item == null) {
setter.accept(null);
holder.warn("无效" + topic + "" + orderItemRefId);
return true;
} else {
if (!Objects.equals(getter.get(), item)) {
setter.accept(item);
holder.info(topic + "修改为: " + item.getRefId());
return true;
}
}
return false;
}
boolean updatePurchaseOrder(Supplier<PurchaseOrder> getter, Consumer<PurchaseOrder> setter, Integer orderRefId, MessageHolder holder, String topic) {
PurchaseOrder order = null;
if (orderRefId != null) {
order = getPurchaseOrdersService().findByRefId(orderRefId);
}
if (order == null) {
setter.accept(null);
holder.warn("无效" + topic + "" + orderRefId);
return true;
} else {
if (!Objects.equals(getter.get(), order)) {
setter.accept(order);
holder.info(topic + "修改为: " + order.getCode());
return true;
}
}
return false;
}
boolean updateContractByContractCode(Supplier<Contract> getter, Consumer<Contract> setter, String contractCode, MessageHolder holder, String topic) {
Contract contract = null;
if (contractCode != null) {
contract = getContractCtx().findContractByCode(contractCode);
}
if (contract == null) {
setter.accept(null);
holder.warn("无效" + topic + "" + contractCode);
return true;
} else {
if (!Objects.equals(getter.get(), contract)) {
setter.accept(contract);
holder.info(topic + "修改为: " + contract.getCode());
return true;
}
}
return false;
}
boolean updateInventory(Supplier<Inventory> getter, Consumer<Inventory> setter, String inventoryCode, MessageHolder holder, String topic) {
return getInventoryCtx().syncInventoryDetailByCode(getter, setter, inventoryCode, holder, topic);
}
private boolean updateInvoice(Supplier<Invoice> getter, Consumer<Invoice> setter, String invoiceNumber, MessageHolder holder, String topic) {
return getInvoiceCtx().updateInvoiceByNumber(getter, setter, invoiceNumber, holder, topic);
}
}

View File

@@ -0,0 +1,318 @@
package com.ecep.contract.manager.cloud.u8.ctx;
import com.ecep.contract.manager.cloud.u8.YongYouU8Service;
import com.ecep.contract.manager.ds.contract.model.Contract;
import com.ecep.contract.manager.ds.contract.model.PurchaseOrder;
import com.ecep.contract.manager.ds.contract.model.PurchaseOrderItem;
import com.ecep.contract.manager.ds.contract.service.ContractService;
import com.ecep.contract.manager.ds.contract.service.PurchaseOrderItemService;
import com.ecep.contract.manager.ds.contract.service.PurchaseOrdersService;
import com.ecep.contract.manager.ds.other.model.Inventory;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.util.NumberUtils;
import lombok.Setter;
import org.hibernate.Hibernate;
import org.springframework.data.domain.Sort;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import static com.ecep.contract.manager.SpringApp.getBean;
public class PurchaseOrderCtx extends AbstractYongYouU8Ctx {
@Setter
private ContractService contractService;
@Setter
private PurchaseOrdersService purchaseOrdersService;
@Setter
private PurchaseOrderItemService purchaseOrderItemService;
InventoryCtx inventoryCtx;
CompanyBankAccountCtx companyBankAccountCtx;
InventoryCtx getInventoryCtx() {
if (inventoryCtx == null) {
inventoryCtx = new InventoryCtx();
inventoryCtx.from(this);
}
return inventoryCtx;
}
CompanyBankAccountCtx getCompanyBankAccountCtx() {
if (companyBankAccountCtx == null) {
companyBankAccountCtx = new CompanyBankAccountCtx();
companyBankAccountCtx.from(this);
}
return companyBankAccountCtx;
}
ContractService getContractService() {
if (contractService == null) {
contractService = getBean(ContractService.class);
}
return contractService;
}
PurchaseOrdersService getPurchaseOrdersService() {
if (purchaseOrdersService == null) {
purchaseOrdersService = getBean(PurchaseOrdersService.class);
}
return purchaseOrdersService;
}
PurchaseOrderItemService getPurchaseOrderItemService() {
if (purchaseOrderItemService == null) {
purchaseOrderItemService = getBean(PurchaseOrderItemService.class);
}
return purchaseOrderItemService;
}
public List<PurchaseOrder> syncByContract(Contract contract, MessageHolder holder) {
PurchaseOrdersService ordersService = getPurchaseOrdersService();
PurchaseOrderItemService itemService = getPurchaseOrderItemService();
List<PurchaseOrder> orders = ordersService.findAll((root, q, cb) -> {
return cb.equal(root.get("contract"), contract);
}, Sort.unsorted());
holder.debug("查找到 " + orders.size() + " 条采购订单记录在数据库中");
Map<Integer, PurchaseOrder> ordersMap = orders.stream().collect(Collectors.toMap(PurchaseOrder::getRefId, item -> item));
List<PurchaseOrderItem> items = itemService.findAll((root, q, cb) -> {
return cb.equal(root.get("order").get("contract"), contract);
}, Sort.unsorted());
// 按 order 分组
Map<PurchaseOrder, Map<Integer, PurchaseOrderItem>> itemMap = items.stream().collect(Collectors.groupingBy(PurchaseOrderItem::getOrder,
Collectors.toMap(PurchaseOrderItem::getRefId, item -> item)));
// 查询 U8 数据库
List<Map<String, Object>> ds = repository.findAllPurchaseOrderItemByContractCode(contract.getCode());
holder.debug("查找到 " + ds.size() + " 条采购订单条目记录在 " + YongYouU8Service.NAME);
Map<PurchaseOrder, List<PurchaseOrderItem>> updateMap = new HashMap<>();
for (Map<String, Object> map : ds) {
Integer poId = (Integer) map.get("POID");
if (poId == 0) {
holder.warn("跳过无效采购订单记录:缺少 POID");
continue;
}
PurchaseOrder order = ordersMap.get(poId);
if (order == null) {
order = new PurchaseOrder();
order.setContract(contract);
order.setRefId(poId);
order = ordersService.save(order);
ordersMap.put(poId, order);
holder.info("新增采购订单 #" + poId);
}
}
for (Map<String, Object> map : ds) {
// holder.debug("条目:" + map.toString());
Integer poId = (Integer) map.get("POID");
if (poId == 0) {
holder.warn("跳过无效采购订单记录:缺少 POID");
continue;
}
PurchaseOrder order = ordersMap.get(poId);
boolean itemModified = false;
List<PurchaseOrderItem> updates = updateMap.computeIfAbsent(order, k -> new ArrayList<>());
// 获取条目标识并处理 null
Integer refId = (Integer) map.get("ID");
if (poId == null) {
holder.warn("跳过条目:订单 " + poId + " 缺少 ID");
continue;
}
Map<Integer, PurchaseOrderItem> subItemMap = itemMap.get(order);
PurchaseOrderItem item = null;
if (subItemMap != null) {
item = subItemMap.remove(refId);
}
if (item == null) {
item = new PurchaseOrderItem();
item.setOrder(order);
item.setRefId(refId);
itemModified = true;
holder.info("新增采购订单条目 #" + refId);
}
MessageHolder subHolder = holder.sub("---| ");
if (applyPurchaseOrderItemDetail(item, map, subHolder)) {
itemModified = true;
}
if (itemModified) {
item = itemService.save(item);
}
updates.add(item);
}
for (PurchaseOrder order : updateMap.keySet()) {
if (applyPurchaseOrderDetail(order, repository.queryPurchaseOrderDetail(order.getRefId()), holder)) {
ordersService.save(order);
}
}
if (!itemMap.isEmpty()) {
for (Map<Integer, PurchaseOrderItem> subMap : itemMap.values()) {
if (!subMap.isEmpty()) {
for (PurchaseOrderItem item : subMap.values()) {
holder.info("删除采购订单条目");
itemService.delete(item);
}
}
}
for (PurchaseOrder order : updateMap.keySet()) {
itemMap.remove(order);
}
if (!itemMap.isEmpty()) {
holder.info("剩余 " + itemMap.size() + " 个采购订单条目");
}
}
return new ArrayList<>(updateMap.keySet());
}
private boolean applyPurchaseOrderDetail(PurchaseOrder order, Map<String, Object> map, MessageHolder holder) {
String code = (String) map.get("cPOID");
String venBank = (String) map.get("cVenBank");
String venBankAccount = (String) map.get("cVenAccount");
String venCode = (String) map.get("cVenCode");
String memo = (String) map.get("cMemo");
boolean modified = false;
if (!Objects.equals(order.getCode(), code)) {
order.setCode(code);
holder.info("订单编号更新为 " + code);
modified = true;
}
if (updateEmployeeByCode(order::getEmployee, order::setEmployee, (String) map.get("cPersonCode"), holder, "业务员")) {
modified = true;
}
if (updateEmployeeByName(order::getMaker, order::setMaker, (String) map.get("cMaker"), holder, "制单人")) {
modified = true;
}
if (updateEmployeeByName(order::getVerifier, order::setVerifier, (String) map.get("cVerifier"), holder, "审核人")) {
modified = true;
}
if (updateEmployeeByName(order::getCloser, order::setCloser, (String) map.get("cCloser"), holder, "订单关闭人")) {
modified = true;
}
if (updateLocalDateTime(order::getMakerDate, order::setMakerDate, (Timestamp) map.get("cmaketime"), holder, "制单日期")) {
modified = true;
}
if (updateLocalDateTime(order::getModifyDate, order::setModifyDate, (Timestamp) map.get("cModifyTime"), holder, "修改日期")) {
modified = true;
}
if (updateLocalDateTime(order::getVerifierDate, order::setVerifierDate, (Timestamp) map.get("cAuditTime"), holder, "审核日期")) {
modified = true;
}
if (updateLocalDateTime(order::getCloserDate, order::setCloserDate, (Timestamp) map.get("dCloseTime"), holder, "关闭日期")) {
modified = true;
}
if (!Objects.equals(order.getVendorCode(), venCode)) {
order.setVendorCode(venCode);
holder.info("供方代码修改为: " + venCode);
modified = true;
}
if (!Objects.equals(order.getDescription(), memo)) {
order.setDescription(memo);
holder.info("描述修改为: " + memo);
modified = true;
}
updateCompanyBankAccount(order.getContract(), venBank, venBankAccount, holder);
return modified;
}
private void updateCompanyBankAccount(Contract contract, String bank, String bankAccount, MessageHolder holder) {
if (contract == null) {
return;
}
if (!Hibernate.isInitialized(contract)) {
contract = getContractService().findById(contract.getId());
}
getCompanyBankAccountCtx().updateBankAccount(contract.getCompany(), bank, bankAccount, holder);
}
private boolean applyPurchaseOrderItemDetail(PurchaseOrderItem item, Map<String, Object> map, MessageHolder holder) {
Integer refId = (Integer) map.get("ID");
String inventoryCode = (String) map.get("cInvCode");
String contractCode = (String) map.get("ContractCode");
String title = (String) map.get("cInvCode");
double quantity = (double) map.get("iQuantity");
BigDecimal taxRate = (BigDecimal) map.get("iPerTaxRate");
BigDecimal taxPrice = (BigDecimal) map.get("iTaxPrice");
double exclusiveTaxPrice = (double) map.get("iUnitPrice");
BigDecimal amount = (BigDecimal) map.get("iSum");
Timestamp arriveDate = (Timestamp) map.get("dArriveDate");
boolean modified = false;
holder.debug("条目:" + title + " x " + amount);
if (updateInventory(item::getInventory, item::setInventory, inventoryCode, holder, "商品")) {
modified = true;
}
if (!Objects.equals(item.getRefId(), refId)) {
item.setRefId(refId);
holder.info("RefId修改为: " + refId);
modified = true;
}
if (!NumberUtils.equals(item.getExclusiveTaxPrice(), exclusiveTaxPrice)) {
item.setExclusiveTaxPrice(exclusiveTaxPrice);
holder.info("不含税单价修改为: " + exclusiveTaxPrice);
modified = true;
}
if (!NumberUtils.equals(item.getPrice(), taxPrice.doubleValue())) {
item.setPrice(taxPrice.doubleValue());
holder.info("含税单价修改为: " + taxPrice.doubleValue());
modified = true;
}
if (!NumberUtils.equals(item.getTaxRate(), taxRate.doubleValue())) {
item.setTaxRate(taxRate.doubleValue());
holder.info("税率修改为: " + taxRate);
modified = true;
}
if (!NumberUtils.equals(item.getQuantity(), quantity)) {
item.setQuantity(quantity);
holder.info("数量修改为: " + quantity);
modified = true;
}
if (updateLocalDate(item::getArriveDate, item::setArriveDate, (Timestamp) map.get("dArriveDate"), holder, "开始日期")) {
modified = true;
}
if (!Objects.equals(item.getDescription(), contractCode)) {
item.setDescription(contractCode);
holder.info("描述修改为: " + contractCode);
modified = true;
}
return modified;
}
boolean updateInventory(Supplier<Inventory> getter, Consumer<Inventory> setter, String inventoryCode, MessageHolder holder, String topic) {
return getInventoryCtx().syncInventoryDetailByCode(getter, setter, inventoryCode, holder, topic);
}
}

View File

@@ -0,0 +1,85 @@
package com.ecep.contract.manager.cloud.u8.ctx;
import com.ecep.contract.manager.ds.contract.model.PurchaseSettlementVoucher;
import com.ecep.contract.manager.ds.contract.model.PurchaseSettlementVoucherItem;
import com.ecep.contract.manager.ds.other.model.Inventory;
import com.ecep.contract.manager.ui.MessageHolder;
import java.sql.Timestamp;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class PurchaseSettlementVoucherCtx extends AbstractYongYouU8Ctx {
InventoryCtx inventoryCtx;
InventoryCtx getInventoryCtx() {
if (inventoryCtx == null) {
inventoryCtx = new InventoryCtx();
inventoryCtx.from(this);
}
return inventoryCtx;
}
private boolean applyPurchaseSettlementVoucherDetail(PurchaseSettlementVoucher voucher, Map<String, Object> map, MessageHolder holder) {
String code = (String) map.get("cSVCode");
String vendorCode = (String) map.get("cVenCode");
String personCode = (String) map.get("cPersonCode");
double taxRate = (double) map.get("iTaxRate");
String maker = (String) map.get("cMaker");
Timestamp date = (Timestamp) map.get("dSVDate");
String description = (String) map.get("cSVMemo");
boolean modified = false;
if (updateText(voucher::getCode, voucher::setCode, code, holder, "编号:")) {
modified = true;
}
if (updateCompanyByVendorCode(voucher::getCompany, voucher::setCompany, vendorCode, holder, "供应商")) {
modified = true;
}
if (updateEmployeeByCode(voucher::getEmployee, voucher::setEmployee, personCode, holder, "业务员")) {
modified = true;
}
if (updateEmployeeByName(voucher::getMaker, voucher::setMaker, maker, holder, "制单人")) {
modified = true;
}
if (updateLocalDate(voucher::getDate, voucher::setDate, date, holder, "日期:")) {
modified = true;
}
if (updateAppendText(voucher::getDescription, voucher::setDescription, description, holder, "描述")) {
modified = true;
}
return modified;
}
private boolean applyPurchaseSettlementVoucherItemDetail(PurchaseSettlementVoucherItem item, Map<String, Object> map, MessageHolder holder) {
String inventoryCode = (String) map.get("cInvCode");
String pivCode = (String) map.get("cPIVCode");
String accountant = (String) map.get("cbAccounter");
Integer rdsID = (Integer) map.get("iRdsID");
double quantity = (double) map.get("iPBVQuantity");
String description = (String) map.get("cbMemo");
boolean modified = false;
if (updateInventory(item::getInventory, item::setInventory, inventoryCode, holder, "商品")) {
modified = true;
}
if (updateEmployeeByName(item::getAccountant, item::setAccountant, accountant, holder, "会计师")) {
modified = true;
}
if (updateNumber(item::getQuantity, item::setQuantity, quantity, holder, "数量")) {
modified = true;
}
if (updateAppendText(item::getDescription, item::setDescription, description, holder, "描述")) {
modified = true;
}
return modified;
}
boolean updateInventory(Supplier<Inventory> getter, Consumer<Inventory> setter, String inventoryCode, MessageHolder holder, String topic) {
return getInventoryCtx().syncInventoryDetailByCode(getter, setter, inventoryCode, holder, topic);
}
}

View File

@@ -0,0 +1,363 @@
package com.ecep.contract.manager.cloud.u8.ctx;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.u8.YongYouU8Service;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.contract.model.Contract;
import com.ecep.contract.manager.ds.contract.model.SalesBillVoucher;
import com.ecep.contract.manager.ds.contract.model.SalesBillVoucherItem;
import com.ecep.contract.manager.ds.contract.model.SalesOrder;
import com.ecep.contract.manager.ds.contract.service.ContractService;
import com.ecep.contract.manager.ds.contract.service.SaleOrdersService;
import com.ecep.contract.manager.ds.contract.service.SalesBillVoucherService;
import com.ecep.contract.manager.ds.customer.model.CompanyCustomer;
import com.ecep.contract.manager.ds.customer.model.CompanyCustomerEntity;
import com.ecep.contract.manager.ds.other.model.Inventory;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.util.NumberUtils;
import lombok.Setter;
import org.hibernate.Hibernate;
import org.springframework.data.domain.Sort;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import static com.ecep.contract.manager.SpringApp.getBean;
public class SalesBillVoucherCtx extends AbstractYongYouU8Ctx {
@Setter
private ContractService contractService;
@Setter
private SaleOrdersService saleOrdersService;
@Setter
private SalesBillVoucherService salesBillVoucherService;
InventoryCtx inventoryCtx;
ContractService getContractService() {
if (contractService == null) {
contractService = getBean(ContractService.class);
}
return contractService;
}
SaleOrdersService getSaleOrdersService() {
if (saleOrdersService == null) {
saleOrdersService = getBean(SaleOrdersService.class);
}
return saleOrdersService;
}
SalesBillVoucherService getSalesBillVoucherService() {
if (salesBillVoucherService == null) {
salesBillVoucherService = SpringApp.getBean(SalesBillVoucherService.class);
}
return salesBillVoucherService;
}
InventoryCtx getInventoryCtx() {
if (inventoryCtx == null) {
inventoryCtx = new InventoryCtx();
inventoryCtx.from(this);
}
return inventoryCtx;
}
public void syncByCompany(Company company, MessageHolder holder) {
List<SalesBillVoucher> vouchers = salesBillVoucherService.findAll((root, q, cb) -> {
return cb.equal(root.get("company"), company);
}, Sort.unsorted());
holder.debug("查找到 " + vouchers.size() + " 条专用发票记录在数据库中");
Map<Integer, SalesBillVoucher> voucherMap = vouchers.stream().collect(Collectors.toMap(SalesBillVoucher::getRefId, item -> item));
CompanyCustomer customer = getCompanyCustomerService().findByCompany(company);
if (customer != null) {
List<CompanyCustomerEntity> entities = getCompanyCustomerEntityService().findAllByCustomer(customer);
for (CompanyCustomerEntity entity : entities) {
// 查询 U8 数据库
List<Map<String, Object>> ds = repository.findAllSalesBillVoucherByCustomerCode(entity.getCode());
holder.debug("查找" + entity.getCode() + "" + ds.size() + " 条专用发票记录在 " + YongYouU8Service.NAME);
for (Map<String, Object> map : ds) {
Integer sbvid = (Integer) map.get("SBVID");
if (sbvid == 0) {
holder.warn("跳过无效专用发票记录:缺少 SBVID");
continue;
}
SalesBillVoucher voucher = voucherMap.get(sbvid);
boolean voucherModified = false;
if (voucher == null) {
voucher = new SalesBillVoucher();
voucher.setCompany(company);
voucher.setRefId(sbvid);
voucherMap.put(sbvid, voucher);
voucherModified = true;
holder.info("新增专用发票记录 #" + sbvid);
}
if (applySalesBillVoucherDetail(voucher, map, holder)) {
voucherModified = true;
}
if (voucherModified) {
voucher = salesBillVoucherService.save(voucher);
voucherMap.put(sbvid, voucher);
}
}
}
}
List<SalesBillVoucherItem> items = salesBillVoucherService.findAllItems((root, q, cb) -> {
return cb.equal(root.get("voucher").get("company"), company);
}, Sort.unsorted());
// 按 order 分组
Map<SalesBillVoucher, Map<Integer, SalesBillVoucherItem>> itemMap = items.stream().collect(Collectors.groupingBy(SalesBillVoucherItem::getVoucher,
Collectors.toMap(SalesBillVoucherItem::getRefId, item -> item)));
for (SalesBillVoucher voucher : voucherMap.values()) {
// 查询 U8 数据库
List<Map<String, Object>> ds = repository.findAllSalesBillVoucherItemBySBVID(voucher.getRefId());
holder.debug("专用发票#" + voucher.getRefId() + "查找到 " + ds.size() + "条条目记录在 " + YongYouU8Service.NAME);
Map<Integer, SalesBillVoucherItem> subItemMap = itemMap.computeIfAbsent(voucher, k -> new HashMap<>());
for (Map<String, Object> map : ds) {
Integer refId = (Integer) map.get("ID");
if (refId == 0) {
holder.warn("跳过无效专用发票记录:缺少 ID");
continue;
}
SalesBillVoucherItem item = subItemMap.remove(refId);
boolean itemModified = false;
if (item == null) {
item = new SalesBillVoucherItem();
item.setVoucher(voucher);
item.setRefId(refId);
itemModified = true;
holder.info("新增专用发票条目 #" + refId);
}
MessageHolder subHolder = holder.sub("---| ");
if (applySalesBillVoucherItemDetail(item, map, subHolder)) {
itemModified = true;
}
if (itemModified) {
item = salesBillVoucherService.save(item);
}
}
for (SalesBillVoucherItem item : subItemMap.values()) {
holder.info("删除无效专用发票条目");
salesBillVoucherService.delete(item);
}
}
}
public void syncBySalesOrder(SalesOrder order, MessageHolder holder) {
SalesBillVoucherService voucherService = getSalesBillVoucherService();
List<SalesBillVoucher> vouchers = voucherService.findAll((root, q, cb) -> {
return cb.equal(root.get("order"), order);
}, Sort.unsorted());
holder.debug("查找到 " + vouchers.size() + " 条专用发票记录在数据库中");
Map<Integer, SalesBillVoucher> voucherMap = vouchers.stream().collect(Collectors.toMap(SalesBillVoucher::getRefId, item -> item));
{
// 查询 U8 数据库
List<Map<String, Object>> ds = repository.findAllSalesBillVoucherBySalesOrderCode(order.getCode());
holder.debug("查找" + order.getCode() + "" + ds.size() + " 条专用发票记录在 " + YongYouU8Service.NAME);
for (Map<String, Object> map : ds) {
Integer sbvid = (Integer) map.get("SBVID");
if (sbvid == 0) {
holder.warn("跳过无效专用发票记录:缺少 SBVID");
continue;
}
SalesBillVoucher voucher = voucherMap.get(sbvid);
boolean voucherModified = false;
if (voucher == null) {
voucher = new SalesBillVoucher();
Contract contract = order.getContract();
if (!Hibernate.isInitialized(contract)) {
contract = getContractService().findById(contract.getId());
}
voucher.setCompany(contract.getCompany());
voucher.setRefId(sbvid);
voucherMap.put(sbvid, voucher);
voucherModified = true;
holder.info("新增专用发票记录 #" + sbvid);
}
if (applySalesBillVoucherDetail(voucher, map, holder)) {
voucherModified = true;
}
if (voucherModified) {
voucher = voucherService.save(voucher);
voucherMap.put(sbvid, voucher);
}
}
}
List<SalesBillVoucherItem> items = voucherService.findAllItems((root, q, cb) -> {
return cb.equal(root.get("voucher").get("order"), order);
}, Sort.unsorted());
// 按 order 分组
Map<SalesBillVoucher, Map<Integer, SalesBillVoucherItem>> itemMap = items.stream().collect(Collectors.groupingBy(SalesBillVoucherItem::getVoucher,
Collectors.toMap(SalesBillVoucherItem::getRefId, item -> item)));
for (SalesBillVoucher voucher : voucherMap.values()) {
// 查询 U8 数据库
List<Map<String, Object>> ds = repository.findAllSalesBillVoucherItemBySBVID(voucher.getRefId());
holder.debug("专用发票#" + voucher.getRefId() + "查找到 " + ds.size() + "条条目记录在 " + YongYouU8Service.NAME);
Map<Integer, SalesBillVoucherItem> subItemMap = itemMap.computeIfAbsent(voucher, k -> new HashMap<>());
for (Map<String, Object> map : ds) {
Integer refId = (Integer) map.get("AutoID");
if (refId == 0) {
holder.warn("跳过无效专用发票记录:缺少 AutoID");
continue;
}
SalesBillVoucherItem item = subItemMap.remove(refId);
boolean itemModified = false;
if (item == null) {
item = new SalesBillVoucherItem();
item.setVoucher(voucher);
item.setRefId(refId);
itemModified = true;
holder.info("新增专用发票条目 #" + refId);
}
MessageHolder subHolder = holder.sub("---| ");
if (applySalesBillVoucherItemDetail(item, map, subHolder)) {
itemModified = true;
}
if (itemModified) {
item = voucherService.save(item);
}
}
for (SalesBillVoucherItem item : subItemMap.values()) {
holder.info("删除无效专用发票条目");
voucherService.delete(item);
}
}
}
private boolean applySalesBillVoucherDetail(SalesBillVoucher voucher, Map<String, Object> map, MessageHolder holder) {
String code = String.valueOf(map.get("SBVID"));
String customerCode = (String) map.get("cCusCode");
String salesOrderCode = (String) map.get("cSOCode");
String personCode = (String) map.get("cPersonCode");
String inCode = (String) map.get("cDLCode");
Timestamp billDate = (Timestamp) map.get("dDate");
String maker = (String) map.get("cMaker");
String checker = (String) map.get("cChecker");
String modifier = (String) map.get("cmodifier");
String verifier = (String) map.get("cVerifier");
Timestamp makeTime = (Timestamp) map.get("cmaketime");
Timestamp verifyTime = (Timestamp) map.get("dverifysystime");
Timestamp modifyTime = (Timestamp) map.get("dmodifysystime");
String description = (String) map.get("cMemo");
boolean modified = false;
holder.debug("条目:" + code + " x " + salesOrderCode);
if (updateCompanyByCustomerCode(voucher::getCompany, voucher::setCompany, customerCode, holder, "客户")) {
modified = true;
}
SalesOrder salesOrder = null;
if (StringUtils.hasText(salesOrderCode)) {
salesOrder = getSaleOrdersService().findByCode(salesOrderCode);
}
if (salesOrder == null) {
voucher.setOrder(null);
holder.warn("无效销售订单:" + salesOrderCode);
modified = true;
} else {
if (!Objects.equals(voucher.getOrder(), salesOrder)) {
voucher.setOrder(salesOrder);
holder.info("销售订单修改为: " + salesOrder.getCode());
modified = true;
}
}
if (updateEmployeeByCode(voucher::getEmployee, voucher::setEmployee, personCode, holder, "业务员")) {
modified = true;
}
if (updateEmployeeByName(voucher::getMaker, voucher::setMaker, maker, holder, "制单人")) {
modified = true;
}
if (updateEmployeeByName(voucher::getVerifier, voucher::setVerifier, verifier, holder, "审核人")) {
modified = true;
}
if (updateLocalDateTime(voucher::getMakerDate, voucher::setMakerDate, makeTime, holder, "制单时间")) {
modified = true;
}
if (updateLocalDateTime(voucher::getVerifierDate, voucher::setVerifierDate, verifyTime, holder, "审核时间")) {
modified = true;
}
if (!Objects.equals(voucher.getDescription(), description)) {
voucher.setDescription(description);
holder.info("描述修改为: " + description);
modified = true;
}
return modified;
}
private boolean applySalesBillVoucherItemDetail(SalesBillVoucherItem item, Map<String, Object> map, MessageHolder holder) {
String code = String.valueOf(map.get("ID"));
String inventoryCode = (String) map.get("cInvCode");
String contractCode = (String) map.get("ContractCode");
String title = (String) map.get("cInvCode");
double quantity = (double) map.get("iQuantity");
double taxRate = (double) map.get("iTaxRate");
double taxPrice = (double) map.get("iTaxUnitPrice");
BigDecimal amount = (BigDecimal) map.get("iSum");
Timestamp signDate = (Timestamp) map.get("dSignDate");
boolean modified = false;
holder.debug("条目:" + title + " x " + amount);
if (updateInventory(item::getInventory, item::setInventory, inventoryCode, holder, "商品")) {
modified = true;
}
if (!NumberUtils.equals(item.getPrice(), taxPrice)) {
item.setPrice(taxPrice);
holder.info("含税单价修改为: " + taxPrice);
modified = true;
}
if (!NumberUtils.equals(item.getQuantity(), quantity)) {
item.setQuantity(quantity);
holder.info("数量修改为: " + quantity);
modified = true;
}
if (!Objects.equals(item.getDescription(), contractCode)) {
item.setDescription(contractCode);
holder.info("描述修改为: " + contractCode);
modified = true;
}
return modified;
}
boolean updateInventory(Supplier<Inventory> getter, Consumer<Inventory> setter, String inventoryCode, MessageHolder holder, String topic) {
return getInventoryCtx().syncInventoryDetailByCode(getter, setter, inventoryCode, holder, topic);
}
}

View File

@@ -0,0 +1,257 @@
package com.ecep.contract.manager.cloud.u8.ctx;
import com.ecep.contract.manager.cloud.u8.YongYouU8Service;
import com.ecep.contract.manager.ds.contract.model.Contract;
import com.ecep.contract.manager.ds.contract.model.SalesOrder;
import com.ecep.contract.manager.ds.contract.model.SalesOrderItem;
import com.ecep.contract.manager.ds.contract.service.SaleOrdersService;
import com.ecep.contract.manager.ds.contract.service.SalesOrderItemService;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.util.NumberUtils;
import lombok.Setter;
import org.springframework.data.domain.Sort;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;
import static com.ecep.contract.manager.SpringApp.getBean;
public class SalesOrderCtx extends AbstractYongYouU8Ctx {
@Setter
private SaleOrdersService saleOrdersService;
@Setter
private SalesOrderItemService orderItemService;
SaleOrdersService getSaleOrdersService() {
if (saleOrdersService == null) {
saleOrdersService = getBean(SaleOrdersService.class);
}
return saleOrdersService;
}
SalesOrderItemService getOrderItemService() {
if (orderItemService == null) {
orderItemService = getBean(SalesOrderItemService.class);
}
return orderItemService;
}
public List<SalesOrder> syncByContract(Contract contract, MessageHolder holder) {
SaleOrdersService saleOrdersService = getSaleOrdersService();
SalesOrderItemService orderItemService = getOrderItemService();
List<SalesOrder> orders = saleOrdersService.findAll((root, q, cb) -> {
return cb.equal(root.get("contract"), contract);
}, Sort.unsorted());
holder.debug("查找到 " + orders.size() + " 条销售订单记录在数据库中");
Map<String, SalesOrder> ordersMap = orders.stream().collect(Collectors.toMap(SalesOrder::getCode, item -> item));
List<SalesOrderItem> items = orderItemService.findAll((root, q, cb) -> {
return cb.equal(root.get("order").get("contract"), contract);
}, Sort.unsorted());
// 按 order 分组
Map<SalesOrder, Map<String, SalesOrderItem>> itemMap = items.stream().collect(Collectors.groupingBy(SalesOrderItem::getOrder,
Collectors.toMap(SalesOrderItem::getCode, item -> item)));
// 查询 U8 数据库
List<Map<String, Object>> ds = repository.findAllSalesOrderItemByContractCode(contract.getCode());
holder.debug("查找到 " + ds.size() + " 条销售订单条目记录在 " + YongYouU8Service.NAME);
Map<SalesOrder, List<SalesOrderItem>> updateMap = new HashMap<>();
for (Map<String, Object> map : ds) {
String orderCode = Optional.ofNullable(map.get("cSOCode")).map(Object::toString).orElse("");
if (orderCode.isEmpty()) {
holder.warn("跳过无效销售订单记录:缺少 cSOCode");
continue;
}
SalesOrder order = ordersMap.get(orderCode);
if (order == null) {
order = new SalesOrder();
order.setContract(contract);
order.setCode(orderCode);
order = saleOrdersService.save(order);
ordersMap.put(orderCode, order);
holder.info("新增销售订单 #" + orderCode);
}
}
for (Map<String, Object> map : ds) {
// holder.debug("条目:" + map.toString());
String orderCode = Optional.ofNullable(map.get("cSOCode")).map(Object::toString).orElse("");
if (orderCode.isEmpty()) {
holder.warn("跳过无效销售订单记录:缺少 cSOCode");
continue;
}
SalesOrder order = ordersMap.get(orderCode);
boolean itemModified = false;
List<SalesOrderItem> updates = updateMap.computeIfAbsent(order, k -> new ArrayList<>());
// 获取条目标识并处理 null
String refId = Optional.ofNullable(map.get("iSOsID")).map(Object::toString).orElse("");
if (refId.isEmpty()) {
holder.warn("跳过条目:订单 " + orderCode + " 缺少 iSOsID");
continue;
}
Map<String, SalesOrderItem> subItemMap = itemMap.get(order);
SalesOrderItem item = null;
if (subItemMap != null) {
item = subItemMap.remove(refId);
}
if (item == null) {
item = new SalesOrderItem();
item.setOrder(order);
item.setCode(refId);
itemModified = true;
holder.info("新增销售订单条目 #" + refId);
}
MessageHolder subHolder = holder.sub("---| ");
if (applySaleOrderItemDetail(item, map, subHolder)) {
itemModified = true;
}
if (itemModified) {
item = orderItemService.save(item);
}
updates.add(item);
}
for (SalesOrder order : updateMap.keySet()) {
holder.debug("销售订单 #" + order.getCode());
if (applySalesOrderDetail(order, repository.querySalesOrderDetail(order.getCode()), holder)) {
saleOrdersService.save(order);
}
}
if (!itemMap.isEmpty()) {
for (Map<String, SalesOrderItem> subMap : itemMap.values()) {
if (!subMap.isEmpty()) {
for (SalesOrderItem item : subMap.values()) {
holder.info("删除销售订单条目");
orderItemService.delete(item);
}
}
}
for (SalesOrder order : updateMap.keySet()) {
itemMap.remove(order);
}
if (!itemMap.isEmpty()) {
holder.info("剩余 " + itemMap.size() + " 个销售订单条目");
}
}
return new ArrayList<>(updateMap.keySet());
}
private boolean applySalesOrderDetail(SalesOrder order, Map<String, Object> map, MessageHolder holder) {
String code = (String) map.get("cSOCode");
String cCloser = (String) map.get("cCloser");
String memo = (String) map.get("cMemo");
boolean modified = false;
if (!Objects.equals(order.getCode(), code)) {
order.setCode(code);
holder.info("订单编号更新为 " + code);
modified = true;
}
if (updateEmployeeByCode(order::getEmployee, order::setEmployee, (String) map.get("cPersonCode"), holder, "业务员")) {
modified = true;
}
if (updateEmployeeByName(order::getMaker, order::setMaker, (String) map.get("cMaker"), holder, "制单人")) {
modified = true;
}
if (updateEmployeeByName(order::getVerifier, order::setVerifier, (String) map.get("cVerifier"), holder, "审核人")) {
modified = true;
}
if (updateLocalDate(order::getMakerDate, order::setMakerDate, (Timestamp) map.get("dcreatesystime"), holder, "制单日期")) {
modified = true;
}
if (updateLocalDate(order::getVerifierDate, order::setVerifierDate, (Timestamp) map.get("dverifysystime"), holder, "审核日期")) {
modified = true;
}
if (!Objects.equals(order.getDescription(), memo)) {
order.setDescription(memo);
holder.info("描述修改为: " + memo);
modified = true;
}
return modified;
}
private boolean applySaleOrderItemDetail(SalesOrderItem item, Map<String, Object> map, MessageHolder holder) {
String code = String.valueOf(map.get("iSOsID"));
String spec = (String) map.get("cInvName");
String title = (String) map.get("cInvName");
double quantity = (double) map.get("iQuantity");
double taxRate = (double) map.get("iTaxRate");
double taxPrice = (double) map.get("iTaxUnitPrice");
double exclusiveTaxPrice = (double) map.get("iUnitPrice");
BigDecimal amount = (BigDecimal) map.get("iSum");
String memo = (String) map.get("cMemo");
boolean modified = false;
holder.debug("条目:" + title + " x " + amount);
if (!Objects.equals(item.getCode(), code)) {
item.setCode(code);
holder.info("代码修改为: " + code);
modified = true;
}
if (!Objects.equals(item.getName(), title)) {
item.setName(title);
holder.info("名称修改为: " + title);
modified = true;
}
if (!NumberUtils.equals(item.getExclusiveTaxPrice(), exclusiveTaxPrice)) {
item.setExclusiveTaxPrice(exclusiveTaxPrice);
holder.info("不含税单价修改为: " + exclusiveTaxPrice);
modified = true;
}
if (!NumberUtils.equals(item.getPrice(), taxPrice)) {
item.setPrice(taxPrice);
holder.info("含税单价修改为: " + taxPrice);
modified = true;
}
if (!NumberUtils.equals(item.getTaxRate(), taxRate)) {
item.setTaxRate(taxRate);
holder.info("税率修改为: " + taxRate);
modified = true;
}
if (!NumberUtils.equals(item.getQuantity(), quantity)) {
item.setQuantity(quantity);
holder.info("数量修改为: " + quantity);
modified = true;
}
if (updateLocalDate(item::getStartDate, item::setStartDate, (Timestamp) map.get("dPreDate"), holder, "开始日期")) {
modified = true;
}
if (updateLocalDate(item::getEndDate, item::setEndDate, (Timestamp) map.get("dPreMoDate"), holder, "结束日期")) {
modified = true;
}
if (!Objects.equals(item.getDescription(), memo)) {
item.setDescription(memo);
modified = true;
}
return modified;
}
}

View File

@@ -0,0 +1,325 @@
package com.ecep.contract.manager.cloud.u8.ctx;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.old.OldVersionService;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.vendor.model.CompanyVendor;
import com.ecep.contract.manager.ds.vendor.model.CompanyVendorEntity;
import com.ecep.contract.manager.ds.vendor.model.VendorCatalog;
import com.ecep.contract.manager.ds.vendor.service.CompanyVendorEntityService;
import com.ecep.contract.manager.ds.vendor.service.CompanyVendorService;
import com.ecep.contract.manager.ui.MessageHolder;
import lombok.Setter;
import org.hibernate.Hibernate;
import org.springframework.util.StringUtils;
import java.time.Instant;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class VendorCtx extends AbstractYongYouU8Ctx {
private static final String AUTO_CREATE_VENDOR_AFTER = "cloud.u8.auto-create-vendor-after";
@Setter
private CompanyVendorService companyVendorService;
@Setter
private CompanyCtx companyCtx;
@Setter
private ContractCtx contractCtx;
@Setter
private CompanyBankAccountCtx companyBankAccountCtx;
public CompanyCtx getCompanyCtx() {
if (companyCtx == null) {
companyCtx = new CompanyCtx();
companyCtx.from(this);
}
return companyCtx;
}
ContractCtx getContractCtx() {
if (contractCtx == null) {
contractCtx = new ContractCtx();
contractCtx.from(this);
}
return contractCtx;
}
CompanyBankAccountCtx getCompanyBankAccountCtx() {
if (companyBankAccountCtx == null) {
companyBankAccountCtx = new CompanyBankAccountCtx();
companyBankAccountCtx.from(this);
}
return companyBankAccountCtx;
}
/**
* 更新供应商相关项(相关项是 U8 系统中的 Vendor 表数据,因为同一个公司有多个相关项,因此需要一个一对多的关系来处理)详情
*
* @param item 供应商相关项
* @param unitCode 供应商相关项编码
* @param holder 消息
*/
public CompanyVendorEntity updateVendorEntityDetailByCode(CompanyVendorEntity item, String unitCode, MessageHolder holder) {
if (applyEntityDetail(item, repository.findVendorByVendCode(unitCode), holder)) {
item = save(item);
}
return item;
}
public boolean applyEntityDetail(CompanyVendorEntity item, Map<String, Object> map, MessageHolder holder) {
if (map == null || map.isEmpty()) {
holder.warn("Vendor 中未检索到供应商数据");
return false;
}
String name = (String) map.get("cVenName");
String abbName = (String) map.get("cVenAbbName");
String venCode = (String) map.get("cVenCode");
String classCode = (String) map.get("cVCCode");
String createPerson = (String) map.get("cCreatePerson");
String modifyPerson = (String) map.get("cModifyPerson");
java.sql.Date devDate = (java.sql.Date) map.get("devDate");
java.sql.Timestamp modifyDate = (java.sql.Timestamp) map.get("dModifyDate");
java.sql.Timestamp createDatetime = (java.sql.Timestamp) map.get("dVenCreateDatetime");
String bank = (String) map.get("cVenBank");
String bankAccount = (String) map.get("cVenAccount");
String address = (String) map.get("cVenAddress");
String phone = (String) map.get("cVenPhone");
String person = (String) map.get("cVenPerson");
boolean modified = false;
if (updateText(item::getName, item::setName, name, holder, "名称")) {
modified = true;
}
if (updateText(item::getAbbName, item::setAbbName, abbName, holder, "简称")) {
modified = true;
}
if (updateText(item::getCode, item::setCode, venCode, holder, "供应商编号")) {
modified = true;
}
if (updateVendorCatalog(item::getCatalog, item::setCatalog, classCode, holder, "分类")) {
modified = true;
}
if (updateEmployeeByName(item::getCreator, item::setCreator, createPerson, holder, "创建人")) {
modified = true;
}
if (updateEmployeeByName(item::getModifier, item::setModifier, modifyPerson, holder, "修改人")) {
modified = true;
}
if (updateLocalDate(item::getDevelopDate, item::setDevelopDate, devDate, holder, "开发日期")) {
modified = true;
}
if (updateLocalDate(item::getModifyDate, item::setModifyDate, modifyDate, holder, "修改日期")) {
modified = true;
}
if (modified) {
LocalDate today = LocalDate.now();
if (item.getUpdatedDate() == null || item.getUpdatedDate().isBefore(today)) {
item.setUpdatedDate(today);
holder.info("更新日期更新为 " + today);
}
}
CompanyVendor vendor = item.getVendor();
if (vendor == null) {
// 如果没有关联供应商,则根据供应商名称或别名查找公司
Company company = findOrCreateCompanyByVendorEntity(item, holder);
if (company != null) {
vendor = getCompanyVendorService().findByCompany(company);
if (vendor == null) {
vendor = createVendorByVendorEntity(item, holder);
if (vendor != null) {
vendor.setCompany(company);
vendor = getCompanyVendorService().save(vendor);
}
}
if (vendor != null) {
item.setVendor(vendor);
modified = true;
}
}
}
if (vendor != null) {
if (!Hibernate.isInitialized(vendor)) {
vendor = getCompanyVendorService().findById(vendor.getId());
}
Company company = vendor.getCompany();
if (company != null) {
getCompanyBankAccountCtx().updateBankAccount(company, bank, bankAccount, holder.sub(item.getName()));
}
}
return modified;
}
private boolean updateVendorCatalog(Supplier<VendorCatalog> getter, Consumer<VendorCatalog> setter, String catalogCode, MessageHolder holder, String topic) {
VendorCatalog catalog = null;
if (StringUtils.hasText(catalogCode)) {
catalog = getCompanyVendorService().findCatalogByCode(catalogCode);
}
if (catalog == null) {
setter.accept(null);
holder.warn("无效" + topic + "" + catalogCode);
return true;
} else {
if (!Objects.equals(getter.get(), catalog)) {
if (!Hibernate.isInitialized(catalog)) {
catalog = getCompanyVendorService().findCatalogByCode(catalogCode);
}
setter.accept(catalog);
holder.info(topic + "修改为: " + catalog.getName());
return true;
}
}
return false;
}
/**
* 同步供应商
*
* @param company 要同步的供应商企业
* @param holder 状态输出
* @return 是否更新了供应商信息
*/
public boolean syncVendor(Company company, MessageHolder holder) {
CompanyVendor companyVendor = getCompanyVendorService().findByCompany(company);
if (companyVendor == null) {
holder.warn("供应商未创建, 如需要请手动创建.");
return false;
}
// 检索相关项
List<CompanyVendorEntity> entities = getCompanyVendorEntityService().findAllByVendor(companyVendor);
if (entities.isEmpty()) {
holder.error("供应商关联任何相关项");
return false;
}
boolean updated = false;
boolean companyModified = false;
// 更新相关项
for (CompanyVendorEntity entity : entities) {
if (!StringUtils.hasText(entity.getCode())) {
holder.warn("相关项:" + entity.getCode() + " 无效,跳过");
continue;
}
if (applyEntityDetail(entity, repository.findVendorByVendCode(entity.getCode()), holder)) {
entity = getCompanyVendorEntityService().save(entity);
}
if (updateCompanyNameAndAbbNameByVendorEntity(company, entity, holder)) {
companyModified = true;
}
}
if (companyModified) {
company = getCompanyService().save(company);
updated = true;
}
// 更新供应商的开发日期
if (updateVendorDevelopDate(companyVendor, entities, holder)) {
companyVendor = getCompanyVendorService().save(companyVendor);
updated = true;
}
// 同步供应商关联的合同
for (CompanyVendorEntity entity : entities) {
if (getContractCtx().syncByVendorEntity(companyVendor, entity, holder)) {
updated = true;
}
}
return updated;
}
private boolean updateCompanyNameAndAbbNameByVendorEntity(Company company, CompanyVendorEntity entity, MessageHolder holder) {
CompanyService companyService = getCompanyService();
if (company == null) {
return false;
}
if (!Hibernate.isInitialized(company)) {
company = companyService.findById(company.getId());
}
boolean modified = false;
CompanyCtx companyCtx = getCompanyCtx();
if (companyCtx.updateCompanyNameIfAbsent(company, entity.getName(), holder)) {
modified = true;
}
if (companyCtx.updateCompanyAbbNameIfAbsent(company, entity.getAbbName(), holder)) {
modified = true;
}
return modified;
}
private boolean updateVendorDevelopDate(CompanyVendor companyVendor, List<CompanyVendorEntity> entities, MessageHolder holder) {
LocalDate developDate = null;
for (CompanyVendorEntity entity : entities) {
// 取最早的开发日期
if (developDate == null || entity.getDevelopDate().isBefore(developDate)) {
developDate = entity.getDevelopDate();
}
}
return updateLocalDate(companyVendor::getDevelopDate, companyVendor::setDevelopDate, developDate, holder, "开发日期");
}
public CompanyVendorEntity findOrCreateByCode(String venCode, MessageHolder subHolder) {
CompanyVendorEntityService service = getCompanyVendorEntityService();
CompanyVendorEntity entity = service.findByCode(venCode);
if (entity == null) {
entity = new CompanyVendorEntity();
entity.setCode(venCode);
entity = service.save(entity);
subHolder.info("创建供应商相关项: " + venCode);
}
return entity;
}
private CompanyVendor createVendorByVendorEntity(CompanyVendorEntity entity, MessageHolder holder) {
LocalDate developDate = entity.getDevelopDate();
if (developDate == null) {
holder.warn(entity.getName() + " 没有设置开发日期,跳过");
return null;
}
// 创建发展日期从2023年1月1日后的
LocalDate start = LocalDate.of(2023, 1, 1);
String autoCreateAfter = getConfService().getString(AUTO_CREATE_VENDOR_AFTER);
if (StringUtils.hasText(autoCreateAfter)) {
start = LocalDate.parse(autoCreateAfter);
}
if (developDate.isBefore(start)) {
// start 之前的不自动创建
holder.warn(entity.getName() + " 的发展日期 " + developDate + "" + start + " 之前的, 按规定不自动创建供应商, 如有需要请手动创建");
return null;
}
CompanyVendor companyVendor = new CompanyVendor();
int nextId = SpringApp.getBean(OldVersionService.class).newCompanyVendor(entity.getName());
companyVendor.setId(nextId);
companyVendor.setCatalog(entity.getCatalog());
companyVendor.setDevelopDate(developDate);
holder.info("新供应商:" + entity.getName() + "分配编号:" + nextId);
companyVendor.setCreated(Instant.now());
return companyVendor;
}
private Company findOrCreateCompanyByVendorEntity(CompanyVendorEntity entity, MessageHolder holder) {
String name = entity.getName();
String abbName = entity.getAbbName();
return getCompanyCtx().findOrCreateByNameOrAbbName(name, abbName, entity.getDevelopDate(), holder);
}
public CompanyVendorEntity save(CompanyVendorEntity entity) {
return getCompanyVendorEntityService().save(entity);
}
}

View File

@@ -0,0 +1,59 @@
package com.ecep.contract.manager.ds;
import com.zaxxer.hikari.HikariDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.repository.config.BootstrapMode;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import static com.ecep.contract.manager.AppV2.*;
@Configuration
@EnableJpaRepositories(bootstrapMode = BootstrapMode.LAZY)
public class DsRepositoriesConfig {
private static final Logger logger = LoggerFactory.getLogger(DsRepositoriesConfig.class);
@Bean
// @ConfigurationProperties(prefix = "spring.datasource")
@Primary
public DataSource dataSource(Environment env) {
if (logger.isDebugEnabled()) {
logger.debug("SpringApp.dataSource, env:{}", env);
}
String host = env.getProperty("db.server.host", DEFAULT_DB_HOST);
String port = env.getProperty("db.server.port", DEFAULT_DB_PORT);
String database = env.getProperty("db.server.database", DEFAULT_DB_DATABASE);
String username = env.getProperty("db.server.username", DEFAULT_DB_USERNAME);
String password = env.getProperty("db.server.password", DEFAULT_DB_PASSWORD);
String url = "jdbc:mysql://" + host + ":" + port + "/" + database;
if (logger.isDebugEnabled()) {
logger.debug("db server url:{},user:{}", url, username);
}
return DataSourceBuilder.create()
.type(HikariDataSource.class)
.url(url)
.username(username)
.password(password)
.driverClassName("com.mysql.cj.jdbc.Driver")
.build();
}
@Primary
@Bean
public JdbcTemplate jdbcTemplate(@Qualifier("dataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}

View File

@@ -0,0 +1,26 @@
package com.ecep.contract.manager.ds;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.time.MonthDay;
import java.time.format.DateTimeFormatter;
@Converter(autoApply = true)
public class MonthDayConverter implements AttributeConverter<MonthDay, String> {
// 定义日期格式(月-日,两位数)
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("MM-dd");
@Override
public String convertToDatabaseColumn(MonthDay attribute) {
// 将 MonthDay 转换为数据库存储的字符串MM-dd
return attribute != null ? attribute.format(FORMATTER) : null;
}
@Override
public MonthDay convertToEntityAttribute(String dbData) {
// 将数据库字符串MM-dd转换为 MonthDay
return dbData != null ? MonthDay.parse(dbData, FORMATTER) : null;
}
}

View File

@@ -0,0 +1,9 @@
package com.ecep.contract.manager.ds;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.ListCrudRepository;
public interface MyRepository<T, ID> extends ListCrudRepository<T, ID>, JpaSpecificationExecutor<T> {
}

View File

@@ -0,0 +1,15 @@
package com.ecep.contract.manager.ds.company;
/**
* Date : 2024/2/3
*/
public enum BlackReasonType {
/**
* 黑名单
*/
BLACK,
/**
* 警示名单
*/
GRAY
}

View File

@@ -0,0 +1,19 @@
package com.ecep.contract.manager.ds.company;
import com.ecep.contract.manager.ds.company.model.CompanyContact;
import com.ecep.contract.manager.ds.company.service.CompanyContactService;
import com.ecep.contract.manager.ds.other.EntityStringConverter;
public class CompanyContactStringConverter extends EntityStringConverter<CompanyContact> {
public CompanyContactStringConverter() {
}
public CompanyContactStringConverter(CompanyContactService service) {
setInitialized(employee -> service.findById(employee.getId()));
// setFromString(service::findByName);
}
}

Some files were not shown because too many files have changed in this diff Show More