|
|
@@ -1,8 +1,10 @@
|
|
|
package com.malk.minglei.service.impl.yida;
|
|
|
|
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
+import com.fasterxml.jackson.core.type.TypeReference;
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
import com.malk.minglei.config.YidaApplicationsProperties;
|
|
|
+import com.malk.minglei.dto.ApprovalMatrixSyncResult;
|
|
|
import com.malk.minglei.dto.MingleiDocumentQueryRequest;
|
|
|
import com.malk.minglei.service.employee.EmployeeRosterService;
|
|
|
import com.malk.minglei.service.yida.MingleiDocumentService;
|
|
|
@@ -25,6 +27,8 @@ import java.util.LinkedHashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.Set;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.UUID;
|
|
|
|
|
|
/**
|
|
|
* 明磊主数据宜搭表单查询服务实现。
|
|
|
@@ -49,8 +53,7 @@ public class MingleiDocumentServiceImpl implements MingleiDocumentService {
|
|
|
FOURTH_LEVEL_DEPARTMENT_MANAGER_FIELD_ID,
|
|
|
DEPARTMENT_LEADER_FIELD_ID
|
|
|
};
|
|
|
- private static final int APPROVAL_MATRIX_QUERY_PAGE_SIZE = 1;
|
|
|
- private static final int APPLICANT_CONFIGURATION_QUERY_PAGE_SIZE = 100;
|
|
|
+ private static final int APPROVAL_MATRIX_SYNC_PAGE_SIZE = 100;
|
|
|
|
|
|
private final YDClient yidaClient;
|
|
|
private final DDClient dingTalkClient;
|
|
|
@@ -59,6 +62,7 @@ public class MingleiDocumentServiceImpl implements MingleiDocumentService {
|
|
|
private final YidaApplicationsProperties.ApplicationCredentials masterDataConfiguration;
|
|
|
private final ObjectMapper objectMapper;
|
|
|
private final EmployeeRosterService employeeRosterService;
|
|
|
+ private final ApprovalMatrixCacheRepository approvalMatrixCacheRepository;
|
|
|
|
|
|
/**
|
|
|
* 创建明磊主数据表单查询服务。
|
|
|
@@ -70,6 +74,7 @@ public class MingleiDocumentServiceImpl implements MingleiDocumentService {
|
|
|
* @param applications 宜搭应用配置
|
|
|
* @param objectMapper JSON 序列化组件
|
|
|
* @param employeeRosterService 员工花名册服务
|
|
|
+ * @param approvalMatrixCacheRepository 审批矩阵本地缓存仓储
|
|
|
*/
|
|
|
public MingleiDocumentServiceImpl(@Qualifier("masterDataYidaClient") YDClient yidaClient,
|
|
|
DDClient dingTalkClient,
|
|
|
@@ -77,7 +82,8 @@ public class MingleiDocumentServiceImpl implements MingleiDocumentService {
|
|
|
DDConf dingTalkConfiguration,
|
|
|
YidaApplicationsProperties applications,
|
|
|
ObjectMapper objectMapper,
|
|
|
- EmployeeRosterService employeeRosterService) {
|
|
|
+ EmployeeRosterService employeeRosterService,
|
|
|
+ ApprovalMatrixCacheRepository approvalMatrixCacheRepository) {
|
|
|
this.yidaClient = yidaClient;
|
|
|
this.dingTalkClient = dingTalkClient;
|
|
|
this.dingTalkContactsClient = dingTalkContactsClient;
|
|
|
@@ -85,6 +91,7 @@ public class MingleiDocumentServiceImpl implements MingleiDocumentService {
|
|
|
this.masterDataConfiguration = applications.getMasterData();
|
|
|
this.objectMapper = objectMapper;
|
|
|
this.employeeRosterService = employeeRosterService;
|
|
|
+ this.approvalMatrixCacheRepository = approvalMatrixCacheRepository;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -96,7 +103,16 @@ public class MingleiDocumentServiceImpl implements MingleiDocumentService {
|
|
|
*/
|
|
|
@Override
|
|
|
public Map<String, Object> queryDocuments(int page, int size) {
|
|
|
- return executeQuery(null, null, page, size);
|
|
|
+ List<ApprovalMatrixCacheRecord> records = approvalMatrixCacheRepository.findPage(page, size);
|
|
|
+ List<Map<String, Object>> resultRecords = new ArrayList<Map<String, Object>>();
|
|
|
+ for (ApprovalMatrixCacheRecord record : records) {
|
|
|
+ resultRecords.add(Collections.<String, Object>singletonMap("formData", toFormData(record)));
|
|
|
+ }
|
|
|
+ Map<String, Object> result = new LinkedHashMap<String, Object>();
|
|
|
+ result.put("records", resultRecords);
|
|
|
+ result.put("totalCount", Integer.valueOf(approvalMatrixCacheRepository.count()));
|
|
|
+ result.put("pageNumber", Integer.valueOf(page));
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -158,8 +174,7 @@ public class MingleiDocumentServiceImpl implements MingleiDocumentService {
|
|
|
if (requestedDepartmentId == null) {
|
|
|
throw new IllegalArgumentException("departmentId must not be blank");
|
|
|
}
|
|
|
- return extractDepartmentManagers(executeQuery(DEPARTMENT_ID_FIELD_ID, requestedDepartmentId,
|
|
|
- 1, APPROVAL_MATRIX_QUERY_PAGE_SIZE));
|
|
|
+ return extractDepartmentManagers(approvalMatrixCacheRepository.findByDepartmentId(requestedDepartmentId));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -173,20 +188,34 @@ public class MingleiDocumentServiceImpl implements MingleiDocumentService {
|
|
|
String requestedUserId = trimToNull(userId);
|
|
|
require(requestedUserId, "userId must not be blank");
|
|
|
String departmentId = resolveDepartmentId(requestedUserId);
|
|
|
- Map<String, Object> queryResult = executeQuery(DEPARTMENT_ID_FIELD_ID, departmentId, 1,
|
|
|
- APPLICANT_CONFIGURATION_QUERY_PAGE_SIZE);
|
|
|
- Map formData = firstFormData(queryResult.get("records"));
|
|
|
+ ApprovalMatrixCacheRecord record = approvalMatrixCacheRepository.findByDepartmentId(departmentId);
|
|
|
Map<String, Object> result = new LinkedHashMap<String, Object>();
|
|
|
result.put("departmentId", departmentId);
|
|
|
- if (formData != null) {
|
|
|
- result.put("company", toStringValue(formData.get(APPLICATION_COMPANY_FIELD_ID)));
|
|
|
- result.put("firstLevelManagerUserIds", employeeUserIds(formData.get(FIRST_LEVEL_DEPARTMENT_MANAGER_FIELD_ID + "_id")));
|
|
|
- result.put("secondLevelManagerUserIds", employeeUserIds(formData.get(SECOND_LEVEL_DEPARTMENT_MANAGER_FIELD_ID + "_id")));
|
|
|
- result.put("thirdLevelManagerUserIds", employeeUserIds(formData.get(THIRD_LEVEL_DEPARTMENT_MANAGER_FIELD_ID + "_id")));
|
|
|
+ if (record != null) {
|
|
|
+ result.put("company", record.getApplicationCompany());
|
|
|
+ result.put("firstLevelManagerUserIds", readUserIds(record.getFirstLevelManagerUserIds()));
|
|
|
+ result.put("secondLevelManagerUserIds", readUserIds(record.getSecondLevelManagerUserIds()));
|
|
|
+ result.put("thirdLevelManagerUserIds", readUserIds(record.getThirdLevelManagerUserIds()));
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public ApprovalMatrixSyncResult syncApprovalMatrix() {
|
|
|
+ List<ApprovalMatrixCacheRecord> records = fetchApprovalMatrixRecords();
|
|
|
+ if (records.isEmpty()) {
|
|
|
+ throw new IllegalStateException("Approval matrix sync returned no records; existing cache was retained");
|
|
|
+ }
|
|
|
+ Set<Long> departmentIds = new LinkedHashSet<Long>();
|
|
|
+ for (ApprovalMatrixCacheRecord record : records) {
|
|
|
+ if (!departmentIds.add(record.getDepartmentId())) {
|
|
|
+ throw new IllegalStateException("Duplicate department_id was found in approval matrix: " + record.getDepartmentId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ int syncedCount = approvalMatrixCacheRepository.replaceAll(records, UUID.randomUUID().toString());
|
|
|
+ return new ApprovalMatrixSyncResult(records.size(), syncedCount);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 按钉钉用户读取通讯录主部门。未设置主部门时取首个所属部门。
|
|
|
*
|
|
|
@@ -298,14 +327,14 @@ public class MingleiDocumentServiceImpl implements MingleiDocumentService {
|
|
|
*/
|
|
|
private Map<String, Object> queryApprovalMatrix(String queryType, String fieldId, String fieldValue) {
|
|
|
long startedAt = System.nanoTime();
|
|
|
- Object totalCount = null;
|
|
|
try {
|
|
|
- Map<String, Object> queryResult = executeQuery(fieldId, fieldValue, 1, APPROVAL_MATRIX_QUERY_PAGE_SIZE);
|
|
|
- totalCount = queryResult.get("totalCount");
|
|
|
- return extractDepartmentManagers(queryResult);
|
|
|
+ ApprovalMatrixCacheRecord record = DEPARTMENT_ID_FIELD_ID.equals(fieldId)
|
|
|
+ ? approvalMatrixCacheRepository.findByDepartmentId(fieldValue)
|
|
|
+ : approvalMatrixCacheRepository.findByDepartmentName(fieldValue);
|
|
|
+ return extractDepartmentManagers(record);
|
|
|
} finally {
|
|
|
- LOGGER.info("Approval matrix query stage=YIDA_MATRIX_QUERY queryType={} durationMs={} totalCount={}",
|
|
|
- queryType, elapsedMillis(startedAt), totalCount);
|
|
|
+ LOGGER.info("Approval matrix query stage=DATABASE_MATRIX_QUERY queryType={} durationMs={}",
|
|
|
+ queryType, elapsedMillis(startedAt));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -332,6 +361,137 @@ public class MingleiDocumentServiceImpl implements MingleiDocumentService {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ private Map<String, Object> extractDepartmentManagers(ApprovalMatrixCacheRecord record) {
|
|
|
+ if (record == null) {
|
|
|
+ return Collections.emptyMap();
|
|
|
+ }
|
|
|
+ Map<String, Object> result = new LinkedHashMap<String, Object>();
|
|
|
+ result.put(FIRST_LEVEL_DEPARTMENT_MANAGER_FIELD_ID, firstUserId(record.getFirstLevelManagerUserIds()));
|
|
|
+ result.put(SECOND_LEVEL_DEPARTMENT_MANAGER_FIELD_ID, firstUserId(record.getSecondLevelManagerUserIds()));
|
|
|
+ result.put(THIRD_LEVEL_DEPARTMENT_MANAGER_FIELD_ID, firstUserId(record.getThirdLevelManagerUserIds()));
|
|
|
+ result.put(FOURTH_LEVEL_DEPARTMENT_MANAGER_FIELD_ID, firstUserId(record.getFourthLevelManagerUserIds()));
|
|
|
+ result.put(DEPARTMENT_LEADER_FIELD_ID, firstUserId(record.getDepartmentLeaderUserIds()));
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<ApprovalMatrixCacheRecord> fetchApprovalMatrixRecords() {
|
|
|
+ validateConfiguration();
|
|
|
+ List<ApprovalMatrixCacheRecord> records = new ArrayList<ApprovalMatrixCacheRecord>();
|
|
|
+ int page = 1;
|
|
|
+ while (true) {
|
|
|
+ Map<String, Object> response = executeQuery(null, null, page, APPROVAL_MATRIX_SYNC_PAGE_SIZE);
|
|
|
+ Object rawRecords = response.get("records");
|
|
|
+ if (rawRecords == null) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (!(rawRecords instanceof Iterable)) {
|
|
|
+ throw new IllegalStateException("Approval matrix sync returned an invalid records payload");
|
|
|
+ }
|
|
|
+
|
|
|
+ int rawPageRecordCount = 0;
|
|
|
+ for (Object rawRecord : (Iterable<?>) rawRecords) {
|
|
|
+ rawPageRecordCount++;
|
|
|
+ if (!(rawRecord instanceof Map)) {
|
|
|
+ throw new IllegalStateException("Approval matrix sync returned an invalid record");
|
|
|
+ }
|
|
|
+ Object formData = ((Map) rawRecord).get("formData");
|
|
|
+ if (!(formData instanceof Map)) {
|
|
|
+ throw new IllegalStateException("Approval matrix record has no formData");
|
|
|
+ }
|
|
|
+ records.add(toCacheRecord((Map) rawRecord, (Map) formData));
|
|
|
+ }
|
|
|
+ // 以宜搭原始页记录数判断是否还有下一页,避免单条坏数据导致提前结束并误删旧缓存。
|
|
|
+ if (rawPageRecordCount < APPROVAL_MATRIX_SYNC_PAGE_SIZE) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ page++;
|
|
|
+ }
|
|
|
+ return records;
|
|
|
+ }
|
|
|
+
|
|
|
+ private ApprovalMatrixCacheRecord toCacheRecord(Map rawRecord, Map formData) {
|
|
|
+ String departmentId = toStringValue(formData.get(DEPARTMENT_ID_FIELD_ID));
|
|
|
+ if (departmentId == null) {
|
|
|
+ throw new IllegalStateException("Approval matrix record has no department_id");
|
|
|
+ }
|
|
|
+ ApprovalMatrixCacheRecord record = new ApprovalMatrixCacheRecord();
|
|
|
+ try {
|
|
|
+ record.setDepartmentId(Long.valueOf(departmentId));
|
|
|
+ } catch (NumberFormatException exception) {
|
|
|
+ throw new IllegalStateException("Approval matrix department_id is invalid: " + departmentId, exception);
|
|
|
+ }
|
|
|
+ record.setDepartmentName(toStringValue(formData.get(DEPARTMENT_NAME_FIELD_ID)));
|
|
|
+ record.setApplicationCompany(toStringValue(formData.get(APPLICATION_COMPANY_FIELD_ID)));
|
|
|
+ record.setFirstLevelManagerUserIds(writeUserIds(formData.get(FIRST_LEVEL_DEPARTMENT_MANAGER_FIELD_ID + "_id")));
|
|
|
+ record.setSecondLevelManagerUserIds(writeUserIds(formData.get(SECOND_LEVEL_DEPARTMENT_MANAGER_FIELD_ID + "_id")));
|
|
|
+ record.setThirdLevelManagerUserIds(writeUserIds(formData.get(THIRD_LEVEL_DEPARTMENT_MANAGER_FIELD_ID + "_id")));
|
|
|
+ record.setFourthLevelManagerUserIds(writeUserIds(formData.get(FOURTH_LEVEL_DEPARTMENT_MANAGER_FIELD_ID + "_id")));
|
|
|
+ record.setDepartmentLeaderUserIds(writeUserIds(formData.get(DEPARTMENT_LEADER_FIELD_ID + "_id")));
|
|
|
+ record.setYidaFormInstanceId(firstText(rawRecord, "formInstanceId", "form_instance_id", "instanceId", "id"));
|
|
|
+ try {
|
|
|
+ record.setSourceFormData(objectMapper.writeValueAsString(formData));
|
|
|
+ } catch (JsonProcessingException exception) {
|
|
|
+ throw new IllegalStateException("Unable to serialize approval matrix formData", exception);
|
|
|
+ }
|
|
|
+ record.setSyncedAt(LocalDateTime.now());
|
|
|
+ return record;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String writeUserIds(Object employeeIds) {
|
|
|
+ try {
|
|
|
+ return objectMapper.writeValueAsString(employeeUserIds(employeeIds));
|
|
|
+ } catch (JsonProcessingException exception) {
|
|
|
+ throw new IllegalStateException("Unable to serialize approval matrix manager user IDs", exception);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<String> readUserIds(String serializedUserIds) {
|
|
|
+ if (serializedUserIds == null || serializedUserIds.trim().isEmpty()) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return objectMapper.readValue(serializedUserIds, new TypeReference<List<String>>() { });
|
|
|
+ } catch (JsonProcessingException exception) {
|
|
|
+ throw new IllegalStateException("Approval matrix cached manager user IDs are invalid", exception);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private String firstUserId(String serializedUserIds) {
|
|
|
+ List<String> userIds = readUserIds(serializedUserIds);
|
|
|
+ return userIds.isEmpty() ? null : userIds.get(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Object> toFormData(ApprovalMatrixCacheRecord record) {
|
|
|
+ Map<String, Object> formData = readSourceFormData(record);
|
|
|
+ formData.put(DEPARTMENT_ID_FIELD_ID, String.valueOf(record.getDepartmentId()));
|
|
|
+ formData.put(DEPARTMENT_NAME_FIELD_ID, record.getDepartmentName());
|
|
|
+ formData.put(APPLICATION_COMPANY_FIELD_ID, record.getApplicationCompany());
|
|
|
+ formData.put(FIRST_LEVEL_DEPARTMENT_MANAGER_FIELD_ID + "_id", readUserIds(record.getFirstLevelManagerUserIds()));
|
|
|
+ formData.put(SECOND_LEVEL_DEPARTMENT_MANAGER_FIELD_ID + "_id", readUserIds(record.getSecondLevelManagerUserIds()));
|
|
|
+ formData.put(THIRD_LEVEL_DEPARTMENT_MANAGER_FIELD_ID + "_id", readUserIds(record.getThirdLevelManagerUserIds()));
|
|
|
+ formData.put(FOURTH_LEVEL_DEPARTMENT_MANAGER_FIELD_ID + "_id", readUserIds(record.getFourthLevelManagerUserIds()));
|
|
|
+ formData.put(DEPARTMENT_LEADER_FIELD_ID + "_id", readUserIds(record.getDepartmentLeaderUserIds()));
|
|
|
+ return formData;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分页接口需要继续返回宜搭表单的完整字段,因此优先使用同步时留存的原始 formData。
|
|
|
+ *
|
|
|
+ * @param record 审批矩阵本地缓存记录
|
|
|
+ * @return 可供分页接口返回的表单字段
|
|
|
+ */
|
|
|
+ private Map<String, Object> readSourceFormData(ApprovalMatrixCacheRecord record) {
|
|
|
+ String sourceFormData = trimToNull(record.getSourceFormData());
|
|
|
+ if (sourceFormData == null) {
|
|
|
+ return new LinkedHashMap<String, Object>();
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return objectMapper.readValue(sourceFormData, new TypeReference<LinkedHashMap<String, Object>>() { });
|
|
|
+ } catch (JsonProcessingException exception) {
|
|
|
+ throw new IllegalStateException("Approval matrix cached formData is invalid", exception);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private Map firstFormData(Object records) {
|
|
|
if (!(records instanceof Iterable)) {
|
|
|
return null;
|
|
|
@@ -434,6 +594,20 @@ public class MingleiDocumentServiceImpl implements MingleiDocumentService {
|
|
|
return value == null ? null : trimToNull(String.valueOf(value));
|
|
|
}
|
|
|
|
|
|
+ private String firstText(Map values, String firstKey, String... otherKeys) {
|
|
|
+ String value = toStringValue(values.get(firstKey));
|
|
|
+ if (value != null) {
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+ for (String key : otherKeys) {
|
|
|
+ value = toStringValue(values.get(key));
|
|
|
+ if (value != null) {
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
private String trimToNull(String value) {
|
|
|
if (value == null) {
|
|
|
return null;
|