dobe_comic8/main/java/shkd/repc/task/DobeDWaccountTask.java

390 lines
19 KiB
Java
Raw Normal View History

2024-11-04 15:32:41 +00:00
package shkd.repc.task;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import kd.bos.context.RequestContext;
2025-04-24 08:56:40 +00:00
import kd.bos.dataentity.OperateOption;
2024-11-04 15:32:41 +00:00
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
2025-06-04 06:41:22 +00:00
import kd.bos.entity.operate.result.OperationResult;
2024-11-04 15:32:41 +00:00
import kd.bos.exception.KDException;
2025-04-25 08:21:32 +00:00
import kd.bos.id.ID;
2024-11-04 15:32:41 +00:00
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
2025-06-12 06:17:29 +00:00
import kd.bos.orm.query.QCP;
2024-11-04 15:32:41 +00:00
import kd.bos.orm.query.QFilter;
2025-06-12 06:17:29 +00:00
import kd.bos.schedule.api.MessageHandler;
2024-11-04 15:32:41 +00:00
import kd.bos.schedule.executor.AbstractTask;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.QueryServiceHelper;
2025-04-24 08:56:40 +00:00
import kd.bos.servicehelper.operation.OperationServiceHelper;
2024-11-04 15:32:41 +00:00
import kd.bos.servicehelper.operation.SaveServiceHelper;
import kd.sdk.plugin.Plugin;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import shkd.utils.DobeDWUtils;
import java.io.IOException;
2025-06-12 06:17:29 +00:00
import java.util.ArrayList;
2024-11-04 15:32:41 +00:00
import java.util.HashMap;
2025-06-12 06:17:29 +00:00
import java.util.List;
2024-11-04 15:32:41 +00:00
import java.util.Map;
/**
* 后台任务插件
2025-06-12 06:17:29 +00:00
* 数仓成本科目同步
* 同步规则以编码为准系统有则判断更新无则新增
2024-11-04 15:32:41 +00:00
*/
public class DobeDWaccountTask extends AbstractTask implements Plugin {
2025-04-24 08:56:40 +00:00
private static final Log logger = LogFactory.getLog(DobeDWaccountTask.class);
2024-11-04 15:32:41 +00:00
private static final String entityName = "recos_stdcostaccount";//标准成本科目实体 供应链库 表名 t_recos_scostaccount
private static final String acctViewEntity = "bd_accountview";//会计科目实体 财务库 表名 T_BD_Account
2025-04-24 08:56:40 +00:00
private static final String dw_menthod = "mdm_costsubject";
2024-11-04 15:32:41 +00:00
// private static final String accEntity = "costaccountentry";//科目分录实体 供应链库 表名 t_recos_costaccount
// private static final String projectEntity = "repmd_projectbill";//项目实体 表名 t_repmd_projectbill
@Override
public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
//调用数仓查询接口
OkHttpClient client = new OkHttpClient();
2025-06-12 06:17:29 +00:00
Request request = new Request.Builder().url(DobeDWUtils.dwUrl + dw_menthod)
.post(DobeDWUtils.createRequestBody("account", 1))
2024-11-04 15:32:41 +00:00
.header("Content-Type", "application/json")
.header("Authorization", DobeDWUtils.appCode)
.build();
2025-04-24 08:56:40 +00:00
String resultData;
2024-11-04 15:32:41 +00:00
try {
Response response = client.newCall(request).execute();
resultData = response.body().string();
2025-04-24 08:56:40 +00:00
logger.info("成本科目接口返回结果:\n{}", resultData);
2024-11-04 15:32:41 +00:00
} catch (IOException e) {
2025-04-24 08:56:40 +00:00
logger.info(String.format("成本科目接口异常:%s", e.getMessage()));
2025-06-04 06:41:22 +00:00
throw new RuntimeException("获取数仓成本科目数据失败", e);
2024-11-04 15:32:41 +00:00
}
JSONObject json_body = JSON.parseObject(resultData);
2025-04-24 08:56:40 +00:00
//定时任务获取的参数和参数值是配置调度程序和作业的时候设置根据参数值保存从数仓获取到的完整json
2025-06-12 06:17:29 +00:00
if (map != null && "yes".equals(map.get("savedwjson"))) {
DobeDWUtils.saveLog("savedwjson1", "成本科目接口", resultData, null, true, "定时任务");
2025-04-24 08:56:40 +00:00
}
2024-11-04 15:32:41 +00:00
//接口返回的数据进行了分页
// int totalNum = json_body.getIntValue("totalNum");//分页-SQL查询总数据量
//根据id查找标准成本科目的表头信息
2025-04-24 08:56:40 +00:00
long bzkmid;
String accountId = requestContext.getAccountId();//获取账套ID
2025-06-12 06:17:29 +00:00
if ("2231954870896690176".equals(accountId)) {
bzkmid = 2234107107932663808L;//测试id
} else {
2025-04-24 08:56:40 +00:00
bzkmid = 2037039962179791872L;//正式id
}
2025-06-12 06:17:29 +00:00
logger.info("accountId " + accountId);
DynamicObject billinfo = BusinessDataServiceHelper.loadSingle(entityName, new QFilter[]{new QFilter("id", "=", bzkmid)});
if (billinfo == null) {
2024-11-04 15:32:41 +00:00
//根据标准科目id未找到对应记录
2025-06-12 06:17:29 +00:00
DobeDWUtils.saveLog(bzkmid + "", "数仓成本科目同步", "", "根据标准科目ID未找到对应记录" + bzkmid, false, "定时任务");
2024-11-04 15:32:41 +00:00
return;
}
2025-06-12 06:17:29 +00:00
2024-11-04 15:32:41 +00:00
JSONArray detailsJson = json_body.getJSONArray("data");
2025-06-12 06:17:29 +00:00
if (detailsJson==null || detailsJson.isEmpty()){
logger.info("解析data为空不继续处理");
return;
}
2025-04-24 08:56:40 +00:00
DynamicObjectCollection doDetails = billinfo.getDynamicObjectCollection("costaccountentry");//标准科目分录数据
2025-06-12 06:17:29 +00:00
if (doDetails!=null && doDetails.size()!=0){
//成本科目最少需要一级数据一条,例:CB
this.dataComparison(detailsJson,doDetails,billinfo);
}
//调用保存操作
OperationResult save = OperationServiceHelper.executeOperate("save", entityName, new DynamicObject[]{billinfo}, OperateOption.create());
if (!save.isSuccess()) {
logger.error(save.getMessage());
2024-11-04 15:32:41 +00:00
}
2025-06-12 06:17:29 +00:00
}
private void dataComparison(JSONArray detailsJson, DynamicObjectCollection doDetails,DynamicObject billinfo) {
// 用于存储需要新增的数据(接口中有但系统中没有的)
List<JSONObject> toAddList = new ArrayList<>();
int updateCount = 0; // 记录更新条数
int addCount = 0; // 记录新增条数
2024-11-04 15:32:41 +00:00
for (int i = 0; i < detailsJson.size(); i++) {
2025-06-12 06:17:29 +00:00
JSONObject jsonObject = detailsJson.getJSONObject(i);
String status = jsonObject.getString("costsubject_status");
if ("启用".equals(status)) {
String code = jsonObject.getString("costsubject_code");
if (code != null) {
boolean found = false;
for (int j = 0; j < doDetails.size(); j++) {
DynamicObject dynamicObject = doDetails.get(j);
String longNumber = dynamicObject.getString("caentry_longnumber");
2025-04-24 08:56:40 +00:00
2025-06-12 06:17:29 +00:00
if (longNumber != null) {
// 去除系统中的"."后与接口编码比较
String cleanedLongNumber = longNumber.replace(".", "");
if (code.equals(cleanedLongNumber)) {
found = true;
// 检查名称或其他字段是否有变化
String systemName = dynamicObject.getString("caentry_name"); // 假设系统中名称字段为caentry_name
String jsonName = jsonObject.getString("costsubject_name");
// 如果名称不同或需要检查其他字段变化,则直接更新
if (!jsonName.equals(systemName)) {
//更新科目名称
dynamicObject.set("caentry_name",jsonName);
updateCount++;
System.out.println("[MyLog]更新科目: " + jsonName + ", 编码: " + code);
logger.info("更新科目名称: {}, 编码: {}", jsonName, code);
}
//会计科目
String accSubjectCode = jsonObject.getString("accsubject_code");
if (accSubjectCode!=null){
DynamicObject sysAccount = dynamicObject.getDynamicObject("caentry_account");
if (sysAccount==null){
//直接匹配会计科目赋值id
Long accountId=this.getSysAccountId(accSubjectCode);
if (accountId!=null){
dynamicObject.set("caentry_account",accountId);
logger.info("成功关联会计科目,科目编码: {}, 会计科目ID: {}", code, accountId);
System.out.println("[MyLog]关联会计科目: " + code + " -> " + accountId);
}
}else {
//编码匹配是否改变
String number = sysAccount.getString("number");
if (!accSubjectCode.equals(number)){
//匹配会计科目赋值id
Long accountId=this.getSysAccountId(accSubjectCode);
if (accountId!=null){
dynamicObject.set("caentry_account",accountId);
logger.info("更新会计科目关联成功,科目编码: {}, 新会计科目ID: {}", code, accountId);
System.out.println("[MyLog]更新会计科目关联: " + code + " -> " + accountId);
}
}
}
}
break; // 找到匹配项后跳出循环
}
}
}
// 如果没有找到匹配项,则加入新增列表
if (!found) {
toAddList.add(jsonObject);
addCount++;
System.out.println("[MyLog]准备新增科目: " + jsonObject.getString("costsubject_name") + ", 编码: " + code);
logger.info("准备新增科目: {}, 编码: {}", jsonObject.getString("costsubject_name"), code);
}
2024-11-04 15:32:41 +00:00
}
2025-06-12 06:17:29 +00:00
}
}
// 打印统计信息
System.out.println("[MyLog]数据比对结果 - 更新条数: " + updateCount + ", 新增条数: " + addCount);
logger.info("数据比对结果 - 更新条数: {}, 新增条数: {}", updateCount, addCount);
//更新
if (toAddList.size()!=0){
this.addCostSubject(toAddList,doDetails,billinfo);
}
}
/**
* 获取会计科目id
* @param accSubjectCode
* @return
*/
private Long getSysAccountId(String accSubjectCode) {
Long pkValue = null;
QFilter number = new QFilter("number", QCP.equals, accSubjectCode);
DynamicObject dynamicObject = BusinessDataServiceHelper.loadSingle("bd_accountview", number.toArray());
if (dynamicObject!=null){
pkValue= (Long) dynamicObject.getPkValue();
}
return pkValue;
}
/**
* 新增标准成本科目数据
* @param toAddList 需要新增的数据
* @param doDetails 单据体
*/
private void addCostSubject(List<JSONObject> toAddList, DynamicObjectCollection doDetails,DynamicObject billinfo) {
System.out.println("[MyLog]开始新增科目,数量: " + toAddList.size());
logger.info("开始新增科目,数量: {}", toAddList.size());
// 用于缓存已创建的父级科目
Map<String, DynamicObject> parentCache = new HashMap<>();
for (JSONObject jsonObject : toAddList) {
try {
// 1. 准备基础数据
//父级编码CB001
String pCode = jsonObject.getString("costsubject_pcode");
//系统需要的编码CB.001
String formattedCode = formatParentCode(pCode);
//科目编码CB001002
String code = jsonObject.getString("costsubject_code");
//系统短编码002
String shortNumber = code.substring(pCode.length());
// 2. 处理父级科目
DynamicObject parentEntry = findOrCreateParent(
jsonObject, pCode, formattedCode, doDetails, parentCache,billinfo);
// 设置父级科目行号(如果父级是新创建的)
if (!parentCache.containsKey(formattedCode)) {
parentEntry.set("seq", doDetails.size()-1); // 使用当前总条数作为行号
parentCache.put(formattedCode, parentEntry);
System.out.println("[MyLog]新增父级科目: " + parentEntry.getString("caentry_name") +
", 编码: " + parentEntry.getString("caentry_longnumber"));
logger.info("新增父级科目: {}, 编码: {}",
parentEntry.getString("caentry_name"),
parentEntry.getString("caentry_longnumber"));
2024-11-04 15:32:41 +00:00
}
2025-06-12 06:17:29 +00:00
// 3. 创建当前科目
DynamicObject dynamicObject = doDetails.addNew();
setupDynamicObject(dynamicObject, jsonObject, parentEntry, formattedCode, shortNumber);
// 4. 设置当前科目行号
dynamicObject.set("seq", doDetails.size()-1); // 使用当前总条数-1作为行号
System.out.println("[MyLog]新增科目: " + dynamicObject.getString("caentry_name") +
", 编码: " + dynamicObject.getString("caentry_longnumber"));
logger.info("新增科目: {}, 编码: {}",
dynamicObject.getString("caentry_name"),
dynamicObject.getString("caentry_longnumber"));
} catch (Exception e) {
System.err.println("[MyLog]新增科目失败: " + jsonObject.getString("costsubject_name") +
", 错误: " + e.getMessage());
logger.error("新增科目失败: {}, 错误: {}", jsonObject.getString("costsubject_name"), e.getMessage(), e);
2024-11-04 15:32:41 +00:00
}
}
2025-06-12 06:17:29 +00:00
System.out.println("[MyLog]科目新增完成,共新增: " + toAddList.size() + "条记录");
logger.info("科目新增完成,共新增: {}条记录", toAddList.size());
}
/**
* 查找或创建父级科目
*/
private DynamicObject findOrCreateParent(JSONObject jsonObject, String pCode,
String formattedCode, DynamicObjectCollection doDetails,
Map<String, DynamicObject> cache,DynamicObject billinfo) {
// 1. 先检查缓存
if (cache.containsKey(formattedCode)) {
return cache.get(formattedCode);
2025-06-04 06:41:22 +00:00
}
2025-06-12 06:17:29 +00:00
// 2. 在现有数据中查找
for (DynamicObject entry : doDetails) {
if (formattedCode.equals(entry.getString("caentry_longnumber"))) {
return entry;
}
}
// 3. 查找顶级父级科目CB
DynamicObject topParent = findTopParent(doDetails);
if (topParent == null) {
throw new RuntimeException("未找到顶级父级科目CB");
}
// 4. 创建新的父级科目
DynamicObject parentEntry = doDetails.addNew();
String parentShortCode = pCode.substring(2);
// 设置父级科目属性
parentEntry.set("pid", topParent.getPkValue()); // 父级 ID——CB
parentEntry.set("caentry_number", parentShortCode);
parentEntry.set("caentry_longnumber", formattedCode);
parentEntry.set("caentry_name", jsonObject.getString("costsubject_pname"));
parentEntry.set("caentry_enable", true);
parentEntry.set("caentry_org", 100000L);
parentEntry.set("caentry_createorg", 100000L);
parentEntry.set("caentry_useorg", 100000L);
parentEntry.set("caentry_isleaf", false);
parentEntry.set("caentry_level", 2);
parentEntry.set("caentry_standlibflag", true);
parentEntry.set("caentry_isimportaccount", false);
parentEntry.set("caentry_isstdaccount", true);
// 立即保存父级科目以生成pkValue
OperationResult saveResult = OperationServiceHelper.executeOperate("save", entityName,
new DynamicObject[]{billinfo}, OperateOption.create());
if (!saveResult.isSuccess()) {
throw new RuntimeException("保存父级科目失败: " + saveResult.getMessage());
}
return parentEntry;
}
/**
* 设置科目属性
*/
private void setupDynamicObject(DynamicObject dynamicObject, JSONObject jsonObject,
DynamicObject parentEntry, String formattedCode, String shortNumber) {
// 1. 设置基础属性
dynamicObject.set("pid", parentEntry.getPkValue());
dynamicObject.set("caentry_fullname", "开发成本_" + parentEntry.getString("caentry_name") +
"_" + jsonObject.getString("costsubject_name"));
dynamicObject.set("caentry_number", shortNumber);
dynamicObject.set("caentry_longnumber", formattedCode + "." + shortNumber);
dynamicObject.set("caentry_name", jsonObject.getString("costsubject_name"));
// 2. 设置固定属性
dynamicObject.set("caentry_ciaccountflag", "1");
dynamicObject.set("caentry_measureway", 1026043947790783488L);
dynamicObject.set("caentry_apportionway", 1026043947790783488L);
dynamicObject.set("caentry_enable", true);
dynamicObject.set("caentry_org", 100000L);
dynamicObject.set("caentry_createorg", 100000L);
dynamicObject.set("caentry_useorg", 100000L);
dynamicObject.set("caentry_isleaf", true);
dynamicObject.set("caentry_level", 3);
dynamicObject.set("caentry_srcid", dynamicObject.getPkValue());
dynamicObject.set("caentry_standlibflag", true);
dynamicObject.set("caentry_isimportaccount", false);
dynamicObject.set("caentry_isstdaccount", true);
// 3. 会计科目
String accSubjectCode = jsonObject.getString("accsubject_code");
if (jsonObject.getString("accsubject_code") != null) {
Long accountId=this.getSysAccountId(accSubjectCode);
if (accountId!=null){
dynamicObject.set("caentry_account",accountId);
}
}
}
/**
* 查找顶级父级科目CB
*/
private DynamicObject findTopParent(DynamicObjectCollection doDetails) {
for (DynamicObject entry : doDetails) {
if ("CB".equals(entry.getString("caentry_longnumber"))) {
return entry;
}
}
return null;
}
/**
* 格式化父级编码CB0010 CB.0010;CB001 CB.001
*/
private String formatParentCode(String pCode) {
String prefix = pCode.substring(0, 2); // 获取前两位字母CB
String numberPart = pCode.substring(2); // 获取数字部分(001)
return prefix + "." + numberPart;//CB.001
2024-11-04 15:32:41 +00:00
}
}