|
|
|
@ -1,33 +1,32 @@
|
|
|
|
|
package com.ruoyi.quartz.task.CJT;
|
|
|
|
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
import com.lark.oapi.service.bitable.v1.model.CreateAppTableRecordRespBody;
|
|
|
|
|
import com.lark.oapi.service.bitable.v1.model.AppTableRecord;
|
|
|
|
|
import com.lark.oapi.service.bitable.v1.model.BatchCreateAppTableRecordRespBody;
|
|
|
|
|
import com.ruoyi.common.constant.RedisConstants;
|
|
|
|
|
import com.ruoyi.common.core.redis.RedisCache;
|
|
|
|
|
import com.ruoyi.common.enums.*;
|
|
|
|
|
import com.ruoyi.common.utils.DateUtils;
|
|
|
|
|
import com.ruoyi.common.enums.AppType;
|
|
|
|
|
import com.ruoyi.common.enums.CjtAccountEnum;
|
|
|
|
|
import com.ruoyi.common.enums.FlagStatus;
|
|
|
|
|
import com.ruoyi.common.enums.TableRelationTypeEnum;
|
|
|
|
|
import com.ruoyi.flyingbook.LarkHelper.LarkRobotHelper;
|
|
|
|
|
import com.ruoyi.flyingbook.LarkHelper.LarkTableHelper;
|
|
|
|
|
import com.ruoyi.flyingbook.domain.ErpLarkRelation;
|
|
|
|
|
import com.ruoyi.flyingbook.domain.ErpLarkTempRelation;
|
|
|
|
|
import com.ruoyi.flyingbook.domain.LarkCompanyRelation;
|
|
|
|
|
import com.ruoyi.flyingbook.domain.LarkTableRelation;
|
|
|
|
|
import com.ruoyi.flyingbook.domain.lark.LarkTableRequest;
|
|
|
|
|
import com.ruoyi.flyingbook.mapper.ErpLarkRelationMapper;
|
|
|
|
|
import com.ruoyi.flyingbook.mapper.ErpLarkTempRelationMapper;
|
|
|
|
|
import com.ruoyi.flyingbook.mapper.LarkCompanyRelationMapper;
|
|
|
|
|
import com.ruoyi.flyingbook.mapper.LarkTableRelationMapper;
|
|
|
|
|
import com.ruoyi.quartz.domain.*;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
|
|
import org.springframework.util.StringUtils;
|
|
|
|
|
import org.apache.commons.collections4.CollectionUtils;
|
|
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
|
|
|
|
|
import java.time.LocalDate;
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
import java.time.ZoneId;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
import static com.ruoyi.quartz.helper.OkHttpHelper.post;
|
|
|
|
|
|
|
|
|
@ -38,22 +37,20 @@ import static com.ruoyi.quartz.helper.OkHttpHelper.post;
|
|
|
|
|
* @create 2023-07-17 20:29
|
|
|
|
|
*/
|
|
|
|
|
@Slf4j
|
|
|
|
|
public abstract class SyncReportJob {
|
|
|
|
|
public class SyncReportJob {
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
private RedisCache redisCache;
|
|
|
|
|
@Autowired
|
|
|
|
|
protected ErpLarkRelationMapper erpLarkRelationMapper;
|
|
|
|
|
@Autowired
|
|
|
|
|
private LarkCompanyRelationMapper larkCompanyRelationMapper;
|
|
|
|
|
@Autowired
|
|
|
|
|
private LarkTableRelationMapper larkTableRelationMapper;
|
|
|
|
|
@Autowired
|
|
|
|
|
private ErpLarkTempRelationMapper erpLarkTempRelationMapper;
|
|
|
|
|
@Autowired
|
|
|
|
|
private LarkTableHelper larkTableHelper;
|
|
|
|
|
@Autowired
|
|
|
|
|
private LarkRobotHelper larkRobotHelper;
|
|
|
|
|
@Autowired
|
|
|
|
|
private CJTCreateLarkTableJob cjtCreateLarkTableJob;
|
|
|
|
|
@Value("${lark.robot.group}")
|
|
|
|
|
private String ROBOT_GROUP;
|
|
|
|
|
@Value("${sync.flag}")
|
|
|
|
@ -95,8 +92,10 @@ public abstract class SyncReportJob {
|
|
|
|
|
initLarkInfo(context);
|
|
|
|
|
//重置ticket
|
|
|
|
|
resetTicket(context);
|
|
|
|
|
preSync(context);
|
|
|
|
|
//执行分页同步
|
|
|
|
|
sync(context);
|
|
|
|
|
finish(context);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("{} 执行失败", getClassName(), e);
|
|
|
|
|
larkRobotHelper.sendMessageByBot(ROBOT_GROUP, buildRobotErrorCountMessage(e));
|
|
|
|
@ -113,7 +112,7 @@ public abstract class SyncReportJob {
|
|
|
|
|
JSONObject jsonObject = new JSONObject();
|
|
|
|
|
jsonObject.put("同步报表任务", getClassName());
|
|
|
|
|
String errorMessage = e.getMessage();
|
|
|
|
|
if (org.apache.commons.lang3.StringUtils.isNotBlank(errorMessage)) {
|
|
|
|
|
if (StringUtils.isNotBlank(errorMessage)) {
|
|
|
|
|
errorMessage = errorMessage.replaceAll("\\\\", "");
|
|
|
|
|
}
|
|
|
|
|
jsonObject.put("异常信息", errorMessage);
|
|
|
|
@ -153,15 +152,12 @@ public abstract class SyncReportJob {
|
|
|
|
|
/**
|
|
|
|
|
* 获取待查询的字段
|
|
|
|
|
*/
|
|
|
|
|
protected String getQueryFields(){
|
|
|
|
|
protected String getQueryFields() {
|
|
|
|
|
return "Warehouse,InventoryCode,Inventory,BaseQuantity,canuseBaseQuantity";
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取查询条件
|
|
|
|
|
*/
|
|
|
|
|
protected abstract String getQueryKey();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取当前执行类名
|
|
|
|
@ -170,76 +166,102 @@ public abstract class SyncReportJob {
|
|
|
|
|
return this.getClass().getSimpleName();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 同步数据
|
|
|
|
|
*
|
|
|
|
|
* @param context
|
|
|
|
|
*/
|
|
|
|
|
protected void sync(CJTJobContext context) {
|
|
|
|
|
String errorMessage = null;
|
|
|
|
|
|
|
|
|
|
List<String> errorMessageList = new ArrayList<>();
|
|
|
|
|
JSONObject cjtRequestReport = new JSONObject();
|
|
|
|
|
CJTRequestReportBody cjtRequestBody = new CJTRequestReportBody(0, PAGE_SIZE, getReportName(),getQueryFields());
|
|
|
|
|
CJTRequestReportBody cjtRequestBody = new CJTRequestReportBody(0, PAGE_SIZE, getReportName(), getQueryFields());
|
|
|
|
|
cjtRequestReport.put("request", cjtRequestBody);
|
|
|
|
|
CJTRequest cjtRequest = buildCJTRequest(context, cjtRequestReport);
|
|
|
|
|
|
|
|
|
|
List<Integer> pageList = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
LarkCompanyRelation companyRelation = context.getCompanyRelation();
|
|
|
|
|
LarkTableRelation tableRelation = context.getTableRelation();
|
|
|
|
|
LarkTableRequest addRecordRequest = new LarkTableRequest(companyRelation.getAppId(), companyRelation.getSecret(), tableRelation.getToAppToken(), tableRelation.getToTableId());
|
|
|
|
|
List<CJTResponseReportBodyDetailRow> rows = new ArrayList<>();
|
|
|
|
|
Boolean flag = Boolean.TRUE;
|
|
|
|
|
do {
|
|
|
|
|
try {
|
|
|
|
|
cjtRequest.setOpenToken(generateToken(context));
|
|
|
|
|
//请求接口并序列化数据
|
|
|
|
|
CJTResponseReportBodyDetail bodyDetail = request(cjtRequest);
|
|
|
|
|
//实际返回数据
|
|
|
|
|
rows = bodyDetail.getRows();
|
|
|
|
|
if (!CollectionUtils.isEmpty(rows)) {
|
|
|
|
|
//批量同步飞书
|
|
|
|
|
List<String> errorCodeList = syncLarkBatch(rows, addRecordRequest, context.getCjt());
|
|
|
|
|
if (!CollectionUtils.isEmpty(errorCodeList)) {
|
|
|
|
|
String errorKey = String.join(",", errorCodeList);
|
|
|
|
|
throw new RuntimeException(String.format("存在同步失败的记录 %s", errorKey));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
flag = executeDetail(context, cjtRequest, addRecordRequest);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("{} exception", this.getClassName(), e);
|
|
|
|
|
errorMessage = buildErrorBody(cjtRequest, e.getMessage());
|
|
|
|
|
pageList.add(cjtRequestBody.getPageIndex());
|
|
|
|
|
} finally {
|
|
|
|
|
cjtRequestBody.addPage();
|
|
|
|
|
}
|
|
|
|
|
} while (!CollectionUtils.isEmpty(rows));
|
|
|
|
|
if (!StringUtils.isEmpty(errorMessage)) {
|
|
|
|
|
throw new RuntimeException(errorMessage);
|
|
|
|
|
} while (flag);
|
|
|
|
|
for (Integer pageIndex : pageList) {
|
|
|
|
|
try {
|
|
|
|
|
cjtRequestBody.setPageIndex(pageIndex);
|
|
|
|
|
executeDetail(context, cjtRequest, addRecordRequest);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
errorMessageList.add(String.valueOf(pageIndex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (CollectionUtils.isNotEmpty(errorMessageList)) {
|
|
|
|
|
throw new RuntimeException(buildErrorBody(cjtRequest, errorMessageList));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void preSync(CJTJobContext context) {
|
|
|
|
|
erpLarkTempRelationMapper.updateByMethod(getReportName(), FlagStatus.DELETED.getCode());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Object changeValueType(String value, CJTSyncTypeRelation cjtSyncTypeRelation) {
|
|
|
|
|
TableFieldTypeEnum type = cjtSyncTypeRelation.getType();
|
|
|
|
|
if (org.apache.commons.lang3.StringUtils.isBlank(value) || type == null) {
|
|
|
|
|
return value;
|
|
|
|
|
private void finish(CJTJobContext context) {
|
|
|
|
|
try {
|
|
|
|
|
LarkCompanyRelation companyRelation = context.getCompanyRelation();
|
|
|
|
|
LarkTableRelation tableRelation = context.getTableRelation();
|
|
|
|
|
LarkTableRequest request = new LarkTableRequest(companyRelation.getAppId(), companyRelation.getSecret(), tableRelation.getToAppToken(), tableRelation.getToTableId());
|
|
|
|
|
ErpLarkTempRelation query = new ErpLarkTempRelation();
|
|
|
|
|
query.setMethod(getReportName());
|
|
|
|
|
query.setFlag(FlagStatus.DELETED.getCode());
|
|
|
|
|
List<ErpLarkTempRelation> erpLarkTempRelations = erpLarkTempRelationMapper.selectErpLarkTempRelationList(query);
|
|
|
|
|
List<String> larkKeyList = new ArrayList<>();
|
|
|
|
|
for (ErpLarkTempRelation erpLarkTempRelation : erpLarkTempRelations) {
|
|
|
|
|
String larkKey = erpLarkTempRelation.getLarkKey();
|
|
|
|
|
if (StringUtils.isBlank(larkKey)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
larkKeyList.add(larkKey);
|
|
|
|
|
if (larkKeyList.size() == 500) {
|
|
|
|
|
request.setRecords(larkKeyList.toArray(new String[0]));
|
|
|
|
|
larkTableHelper.deleteTableRecordBatch(request);
|
|
|
|
|
larkKeyList = new ArrayList<>();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
erpLarkTempRelationMapper.deleteByMethod(getReportName(), FlagStatus.DELETED.getCode());
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.info("Sync report job finish error", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case NUMBER:
|
|
|
|
|
return Double.valueOf(value);
|
|
|
|
|
case DATE:
|
|
|
|
|
LocalDateTime localDateTime = DateUtils.str2ldt(value, cjtSyncTypeRelation.getPattern());
|
|
|
|
|
return DateUtils.ldt2Long(localDateTime);
|
|
|
|
|
default:
|
|
|
|
|
return value;
|
|
|
|
|
private Boolean executeDetail(CJTJobContext context, CJTRequest cjtRequest, LarkTableRequest addRecordRequest) {
|
|
|
|
|
cjtRequest.setOpenToken(generateToken(context));
|
|
|
|
|
//请求接口并序列化数据
|
|
|
|
|
CJTResponseReportBodyDetail bodyDetail = request(cjtRequest);
|
|
|
|
|
//实际返回数据
|
|
|
|
|
List<CJTResponseReportBodyDetailRow> rows = bodyDetail.getRows();
|
|
|
|
|
if (CollectionUtils.isNotEmpty(rows)) {
|
|
|
|
|
//批量同步飞书
|
|
|
|
|
List<String> errorCodeList = syncLarkBatch(rows, addRecordRequest, context.getCjt());
|
|
|
|
|
if (!CollectionUtils.isEmpty(errorCodeList)) {
|
|
|
|
|
String errorKey = String.join(",", errorCodeList);
|
|
|
|
|
throw new RuntimeException(String.format("存在同步失败的记录 %s", errorKey));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return CollectionUtils.isNotEmpty(rows);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected Map<String,Object> buildLarkBody(CJTResponseReportBodyDetailRow rowDetail){
|
|
|
|
|
protected Map<String, Object> buildLarkBody(CJTResponseReportBodyDetailRow rowDetail) {
|
|
|
|
|
Map<String, Object> body = new HashMap<>();
|
|
|
|
|
body.put("仓库",rowDetail.getWarehouse());
|
|
|
|
|
body.put("存货编码",rowDetail.getInventoryCode());
|
|
|
|
|
body.put("现存量",rowDetail.getBaseQuantity());
|
|
|
|
|
body.put("可用量",rowDetail.getCanuseBaseQuantity());
|
|
|
|
|
body.put("仓库", rowDetail.getWarehouse());
|
|
|
|
|
body.put("存货编码", rowDetail.getInventoryCode());
|
|
|
|
|
body.put("现存量", rowDetail.getBaseQuantity());
|
|
|
|
|
body.put("可用量", rowDetail.getCanuseBaseQuantity());
|
|
|
|
|
return body;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -247,21 +269,45 @@ public abstract class SyncReportJob {
|
|
|
|
|
* 执行字段映射
|
|
|
|
|
*/
|
|
|
|
|
protected List<String> syncLarkBatch(List<CJTResponseReportBodyDetailRow> rows, LarkTableRequest addRecordRequest, String cjt) {
|
|
|
|
|
//错误唯一键
|
|
|
|
|
List<String> errorKey = new ArrayList<>();
|
|
|
|
|
for (CJTResponseReportBodyDetailRow row : rows) {
|
|
|
|
|
try {
|
|
|
|
|
try {
|
|
|
|
|
//错误唯一键
|
|
|
|
|
List<AppTableRecord> list = new ArrayList<>();
|
|
|
|
|
List<ErpLarkTempRelation> waitCreateList = new ArrayList<>();
|
|
|
|
|
for (CJTResponseReportBodyDetailRow row : rows) {
|
|
|
|
|
Map<String, Object> body = buildLarkBody(row);
|
|
|
|
|
addRecordRequest.setBody(body);
|
|
|
|
|
AppTableRecord appTableRecord = new AppTableRecord();
|
|
|
|
|
appTableRecord.setFields(body);
|
|
|
|
|
list.add(appTableRecord);
|
|
|
|
|
}
|
|
|
|
|
if (CollectionUtils.isNotEmpty(list)){
|
|
|
|
|
addRecordRequest.setAppTableRecords(list.toArray(new AppTableRecord[0]));
|
|
|
|
|
//在飞书创建一行,并根据创建返回的行id在本地保留一条映射纪律
|
|
|
|
|
larkTableHelper.addTableRecord(addRecordRequest);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("{} addOrUpdate exception", this.getClassName(), e);
|
|
|
|
|
BatchCreateAppTableRecordRespBody resp = larkTableHelper.addTableRecordBatch(addRecordRequest);
|
|
|
|
|
for (AppTableRecord record : resp.getRecords()) {
|
|
|
|
|
buildTempList(waitCreateList,record.getRecordId());
|
|
|
|
|
}
|
|
|
|
|
if (CollectionUtils.isNotEmpty(waitCreateList)){
|
|
|
|
|
erpLarkTempRelationMapper.batchInsert(waitCreateList);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("{} addOrUpdate exception", this.getClassName(), e);
|
|
|
|
|
}
|
|
|
|
|
return errorKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void buildTempList(List<ErpLarkTempRelation> waitCreateList,String recordId){
|
|
|
|
|
ErpLarkTempRelation erpLarkTempRelation = new ErpLarkTempRelation();
|
|
|
|
|
erpLarkTempRelation.setCreateTime(new Date());
|
|
|
|
|
erpLarkTempRelation.setCreateBy("System");
|
|
|
|
|
erpLarkTempRelation.setMethod(getReportName());
|
|
|
|
|
erpLarkTempRelation.setFlag(FlagStatus.OK.getCode());
|
|
|
|
|
erpLarkTempRelation.setLarkKey(recordId);
|
|
|
|
|
waitCreateList.add(erpLarkTempRelation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private String buildCacheUniqueKey(String key, String appKey) {
|
|
|
|
|
return String.format("%s:%s", key, appKey);
|
|
|
|
@ -296,7 +342,7 @@ public abstract class SyncReportJob {
|
|
|
|
|
private String generateToken(CJTJobContext context) {
|
|
|
|
|
String tokenCacheKey = buildCacheUniqueKey(RedisConstants.CJT_TOKEN_CACHE_KEY, context.getAppKey());
|
|
|
|
|
String openToken = (String) redisCache.getCacheObject(tokenCacheKey);
|
|
|
|
|
if (StringUtils.isEmpty(openToken)) {
|
|
|
|
|
if (StringUtils.isBlank(openToken)) {
|
|
|
|
|
CJTRequest cjtRequest = new CJTRequest(REQUEST_GENERATE_TOKEN_PATH
|
|
|
|
|
, context.getAppKey()
|
|
|
|
|
, context.getAppSecret()
|
|
|
|
@ -357,16 +403,16 @@ public abstract class SyncReportJob {
|
|
|
|
|
CJTResponseReportBody responseBody = JSONObject.parseObject(post, CJTResponseReportBody.class);
|
|
|
|
|
if (!"0".equals(responseBody.getStatus())) {
|
|
|
|
|
log.error("{} exception", this.getClassName(), responseBody.getErrorMessage());
|
|
|
|
|
throw new RuntimeException(buildErrorBody(req, responseBody.getErrorMessage()));
|
|
|
|
|
throw new RuntimeException(buildErrorBody(req, Arrays.asList(responseBody.getErrorMessage())));
|
|
|
|
|
}
|
|
|
|
|
return responseBody.getDataSource();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected String buildErrorBody(CJTRequest req, String errorMessage) {
|
|
|
|
|
protected String buildErrorBody(CJTRequest req, List<String> errorPageIndexList) {
|
|
|
|
|
JSONObject errorInfo = new JSONObject();
|
|
|
|
|
errorInfo.put("url", req.getUrl());
|
|
|
|
|
errorInfo.put("body", JSONObject.toJSONString(req.getBody()));
|
|
|
|
|
errorInfo.put("errorMessage", errorMessage);
|
|
|
|
|
errorInfo.put("errorMessage", String.join(",", errorPageIndexList));
|
|
|
|
|
return errorInfo.toJSONString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|