This commit is contained in:
2025-11-26 16:10:17 +08:00
parent f0e85c5a18
commit c10bd369c0
83 changed files with 1755 additions and 541 deletions

View File

@@ -6,12 +6,12 @@
<parent>
<groupId>com.ecep.contract</groupId>
<artifactId>Contract-Manager</artifactId>
<version>0.0.134-SNAPSHOT</version>
<version>0.0.135-SNAPSHOT</version>
</parent>
<groupId>com.ecep.contract</groupId>
<artifactId>server</artifactId>
<version>0.0.134-SNAPSHOT</version>
<version>0.0.135-SNAPSHOT</version>
<properties>
<maven.compiler.source>${java.version}</maven.compiler.source>
@@ -22,7 +22,7 @@
<dependency>
<groupId>com.ecep.contract</groupId>
<artifactId>common</artifactId>
<version>0.0.134-SNAPSHOT</version>
<version>0.0.135-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -11,6 +11,7 @@ import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import com.ecep.contract.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -25,10 +26,6 @@ import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.BlackReasonType;
import com.ecep.contract.IEntityService;
import com.ecep.contract.QueryService;
import com.ecep.contract.SpringApp;
import com.ecep.contract.cloud.CloudInfo;
import com.ecep.contract.ds.company.model.Company;
import com.ecep.contract.ds.company.model.CompanyBlackReason;
@@ -146,80 +143,6 @@ public class CloudRkService implements IEntityService<CloudRk>, QueryService<Clo
};
}
/**
* 更新黑名单列表
*/
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, FileUtils.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(LocalDateTime.now());
}
private void toCompanyBlackReasonList(
Company company, BlackReasonType type,
JsonNode reason, List<CompanyBlackReason> dbReasons,
@@ -381,15 +304,19 @@ public class CloudRkService implements IEntityService<CloudRk>, QueryService<Clo
}
}
// TODO 这个可以无法更新缓存
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "#p1.id"),
})
public void resetTo(Company from, Company to) {
public void resetTo(Company from, Company to, MessageHolder holder) {
List<CloudRk> list = cloudRKRepository.findAllByCompanyId(from.getId());
if (list.isEmpty()) {
holder.debug("No records to reset");
return;
}
for (CloudRk item : list) {
item.setCompany(to);
holder.info("Reset #" + item.getId());
}
cloudRKRepository.saveAll(list);
}

View File

@@ -14,10 +14,7 @@ import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -73,7 +70,15 @@ public class CloudRkCtx extends AbstractCtx implements CloudRkContext {
}
public void post(String url, Consumer<Map<String, Object>> data, Consumer<JsonNode> consumer) throws IOException {
HttpJsonUtils.post(url, data, consumer, getObjectMapper(), getSocksProxy());
Map<String, String> headers = new HashMap<>();
headers.put("token", "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXB0X2NvZGUiOiJDNEU0M0lQVCIsImx0cGFfdG9rZW4iOm51bGwsImV4cGlyZV");
HttpJsonUtils.post(url, headers, data, consumer, getObjectMapper(), getSocksProxy());
}
public void get(String url, Consumer<JsonNode> consumer) throws IOException {
Map<String, String> headers = new HashMap<>();
headers.put("token", "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXB0X2NvZGUiOiJDNEU0M0lQVCIsImx0cGFfdG9rZW4iOm51bGwsImV4cGlyZV");
HttpJsonUtils.get(url, headers, consumer, getObjectMapper(), getSocksProxy());
}
/**
@@ -162,10 +167,10 @@ public class CloudRkCtx extends AbstractCtx implements CloudRkContext {
for (String name : companyNames) {
String url = api + URLEncoder.encode(name, StandardCharsets.UTF_8);
try {
HttpJsonUtils.get(url, json -> {
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);
}
@@ -466,16 +471,15 @@ public class CloudRkCtx extends AbstractCtx implements CloudRkContext {
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 {
holder.debug("POST " + url);
HttpJsonUtils.post(url, data -> {
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);
}

View File

@@ -5,7 +5,6 @@ import java.util.Optional;
import java.util.stream.Collectors;
import com.ecep.contract.QueryService;
import com.ecep.contract.ds.other.model.CloudRk;
import com.ecep.contract.util.SpecificationUtils;
import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
@@ -146,10 +145,15 @@ public class CloudTycService implements IEntityService<CloudTyc>, QueryService<C
}
}
public void resetTo(Company from, Company to) {
public void resetTo(Company from, Company to, MessageHolder holder) {
List<CloudTyc> list = cloudTycRepository.findAllByCompanyId(from.getId());
if (list.isEmpty()) {
holder.debug("No records to reset");
return;
}
for (CloudTyc item : list) {
item.setCompany(to);
holder.info("Reset #" + item.getId());
}
cloudTycRepository.saveAll(list);
}

View File

@@ -5,7 +5,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import com.ecep.contract.vo.ContractGroupVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
@@ -13,28 +12,53 @@ import org.springframework.beans.BeansException;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.ds.contract.service.ContractGroupService;
import com.ecep.contract.model.ContractGroup;
import com.ecep.contract.service.tasker.WebSocketServerTasker;
import com.ecep.contract.ui.Tasker;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Setter;
/**
* 同步合同分组
* 合同分组同步任务
* <p>
* 该类实现了从U8系统同步合同分组到本地系统的功能
* <p>
* <b>实现特点:</b>
* 1. 继承Tasker基类获取通信框架和消息处理功能
* 2. 实现WebSocketServerTasker接口以支持WebSocket通信
* 3. 使用ContractGroupService处理具体的分组数据同步逻辑
* 4. 提供进度反馈和状态更新
* <p>
* <b>工作流程:</b>
* 1. init方法初始化任务标题
* 2. execute方法读取U8系统中的所有合同分组
* 3. 遍历并同步每个分组数据到本地
* 4. 提供实时进度更新
* <p>
* <b>注意事项:</b>
* 1. 不重复实现Tasker基类已提供的handler设置方法
* 2. 使用MessageHolder进行消息反馈
* 3. 在执行过程中检查cancelled状态以支持任务取消
* <p>
* <b>使用示例:</b>
* 该任务通常由WebSocketServerTaskManager自动实例化和执行通过WebSocket与客户端通信
*/
public class ContractGroupSyncTask extends Tasker<Object> {
public class ContractGroupSyncTask extends Tasker<Object> implements WebSocketServerTasker {
private static final Logger logger = LoggerFactory.getLogger(ContractGroupSyncTask.class);
@Setter
private ContractGroupService contractGroupService;
public ContractGroupSyncTask() {
updateTitle("用友U8系统-同步合同分组信息");
// 初始化逻辑已移至init方法
}
ContractGroupService getContractGroupService() {
if (contractGroupService == null) {
contractGroupService = SpringApp.getBean(ContractGroupService.class);
}
return contractGroupService;
public ContractGroupService getContractGroupService() {
return getCachedBean(ContractGroupService.class);
}
@Override
public void init(JsonNode argsNode) {
updateTitle("用友U8系统-同步合同分组信息");
}
@Override
@@ -44,7 +68,7 @@ public class ContractGroupSyncTask extends Tasker<Object> {
service = SpringApp.getBean(YongYouU8Service.class);
} catch (BeansException e) {
logger.error("can't get bean of YongYouU8Service", e);
holder.error("can't get bean of YongYouU8Service");
holder.info("can't get bean of YongYouU8Service");
return null;
}
@@ -53,7 +77,6 @@ public class ContractGroupSyncTask extends Tasker<Object> {
List<Map<String, Object>> list = service.queryAllContractGroup();
int size = list.size();
holder.debug("总共读取 CM_Group 数据 " + size + "");
for (Map<String, Object> map : list) {
if (isCancelled()) {
holder.info("Cancelled");
@@ -64,7 +87,6 @@ public class ContractGroupSyncTask extends Tasker<Object> {
// 更新进度
updateProgress(counter.incrementAndGet(), size);
}
return null;
}

View File

@@ -13,22 +13,20 @@ import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.ds.contract.service.ContractKindService;
import com.ecep.contract.model.ContractKind;
import com.ecep.contract.service.tasker.WebSocketServerTasker;
import com.ecep.contract.ui.Tasker;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Setter;
/**
* 同步合同分类
*/
public class ContractKindSyncTask extends Tasker<Object> {
public class ContractKindSyncTask extends Tasker<Object> implements WebSocketServerTasker {
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);
@@ -36,35 +34,54 @@ public class ContractKindSyncTask extends Tasker<Object> {
return contractKindService;
}
@Override
public void init(JsonNode argsNode) {
// 初始化任务标题
updateTitle("用友U8系统-同步合同分类信息");
}
@Override
protected Object execute(MessageHolder holder) throws Exception {
holder.info("开始执行合同类型同步任务...");
updateProgress(0, 100);
YongYouU8Repository repository = null;
try {
repository = SpringApp.getBean(YongYouU8Repository.class);
} catch (BeansException e) {
logger.error("can't get bean of YongYouU8Repository", e);
holder.error("can't get bean of YongYouU8Repository");
return null;
}
AtomicInteger counter = new AtomicInteger(0);
logger.info("读取 U8 系统 CM_Kind 数据...");
List<Map<String, Object>> list = repository.queryAllContractKind();
int size = list.size();
holder.debug("总共读取 CM_Kind 数据 " + size + "");
AtomicInteger counter = new AtomicInteger(0);
logger.info("正在读取U8系统中的合同分类数据...");
for (Map<String, Object> map : list) {
if (isCancelled()) {
holder.info("Cancelled");
return null;
List<Map<String, Object>> list = repository.queryAllContractKind();
int size = list.size();
holder.debug("共读取到" + size + "条合同分类数据,开始同步...");
for (Map<String, Object> map : list) {
if (isCancelled()) {
holder.info("任务已取消");
return null;
}
MessageHolder sub = holder.sub(counter.get() + "/" + size + ">");
sync(map, sub);
// 更新进度
int progress = (int) ((counter.incrementAndGet() * 100.0) / size);
updateProgress(counter.get(), size);
holder.info("同步进度: " + progress + "%");
}
MessageHolder sub = holder.sub(counter.get() + "/" + size + ">");
sync(map, sub);
// 更新进度
updateProgress(counter.incrementAndGet(), size);
}
return null;
holder.info("合同类型同步任务执行完成");
updateProgress(100, 100);
return null;
} catch (BeansException e) {
logger.error("无法获取YongYouU8Repository实例", e);
holder.error("无法获取YongYouU8Repository实例");
throw e;
} catch (Exception e) {
logger.error("合同类型同步任务执行失败", e);
holder.error("合同类型同步任务执行失败: " + e.getMessage());
throw e;
}
}
private void sync(Map<String, Object> map, MessageHolder holder) {

View File

@@ -13,58 +13,75 @@ import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.ds.contract.service.ContractTypeService;
import com.ecep.contract.model.ContractType;
import com.ecep.contract.service.tasker.WebSocketServerTasker;
import com.ecep.contract.ui.Tasker;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Setter;
/**
* 同步合同类型
*/
public class ContractTypeSyncTask extends Tasker<Object> {
public class ContractTypeSyncTask extends Tasker<Object> implements WebSocketServerTasker {
private static final Logger logger = LoggerFactory.getLogger(ContractTypeSyncTask.class);
@Setter
private ContractTypeService contractTypeService;
public ContractTypeSyncTask() {
@Override
public void init(JsonNode argsNode) {
// 初始化任务标题
updateTitle("用友U8系统-同步合同类型信息");
}
ContractTypeService getContractTypeService() {
if (contractTypeService == null) {
contractTypeService = SpringApp.getBean(ContractTypeService.class);
}
return contractTypeService;
return getCachedBean(ContractTypeService.class);
}
@Override
protected Object execute(MessageHolder holder) throws Exception {
// 初始化消息
holder.info("开始执行合同类型同步任务...");
updateProgress(0, 100);
YongYouU8Repository repository = null;
try {
repository = SpringApp.getBean(YongYouU8Repository.class);
} catch (BeansException e) {
logger.error("can't get bean of YongYouU8Service", e);
holder.error("can't get bean of YongYouU8Service");
return null;
}
AtomicInteger counter = new AtomicInteger(0);
logger.info("读取 U8 系统 CM_Type,CM_TypeClass 数据...");
List<Map<String, Object>> list = repository.queryAllContractType();
int size = list.size();
holder.debug("总共读取 CM_Type,CM_TypeClass 数据 " + size + "");
AtomicInteger counter = new AtomicInteger(0);
logger.info("正在读取U8系统中的合同类型数据...");
for (Map<String, Object> map : list) {
if (isCancelled()) {
holder.info("Cancelled");
return null;
List<Map<String, Object>> list = repository.queryAllContractType();
int size = list.size();
holder.debug("共读取到" + size + "条合同类型数据,开始同步...");
for (Map<String, Object> map : list) {
if (isCancelled()) {
holder.info("任务已取消");
return null;
}
MessageHolder sub = holder.sub(counter.get() + "/" + size + "> ");
sync(map, sub);
// 更新进度
int progress = (int) ((counter.incrementAndGet() * 100.0) / size);
updateProgress(counter.get(), size);
sub.info("同步进度: " + progress + "%");
}
MessageHolder sub = holder.sub(counter.get() + "/" + size + ">");
sync(map, sub);
// 更新进度
updateProgress(counter.incrementAndGet(), size);
}
return null;
holder.info("合同类型同步任务执行完成");
updateProgress(100, 100);
return null;
} catch (BeansException e) {
logger.error("无法获取YongYouU8Repository实例", e);
holder.error("无法获取YongYouU8Repository实例");
throw e;
} catch (Exception e) {
logger.error("合同类型同步任务执行失败", e);
holder.error("合同类型同步任务执行失败: " + e.getMessage());
throw e;
}
}
private void sync(Map<String, Object> map, MessageHolder holder) {

View File

@@ -5,37 +5,38 @@ import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import com.ecep.contract.ds.customer.service.CustomerCatalogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.ds.customer.service.CustomerCatalogService;
import com.ecep.contract.ds.customer.service.CustomerService;
import com.ecep.contract.model.CustomerCatalog;
import com.ecep.contract.service.tasker.WebSocketServerTasker;
import com.ecep.contract.ui.Tasker;
import com.ecep.contract.vo.CustomerCatalogVo;
import lombok.Setter;
import com.fasterxml.jackson.databind.JsonNode;
/**
* 同步客户分类
*/
public class CustomerClassSyncTask extends Tasker<Object> {
public class CustomerClassSyncTask extends Tasker<Object> implements WebSocketServerTasker {
private static final Logger logger = LoggerFactory.getLogger(CustomerClassSyncTask.class);
@Setter
private CustomerService companyCustomerService;
public CustomerClassSyncTask() {
updateTitle("用友U8系统-同步客户分类信息");
}
CustomerService getCompanyCustomerService() {
if (companyCustomerService == null) {
companyCustomerService = SpringApp.getBean(CustomerService.class);
}
return companyCustomerService;
return getCachedBean(CustomerService.class);
}
@Override
public void init(JsonNode argsNode) {
// 初始化参数,当前任务不需要特殊参数
updateTitle("用友U8系统-同步客户分类信息");
}
@Override
@@ -45,27 +46,29 @@ public class CustomerClassSyncTask extends Tasker<Object> {
repository = SpringApp.getBean(YongYouU8Repository.class);
} catch (BeansException e) {
logger.error("can't get bean of YongYouU8Repository", e);
holder.error("can't get bean of YongYouU8Repository");
holder.error("获取YongYouU8Repository失败: " + e.getMessage());
return null;
}
AtomicInteger counter = new AtomicInteger(0);
logger.info("读取 U8 系统 CustomerClass 数据...");
logger.info("开始读取U8系统客户分类数据...");
List<Map<String, Object>> list = repository.queryAllCustomerClass();
int size = list.size();
holder.debug("总共读取 CustomerClass 数据 " + size + " ");
holder.debug("总共读取" + size + "客户分类数据");
for (Map<String, Object> map : list) {
if (isCancelled()) {
holder.info("Cancelled");
holder.info("任务已取消");
return null;
}
MessageHolder sub = holder.sub(counter.get() + "/" + size + ">");
sync(map, sub);
// 更新进度
updateProgress(counter.incrementAndGet(), size);
int current = counter.incrementAndGet();
updateProgress(current, size);
}
holder.info("客户分类数据同步完成");
return null;
}
@@ -74,33 +77,40 @@ public class CustomerClassSyncTask extends Tasker<Object> {
String code = (String) map.get("cCCCode");
String name = (String) map.get("cCCName");
holder.debug("处理客户分类:" + code + " - " + name);
var catalogService = getCachedBean(CustomerCatalogService.class);
CustomerCatalogVo customerCatalog = catalogService.findByCode(code);
if (customerCatalog == null) {
CustomerCatalog v1 = new CustomerCatalog();
v1.setCode(code);
v1.setName(name);
v1 = catalogService.save(v1);
holder.info("新建客户分类:" + code);
customerCatalog = v1.toVo();
}
try {
CustomerCatalogVo customerCatalog = catalogService.findByCode(code);
if (customerCatalog == null) {
CustomerCatalog v1 = new CustomerCatalog();
v1.setCode(code);
v1.setName(name);
v1 = catalogService.save(v1);
holder.info("新建客户分类:" + code);
customerCatalog = v1.toVo();
}
if (!Objects.equals(customerCatalog.getCode(), code)) {
customerCatalog.setCode(code);
holder.info("客户分类代码:" + customerCatalog.getCode() + " -> " + code);
modified = true;
}
if (!Objects.equals(customerCatalog.getName(), name)) {
customerCatalog.setName(name);
holder.info("客户分类名称:" + customerCatalog.getName() + " -> " + name);
modified = true;
}
if (!Objects.equals(customerCatalog.getCode(), code)) {
customerCatalog.setCode(code);
holder.info("客户分类代码:" + customerCatalog.getCode() + " -> " + code);
modified = true;
}
if (!Objects.equals(customerCatalog.getName(), name)) {
customerCatalog.setName(name);
holder.info("客户分类名称:" + customerCatalog.getName() + " -> " + name);
modified = true;
}
if (modified) {
var v1 = catalogService.getById(customerCatalog.getId());
catalogService.updateByVo(v1, customerCatalog);
catalogService.save(v1);
if (modified) {
var v1 = catalogService.getById(customerCatalog.getId());
catalogService.updateByVo(v1, customerCatalog);
catalogService.save(v1);
}
} catch (Exception e) {
logger.error("同步客户分类失败: " + code, e);
holder.error("同步客户分类失败: " + e.getMessage());
}
}
}

View File

@@ -6,8 +6,6 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
import com.ecep.contract.ds.customer.service.CompanyCustomerEntityService;
import com.ecep.contract.vo.CompanyCustomerEntityVo;
import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -18,32 +16,44 @@ import com.ecep.contract.SpringApp;
import com.ecep.contract.cloud.u8.ctx.CompanyCtx;
import com.ecep.contract.cloud.u8.ctx.CustomerCtx;
import com.ecep.contract.constant.CloudServiceConstant;
import com.ecep.contract.ds.company.model.Company;
import com.ecep.contract.ds.company.service.CompanyService;
import com.ecep.contract.ds.contract.tasker.AbstContractRepairTasker;
import com.ecep.contract.ds.customer.service.CustomerService;
import com.ecep.contract.ds.other.model.CloudYu;
import com.ecep.contract.ds.company.model.Company;
import com.ecep.contract.ds.customer.model.CompanyCustomer;
import com.ecep.contract.ds.customer.model.CompanyCustomerEntity;
import com.ecep.contract.ds.customer.service.CompanyCustomerEntityService;
import com.ecep.contract.ds.customer.service.CustomerService;
import com.ecep.contract.ds.other.model.CloudYu;
import com.ecep.contract.service.tasker.WebSocketServerTasker;
import com.ecep.contract.vo.CompanyCustomerEntityVo;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Setter;
/**
* 同步客户任务
*/
public class CustomerSyncTask extends AbstContractRepairTasker {
public class CustomerSyncTask extends AbstContractRepairTasker implements WebSocketServerTasker {
private static final Logger logger = LoggerFactory.getLogger(CustomerSyncTask.class);
private YongYouU8Repository repository;
private final CustomerCtx customerCtx = new CustomerCtx();
@Setter
private YongYouU8Service yongYouU8Service;
public CustomerSyncTask() {
private CustomerService getCustomerService() {
return getCachedBean(CustomerService.class);
}
@Override
public void init(JsonNode argsNode) {
// 初始化参数,当前任务不需要特殊参数
updateTitle("用友U8系统-同步客户");
}
private CustomerService getCompanyCustomerService() {
return customerCtx.getCompanyCustomerService();
@Override
protected Object execute(MessageHolder holder) throws Exception {
repair(holder);
return null;
}
@Override
@@ -106,7 +116,7 @@ public class CustomerSyncTask extends AbstContractRepairTasker {
return;
}
if (!Hibernate.isInitialized(customer)) {
customer = getCompanyCustomerService().getById(customer.getId());
customer = getCustomerService().getById(customer.getId());
}
Company company = customer.getCompany();
if (company == null) {
@@ -130,7 +140,7 @@ public class CustomerSyncTask extends AbstContractRepairTasker {
return;
}
if (!Hibernate.isInitialized(customer)) {
customer = getCompanyCustomerService().getById(customer.getId());
customer = getCustomerService().getById(customer.getId());
}
Company company = customer.getCompany();
if (company == null) {

View File

@@ -15,7 +15,6 @@ import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.ds.other.service.DepartmentService;
import com.ecep.contract.ds.other.service.EmployeeService;
import com.ecep.contract.model.Department;
import com.ecep.contract.model.Employee;
import com.ecep.contract.service.tasker.WebSocketServerTasker;
import com.ecep.contract.ui.Tasker;

View File

@@ -13,19 +13,26 @@ import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.ds.vendor.repository.VendorClassRepository;
import com.ecep.contract.model.VendorCatalog;
import com.ecep.contract.service.tasker.WebSocketServerTasker;
import com.ecep.contract.ui.Tasker;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Setter;
/**
* 同步供应商分类
*/
public class VendorClassSyncTask extends Tasker<Object> {
public class VendorClassSyncTask extends Tasker<Object> implements WebSocketServerTasker {
private static final Logger logger = LoggerFactory.getLogger(VendorClassSyncTask.class);
@Setter
private VendorClassRepository vendorClassRepository;
public VendorClassSyncTask() {
}
@Override
public void init(JsonNode argsNode) {
// 初始化参数,当前任务不需要特殊参数
updateTitle("用友U8系统-同步供应商分类信息");
}
@@ -43,7 +50,7 @@ public class VendorClassSyncTask extends Tasker<Object> {
service = SpringApp.getBean(YongYouU8Service.class);
} catch (BeansException e) {
logger.error("can't get bean of YongYouU8Service", e);
holder.error("can't get bean of YongYouU8Service");
holder.error("获取YongYouU8Service失败: " + e.getMessage());
return null;
}
@@ -51,7 +58,7 @@ public class VendorClassSyncTask extends Tasker<Object> {
logger.info("读取 U8 系统 VendorClass 数据表...");
List<Map<String, Object>> list = service.queryAllVendorClass();
int size = list.size();
holder.debug("总共读取 VendorClass 数据 " + size + " ");
holder.debug("总共读取" + size + "供应商分类数据");
for (Map<String, Object> map : list) {
if (isCancelled()) {
@@ -64,6 +71,8 @@ public class VendorClassSyncTask extends Tasker<Object> {
updateProgress(counter.incrementAndGet(), size);
}
updateMessage("供应商分类数据同步完成");
updateProperty("completed", true);
return null;
}
@@ -73,27 +82,33 @@ public class VendorClassSyncTask extends Tasker<Object> {
String code = (String) map.get("cVCCode");
String name = (String) map.get("cVCName");
VendorClassRepository repository = getVendorClassRepository();
VendorCatalog vendorCatalog = repository.findByCode(code).orElse(null);
if (vendorCatalog == null) {
vendorCatalog = new VendorCatalog();
holder.info("新建供应商分类:" + code);
modified = true;
}
try {
VendorClassRepository repository = getVendorClassRepository();
VendorCatalog vendorCatalog = repository.findByCode(code).orElse(null);
if (vendorCatalog == null) {
vendorCatalog = new VendorCatalog();
holder.info("新建供应商分类:" + code);
modified = true;
}
if (!Objects.equals(vendorCatalog.getCode(), code)) {
vendorCatalog.setCode(code);
holder.info("供应商分类代码:" + vendorCatalog.getCode() + " -> " + code);
modified = true;
}
if (!Objects.equals(vendorCatalog.getName(), name)) {
vendorCatalog.setName(name);
holder.info("供应商分类名称:" + vendorCatalog.getName() + " -> " + name);
modified = true;
}
if (!Objects.equals(vendorCatalog.getCode(), code)) {
vendorCatalog.setCode(code);
holder.info("供应商分类代码:" + vendorCatalog.getCode() + " -> " + code);
modified = true;
}
if (!Objects.equals(vendorCatalog.getName(), name)) {
vendorCatalog.setName(name);
holder.info("供应商分类名称:" + vendorCatalog.getName() + " -> " + name);
modified = true;
}
if (modified) {
repository.save(vendorCatalog);
if (modified) {
repository.save(vendorCatalog);
}
} catch (Exception e) {
logger.error("同步供应商分类失败: " + code, e);
holder.error("同步供应商分类失败: " + e.getMessage());
updateMessage("同步供应商分类失败: " + code + " - " + e.getMessage());
}
}
}

View File

@@ -3,6 +3,8 @@ package com.ecep.contract.cloud.u8;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
@@ -12,6 +14,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import com.ecep.contract.Message;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.cloud.u8.ctx.CompanyCtx;
@@ -25,17 +28,17 @@ import com.ecep.contract.ds.other.model.CloudYu;
import com.ecep.contract.ds.company.model.Company;
import com.ecep.contract.ds.vendor.model.Vendor;
import com.ecep.contract.ds.vendor.model.VendorEntity;
import com.ecep.contract.service.tasker.WebSocketServerTasker;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Setter;
/**
* 供应商同步任务
*/
public class VendorSyncTask extends AbstContractRepairTasker {
public class VendorSyncTask extends AbstContractRepairTasker implements WebSocketServerTasker {
private static final Logger logger = LoggerFactory.getLogger(VendorSyncTask.class);
private final VendorCtx vendorCtx = new VendorCtx();
private VendorService vendorService;
private VendorEntityService vendorEntityService;
private YongYouU8Repository repository;
@Setter
private YongYouU8Service yongYouU8Service;
@@ -45,17 +48,22 @@ public class VendorSyncTask extends AbstContractRepairTasker {
}
private VendorService getVendorService() {
if (vendorService == null) {
vendorService = SpringApp.getBean(VendorService.class);
}
return vendorService;
return getCachedBean(VendorService.class);
}
private VendorEntityService getVendorEntityService() {
if (vendorEntityService == null) {
vendorEntityService = SpringApp.getBean(VendorEntityService.class);
}
return vendorEntityService;
return getCachedBean(VendorEntityService.class);
}
@Override
public void init(JsonNode argsNode) {
// 初始化参数,当前任务不需要特殊参数
}
@Override
protected Object execute(MessageHolder holder) throws Exception {
repair(holder);
return null;
}
@Override

View File

@@ -5,6 +5,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.util.SpecificationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -119,13 +120,13 @@ public class YongYouU8Service
* @param cloudYu Cloud Yu 对象
* @return 更新的 Cloud Yu
*/
@Caching(evict = { @CacheEvict(key = "#cloudYu.id") })
@Caching(evict = {@CacheEvict(key = "#cloudYu.id")})
@Override
public CloudYu save(CloudYu cloudYu) {
return cloudYuRepository.save(cloudYu);
}
@Caching(evict = { @CacheEvict(key = "#cloudYu.id") })
@Caching(evict = {@CacheEvict(key = "#cloudYu.id")})
@Override
public void delete(CloudYu vo) {
CloudYu entity = cloudYuRepository.findById(vo.getId()).orElse(null);
@@ -143,10 +144,15 @@ public class YongYouU8Service
}
}
public void resetTo(Company from, Company to) {
public void resetTo(Company from, Company to, MessageHolder holder) {
List<CloudYu> list = cloudYuRepository.findAllByCompanyId(from.getId());
if (list.isEmpty()) {
holder.debug("No records to reset");
return;
}
for (CloudYu item : list) {
item.setCompany(to);
holder.info("Reset #" + item.getId());
}
cloudYuRepository.saveAll(list);
}

View File

@@ -2,6 +2,7 @@ package com.ecep.contract.ds.company.service;
import java.util.List;
import com.ecep.contract.MessageHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -51,15 +52,17 @@ public class CompanyContactService implements IEntityService<CompanyContact>, Qu
return repository.save(contact);
}
public void resetTo(Company from, Company to) {
// 曾用名 关联到 updater
public void resetTo(Company from, Company to, MessageHolder holder) {
// 联系人 关联到 updater
List<CompanyContact> list = repository.findAllByCompany(from);
if (list.isEmpty()) {
holder.info("无联系人");
return;
}
for (CompanyContact oldName : list) {
oldName.setMemo(MyStringUtils.appendIfAbsent(oldName.getMemo(), "转自 " + from.getId()));
oldName.setCompany(to);
for (CompanyContact contact : list) {
contact.setMemo(MyStringUtils.appendIfAbsent(contact.getMemo(), "转自 " + from.getId()));
contact.setCompany(to);
holder.info("关联了 " + contact.getName() + "" + to.getName());
}
repository.saveAll(list);
}

View File

@@ -4,6 +4,8 @@ import java.io.File;
import java.time.LocalDate;
import java.util.List;
import com.ecep.contract.Message;
import com.ecep.contract.MessageHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -163,17 +165,21 @@ public class CompanyOldNameService implements IEntityService<CompanyOldName>, Qu
* @param from from
* @param to to
*/
public void resetTo(Company from, Company to) {
public void resetTo(Company from, Company to, MessageHolder holder) {
// 曾用名 关联到 to
List<CompanyOldName> list = companyOldNameRepository.findAllByCompanyId(from.getId());
if (list.isEmpty()) {
holder.info("无曾用名");
return;
}
for (CompanyOldName oldName : list) {
oldName.setMemo(MyStringUtils.appendIfAbsent(oldName.getMemo(), "转自 " + from.getId()));
oldName.setCompanyId(to.getId());
holder.info("关联了 " + oldName.getName() + "" + to.getName());
}
companyOldNameRepository.saveAll(list);
}
public void deleteByCompany(Company company) {

View File

@@ -10,6 +10,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import com.ecep.contract.ds.project.service.ProjectService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -92,6 +93,8 @@ public class CompanyService extends EntityService<Company, CompanyVo, Integer>
@Lazy
@Autowired(required = false)
private YongYouU8Service yongYouU8Service;
@Autowired
private ProjectService projectService;
@Override
protected CompanyRepository getRepository() {
@@ -130,7 +133,7 @@ public class CompanyService extends EntityService<Company, CompanyVo, Integer>
protected Specification<Company> buildParameterSpecification(JsonNode paramsNode) {
Specification<Company> spec = null;
// field
spec = SpecificationUtils.andFieldEqualParam(spec, paramsNode, "name","uniscid", "abbName");
spec = SpecificationUtils.andFieldEqualParam(spec, paramsNode, "name", "uniscid", "abbName");
return spec;
}
@@ -251,7 +254,7 @@ public class CompanyService extends EntityService<Company, CompanyVo, Integer>
// 合并重复的
for (Company company : removes) {
try {
merge(company, updater);
merge(company, updater, null);
} catch (Exception e) {
logger.error("合并 {} -> {} 时发生错误:{}", company.toPrettyString(), updater.toPrettyString(), e.getMessage(),
e);
@@ -275,11 +278,11 @@ public class CompanyService extends EntityService<Company, CompanyVo, Integer>
* </ul>
* 或者 把关联数据转移到其他公司
* <ul>
* <li>{@link VendorService#resetTo(Company, Company)}</li>
* <li>{@link CustomerService#resetTo(Company, Company)}</li>
* <li>{@link VendorService#resetTo(Company, Company, MessageHolder)}</li>
* <li>{@link CustomerService#mergeTo(Company, Company)}</li>
* <li>{@link CompanyOldNameService#resetTo(Company, Company)}</li>
* <li>{@link CompanyContactService#resetTo(Company, Company)}</li>
* <li>{@link ContractService#resetTo(Company, Company)}</li>
* <li>{@link ContractService#mergeTo(Company, Company, MessageHolder)}</li>
* <li>{@link CompanyContactService#resetTo(Company, Company)}</li>
* </ul>
* </p>
@@ -323,20 +326,20 @@ public class CompanyService extends EntityService<Company, CompanyVo, Integer>
* </ol>
* </p>
*/
public void merge(Company from, Company to) {
// cloudRkService.findById(from.getId());
cloudRkService.resetTo(from, to);
cloudTycService.resetTo(from, to);
yongYouU8Service.resetTo(from, to);
public void merge(Company from, Company to, MessageHolder holder) {
cloudRkService.resetTo(from, to, holder);
cloudTycService.resetTo(from, to, holder);
yongYouU8Service.resetTo(from, to, holder);
companyOldNameService.resetTo(from, to);
companyContactService.resetTo(from, to);
companyOldNameService.resetTo(from, to, holder);
companyContactService.resetTo(from, to, holder);
// 供应商和客户
vendorService.resetTo(from, to);
companyCustomerService.resetTo(from, to);
vendorService.resetTo(from, to, holder);
companyCustomerService.mergeTo(from, to, holder);
contractService.resetTo(from, to);
companyContactService.resetTo(from, to);
contractService.mergeTo(from, to, holder);
projectService.mergeTo(from, to, holder);
repository.delete(from);
if (logger.isInfoEnabled()) {
logger.info("Merge {} to {}", from, to);
@@ -428,7 +431,6 @@ public class CompanyService extends EntityService<Company, CompanyVo, Integer>
*
* @param company 要验证的公司
* @param verifyDate 验证日期
* @param status 状态输出
*/
public boolean verifyEnterpriseStatus(Company company, LocalDate verifyDate, MessageHolder holder) {
// 检查营业状态
@@ -506,7 +508,7 @@ public class CompanyService extends EntityService<Company, CompanyVo, Integer>
}
public Predicate buildSearchPredicate(String searchText, Path<Company> root, CriteriaQuery<?> query,
CriteriaBuilder builder) {
CriteriaBuilder builder) {
return builder.or(
builder.like(root.get("name"), "%" + searchText + "%"),
builder.like(root.get("shortName"), "%" + searchText + "%"),

View File

@@ -0,0 +1,102 @@
package com.ecep.contract.ds.company.tasker;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.ds.company.model.Company;
import com.ecep.contract.ds.company.service.CompanyService;
import com.ecep.contract.service.tasker.WebSocketServerTasker;
import com.ecep.contract.ui.Tasker;
import com.ecep.contract.vo.CompanyVo;
import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
/**
* 公司合并任务
* 用于通过WebSocket执行公司合并操作
*/
public class CompanyMergeServerTasker extends Tasker<Object> implements WebSocketServerTasker {
private static final Logger logger = LoggerFactory.getLogger(CompanyMergeServerTasker.class);
private CompanyVo company;
private List<String> nameList;
private CompanyService companyService;
@Override
public void init(JsonNode argsNode) {
companyService = getBean(CompanyService.class);
// 从第一个参数获取公司ID并查找公司
company = companyService.findById(argsNode.get(0).asInt());
// 从第二个参数获取名称列表
JsonNode nameListNode = argsNode.get(1);
nameList = new ArrayList<>();
// 遍历JSON数组将每个元素添加到nameList中
if (nameListNode != null && nameListNode.isArray()) {
for (JsonNode nameNode : nameListNode) {
nameList.add(nameNode.asText());
}
}
}
@Override
protected Object execute(MessageHolder holder) throws Exception {
HashSet<String> nameSet = new HashSet<>(nameList);
nameSet.add(company.getName());
int size = nameSet.size();
int count = 1;
int merge = 0;
HashMap<Integer, Company> targetCompanyMap = new HashMap<>();
for (String name : nameSet) {
MessageHolder sub = holder.sub(count + "/" + size + ":" + name + ">");
if (name == null || name.isEmpty()) {
sub.warn("名称为空");
continue;
}
List<Company> list = companyService.findAllByName(name);
for (Company company : list) {
sub.debug("找到 " + company.getName());
targetCompanyMap.put(company.getId(), company);
}
count++;
}
targetCompanyMap.remove(this.company.getId());
if (targetCompanyMap.isEmpty()) {
holder.warn("没有需要并户的公司");
return null;
}
//
Company targetCompany = companyService.getById(this.company.getId());
for (Company company : targetCompanyMap.values()) {
try {
companyService.merge(company, targetCompany, holder);
holder.info("并户 " + company.getName() + "[" + company.getId() + "] 到当前公司");
merge++;
} catch (Exception e) {
holder.warn("合并 " + company.getName() + " -> " + targetCompany.getName() + " 失败: " + e.getMessage());
logger.warn("合并 {} -> {} 失败: {}", company.getName(), targetCompany.getName(), e.getMessage(), e);
}
}
if (merge == 0) {
holder.info("没有需要并户的公司");
} else {
holder.info("完成合并操作,共合并 " + merge + " 个公司");
}
updateTitle("公司合并任务完成");
return null;
}
}

View File

@@ -9,6 +9,7 @@ import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.ecep.contract.*;
import com.ecep.contract.ds.contract.model.ContractItem;
import com.ecep.contract.vo.ContractCatalogVo;
import jakarta.persistence.criteria.Root;
@@ -25,11 +26,6 @@ import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.ContractPayWay;
import com.ecep.contract.EntityService;
import com.ecep.contract.IEntityService;
import com.ecep.contract.QueryService;
import com.ecep.contract.SpringApp;
import com.ecep.contract.constant.ContractConstant;
import com.ecep.contract.ds.company.service.CompanyService;
import com.ecep.contract.ds.contract.repository.ContractRepository;
@@ -420,14 +416,16 @@ public class ContractService extends EntityService<Contract, ContractVo, Integer
/**
* 重置合同关联企业
*/
public void resetTo(Company from, Company to) {
public void mergeTo(Company from, Company to, MessageHolder holder) {
List<Contract> list = contractRepository.findAllByCompanyId(from.getId());
if (list.isEmpty()) {
holder.info("没有合同需要处理");
return;
}
for (Contract contract : list) {
contract.setDescription(MyStringUtils.appendIfAbsent(contract.getDescription(), "转自 " + from.getId()));
contract.setCompany(to);
holder.info("Reset #" + contract.getId());
}
contractRepository.saveAll(list);
}

View File

@@ -356,7 +356,7 @@ public class CustomerService extends CompanyBasicService
* @param from 要转移的客户信息所属的公司
* @param to 要转移到的公司
*/
public void resetTo(Company from, Company to) {
public void mergeTo(Company from, Company to, MessageHolder holder) {
// 这里使用Optional对象来处理可能为空的情况
Optional<CompanyCustomer> fromCustomer = repository.findByCompany(from);
if (fromCustomer.isEmpty()) {
@@ -373,7 +373,7 @@ public class CustomerService extends CompanyBasicService
}
// 把 fromCustomer 信息合并到 toCustomer
resetTo(fromCustomer.get(), toCustomer.get());
mergeTo(fromCustomer.get(), toCustomer.get(), holder);
}
@@ -383,7 +383,7 @@ public class CustomerService extends CompanyBasicService
* @param from 源客户对象
* @param to 目标客户对象
*/
public void resetTo(CompanyCustomer from, CompanyCustomer to) {
public void mergeTo(CompanyCustomer from, CompanyCustomer to, MessageHolder holder) {
// file
companyCustomerFileService.resetTo(from, to);
// entity

View File

@@ -2,6 +2,7 @@ package com.ecep.contract.ds.other.controller;
import java.util.Map;
import com.ecep.contract.vo.FunctionVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
@@ -73,7 +74,7 @@ public class EmployeeRoleController {
}
@RequestMapping("/getFunctionsByRoleId")
public java.util.List<com.ecep.contract.model.Function> getFunctionsByRoleId(Integer roleId) {
public java.util.List<FunctionVo> getFunctionsByRoleId(Integer roleId) {
return employeeRoleService.getFunctionsByRoleId(roleId);
}
}

View File

@@ -3,6 +3,7 @@ package com.ecep.contract.ds.other.service;
import java.util.List;
import java.util.Optional;
import com.ecep.contract.vo.FunctionVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
@@ -36,6 +37,9 @@ public class EmployeeRoleService implements IEntityService<EmployeeRole>, QueryS
@Lazy
@Autowired
private EmployeeRoleRepository roleRepository;
@Lazy
@Autowired
private FunctionService functionService;
@Cacheable(key = "#p0")
public EmployeeRoleVo findById(Integer id) {
@@ -95,15 +99,31 @@ public class EmployeeRoleService implements IEntityService<EmployeeRole>, QueryS
}
@Transactional
public List<Function> getFunctionsByRoleId(int roleId) {
public List<FunctionVo> getFunctionsByRoleId(Integer roleId) {
Optional<EmployeeRole> optional = roleRepository.findById(roleId);
if (optional.isPresent()) {
EmployeeRole role = optional.get();
return role.getFunctions().stream().toList();
return role.getFunctions().stream().map(Function::toVo).toList();
}
return null;
}
@Transactional
public void saveRoleFunctions(Integer roleId, FunctionVo[] functions) {
Optional<EmployeeRole> optional = roleRepository.findById(roleId);
if (optional.isEmpty()) {
throw new RuntimeException("角色不存在");
}
EmployeeRole role = optional.get();
java.util.List<Function> list = new java.util.ArrayList<>();
for (FunctionVo functionVo : functions) {
Function func = functionService.getById(functionVo.getId());
list.add(func);
}
role.setFunctions(list);
save(role);
}
@Override
public void updateByVo(EmployeeRole role, EmployeeRoleVo vo) {
role.setCode(vo.getCode());

View File

@@ -1,5 +1,6 @@
package com.ecep.contract.ds.project.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Repository;
@@ -30,4 +31,6 @@ public interface ProjectRepository extends
Optional<Project> findByName(String name);
Optional<Project> findByCode(String code);
List<Project> findAllByCustomerId(Integer id);
}

View File

@@ -8,6 +8,8 @@ import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.ds.company.model.Company;
import com.ecep.contract.vo.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -415,4 +417,16 @@ public class ProjectService
}
public void mergeTo(Company from, Company to, MessageHolder holder) {
List<Project> list = projectRepository.findAllByCustomerId(from.getId());
if (list.isEmpty()) {
holder.info("没有项目需要处理");
return;
}
for (Project project : list) {
project.setCustomer(to);
holder.info("Reset #" + project.getId());
}
projectRepository.saveAll(list);
}
}

View File

@@ -0,0 +1,24 @@
package com.ecep.contract.ds.vendor.converter;
import org.springframework.lang.Nullable;
import com.ecep.contract.ds.vendor.service.VendorService;
import com.ecep.contract.vo.VendorVo;
public class StringToVendorConverter implements org.springframework.core.convert.converter.Converter<String, VendorVo> {
private VendorService service;
public StringToVendorConverter(VendorService service) {
this.service = service;
}
@Override
@Nullable
public VendorVo convert(String string) {
if (string == null || string.trim().isEmpty()) {
return null;
}
return service.findById(Integer.parseInt(string));
}
}

View File

@@ -31,6 +31,7 @@ import org.springframework.util.StringUtils;
import com.ecep.contract.IEntityService;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.QueryService;
import com.ecep.contract.SpringApp;
import com.ecep.contract.VendorFileType;
import com.ecep.contract.VendorType;
import com.ecep.contract.constant.CompanyVendorConstant;
@@ -44,6 +45,7 @@ import com.ecep.contract.ds.vendor.repository.VendorTypeLocalRepository;
import com.ecep.contract.ds.company.model.Company;
import com.ecep.contract.model.CompanyBasicFile;
import com.ecep.contract.ds.contract.model.Contract;
import com.ecep.contract.ds.vendor.converter.StringToVendorConverter;
import com.ecep.contract.ds.vendor.model.Vendor;
import com.ecep.contract.model.VendorCatalog;
import com.ecep.contract.ds.vendor.model.VendorEntity;
@@ -57,6 +59,7 @@ import com.ecep.contract.util.SpecificationUtils;
import com.ecep.contract.vo.VendorVo;
import com.fasterxml.jackson.databind.JsonNode;
import jakarta.annotation.PostConstruct;
import jakarta.persistence.criteria.Path;
@Lazy
@@ -89,6 +92,12 @@ public class VendorService extends CompanyBasicService
@Autowired
private VendorClassRepository vendorClassRepository;
@PostConstruct
public void init() {
SpringApp.getBean(org.springframework.core.convert.converter.ConverterRegistry.class)
.addConverter(new StringToVendorConverter(this));
}
@Cacheable(key = "#p0")
public VendorVo findById(Integer id) {
return repository.findById(id).map(Vendor::toVo).orElse(null);
@@ -226,7 +235,7 @@ public class VendorService extends CompanyBasicService
@SuppressWarnings("unchecked")
@Override
protected <T, F extends CompanyBasicFile<T>> boolean fillFileAsDefaultType(F dbFile, File file,
Consumer<String> status) {
Consumer<String> status) {
dbFile.setType((T) VendorFileType.General);
fillFile(dbFile, file, null, status);
vendorFileService.save((VendorFile) dbFile);
@@ -236,7 +245,7 @@ public class VendorService extends CompanyBasicService
@SuppressWarnings("unchecked")
@Override
protected <T, F extends CompanyBasicFile<T>> F fillFileType(File file, List<File> fileList,
Consumer<String> status) {
Consumer<String> status) {
VendorFile vendorFile = new VendorFile();
vendorFile.setType(VendorFileType.General);
vendorFile.setFilePath(file.getAbsolutePath());
@@ -257,7 +266,7 @@ public class VendorService extends CompanyBasicService
@Override
protected <T, F extends CompanyBasicFile<T>> boolean fillFileAsEvaluationFile(F customerFile, File file,
List<File> fileList, Consumer<String> status) {
List<File> fileList, Consumer<String> status) {
boolean modified = super.fillFileAsEvaluationFile(customerFile, file, fileList, status);
// 当评价表有日期,并且未设审核时
boolean valid = FileUtils.isArchiveFile(customerFile.getFilePath()) && customerFile.getSignDate() != null;
@@ -428,7 +437,7 @@ public class VendorService extends CompanyBasicService
return dir;
}
public void resetTo(Company from, Company to) {
public void resetTo(Company from, Company to, MessageHolder holder) {
Optional<Vendor> optional = repository.findByCompany(from);
optional.ifPresent(companyVendor -> {
companyVendor

View File

@@ -121,6 +121,7 @@ public class WebSocketServerCallbackManager {
return method.invoke(service);
}
// 第一个参数不是数组时
if (!argumentsNode.get(0).isArray()) {
Class<?> parameterType = Class.forName(argumentsNode.get(1).asText());
Object arg = objectMapper.treeToValue(argumentsNode.get(0), parameterType);

View File

@@ -13,12 +13,23 @@ import com.fasterxml.jackson.databind.JsonNode;
* 定义了所有通过WebSocket与客户端通信的任务的通用方法
* 包括任务名称、初始化参数、设置会话、更新消息、更新标题、更新进度等操作
* <p>
* 所有通过WebSocket与客户端通信的任务类都应实现此接口, 文档参考 .trace/rules/server_task_rules.md
* tips检查是否在 tasker_mapper.json 中注册
* 所有通过WebSocket与客户端通信的任务类都应实现此接口, 通常应继承Tasker类并实现此接口
* <p>
* <b>实现注意事项:</b>
* 1. 服务器端任务实现应继承Tasker基类该基类已提供大部分通信功能的实现
* 2. 不要在子类中重复实现setMessageHandler、setTitleHandler、setPropertyHandler和setProgressHandler方法这些由Tasker基类提供
* 3. 任务类应覆盖init方法以初始化参数和设置任务标题
* 4. 任务类应覆盖execute方法实现具体业务逻辑使用MessageHolder进行消息消息反馈
* 5. 任务执行时使用updateProgress方法进行进度反馈
* 6. 任务名称应与客户端对应的Tasker类名保持一致以确保正确的通信映射
* <p>
* <b>注册要求:</b>
* 任务类必须在tasker_mapper.json中注册以确保WebSocketServerTaskManager能够正确识别和实例化
*/
public interface WebSocketServerTasker extends Callable<Object> {
/**
* 初始化任务参数
* 任务类应在init方法中解析argsNode, 初始化任务参数
*
* @param argsNode 任务参数的JSON节点
*/

View File

@@ -1,6 +1,5 @@
package com.ecep.contract.ui;
import java.util.HashMap;
import java.util.Locale;
import java.util.function.BiConsumer;
import java.util.logging.Level;
@@ -11,7 +10,6 @@ import org.springframework.beans.BeansException;
import com.ecep.contract.Message;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.ds.company.service.CompanyService;
import com.ecep.contract.ds.other.service.EmployeeService;
import com.ecep.contract.ds.other.service.SysConfService;
@@ -22,6 +20,27 @@ import com.ecep.contract.util.DefaultBeanContext;
import lombok.Getter;
import lombok.Setter;
/**
* Tasker基类提供任务执行和通信的核心功能
* <p>
* 该基类实现了任务执行框架,提供了以下核心功能:
* 1. 任务执行环境call方法
* 2. 消息处理和进度更新机制
* 3. Spring Bean获取和缓存功能
* 4. 当前用户和本地化支持
* <p>
* <b>主要组件:</b>
* - messageHandler: 处理消息通知
* - titleHandler: 处理标题更新
* - progressHandler: 处理进度更新
* - propertyHandler: 处理属性更新
* <p>
* <b>使用说明:</b>
* 1. 子类应继承此类并实现execute方法实现具体业务逻辑
* 2. 使用updateMessage、updateProgress等方法进行状态反馈
* 3. 对于WebSocket任务还应实现WebSocketServerTasker接口
* 4. 子类通常不需要覆盖setter方法这些由框架自动设置
*/
public abstract class Tasker<T> implements java.util.concurrent.Callable<T>, BeanContext {
private static final Logger logger = LoggerFactory.getLogger(Tasker.class);
@Setter

View File

@@ -20,7 +20,15 @@
"ContractRepairAllTask": "com.ecep.contract.ds.contract.tasker.ContractRepairAllTasker",
"ContractFilesRebuildAllTasker": "com.ecep.contract.ds.contract.tasker.ContractFilesRebuildAllTasker",
"ContractFilesRebuildTasker": "com.ecep.contract.ds.contract.tasker.ContractFilesRebuildTasker",
"EmployeesSyncTask": "com.ecep.contract.cloud.u8.EmployeesSyncTask"
"EmployeesSyncTask": "com.ecep.contract.cloud.u8.EmployeesSyncTask",
"CompanyMergeTask": "com.ecep.contract.ds.company.tasker.CompanyMergeServerTasker",
"VendorSyncTask": "com.ecep.contract.cloud.u8.VendorSyncTask",
"CustomerSyncTask": "com.ecep.contract.cloud.u8.CustomerSyncTask",
"CustomerClassSyncTask": "com.ecep.contract.cloud.u8.CustomerClassSyncTask",
"VendorClassSyncTask": "com.ecep.contract.cloud.u8.VendorClassSyncTask",
"ContractKindSyncTask": "com.ecep.contract.cloud.u8.ContractKindSyncTask",
"ContractTypeSyncTask": "com.ecep.contract.cloud.u8.ContractTypeSyncTask",
"ContractGroupSyncTask": "com.ecep.contract.cloud.u8.ContractGroupSyncTask"
},
"descriptions": "任务注册信息, 客户端的任务可以通过 WebSocket 调用"
}