数仓成本科目同步接口1.0

This commit is contained in:
李贵强 2025-06-12 14:17:29 +08:00
parent e0f8d37841
commit 1df9368967
1 changed files with 309 additions and 107 deletions

View File

@ -12,7 +12,9 @@ import kd.bos.exception.KDException;
import kd.bos.id.ID;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.schedule.api.MessageHandler;
import kd.bos.schedule.executor.AbstractTask;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.QueryServiceHelper;
@ -25,11 +27,15 @@ import okhttp3.Response;
import shkd.utils.DobeDWUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 后台任务插件
* 数仓成本科目同步
* 同步规则以编码为准系统有则判断更新无则新增
*/
public class DobeDWaccountTask extends AbstractTask implements Plugin {
@ -63,15 +69,15 @@ public class DobeDWaccountTask extends AbstractTask implements Plugin {
JSONObject json_body = JSON.parseObject(resultData);
//定时任务获取的参数和参数值是配置调度程序和作业的时候设置根据参数值保存从数仓获取到的完整json
if (map != null && "yes".equals(map.get("savedwjson"))) {
DobeDWUtils.saveLog("savedwjson1","科目接口",resultData,null,true,"定时任务");
DobeDWUtils.saveLog("savedwjson1", "成本科目接口", resultData, null, true, "定时任务");
}
//接口返回的数据进行了分页
// int totalNum = json_body.getIntValue("totalNum");//分页-SQL查询总数据量
//根据id查找标准成本科目的表头信息
long bzkmid;
String accountId = requestContext.getAccountId();//获取账套ID
if("2008012388581769216".equals(accountId)){
bzkmid = 2012525353133704192L;//测试id
if ("2231954870896690176".equals(accountId)) {
bzkmid = 2234107107932663808L;//测试id
} else {
bzkmid = 2037039962179791872L;//正式id
}
@ -82,107 +88,303 @@ public class DobeDWaccountTask extends AbstractTask implements Plugin {
DobeDWUtils.saveLog(bzkmid + "", "数仓成本科目同步", "", "根据标准科目ID未找到对应记录" + bzkmid, false, "定时任务");
return;
}
// String acctid = null;//成本科目数仓id
String number;//成本科目编号
String name;//成本科名称
// String ciaccountflag = null; //科目类别 非建安科目and建安科目
// String apportionway = null;
// String taxrate = null;
String kjkm_num;//会计科目编号
String kjkm_name;//会计科目名称
String parentnumber;//成本科目父级编号
DynamicObject acctinfo;//成本科目对象
DynamicObject parentAcctinfo;//父级成本科目对象
DynamicObject acctViewinfo;//会计科目对象
Map<String,DynamicObject> parentAccts = new HashMap<>();//现有成本科目集合
Map<String,DynamicObject> acctViewMap = new HashMap<>();//会计科目缓存
JSONArray detailsJson = json_body.getJSONArray("data");
if (detailsJson==null || detailsJson.isEmpty()){
logger.info("解析data为空不继续处理");
return;
}
DynamicObjectCollection doDetails = billinfo.getDynamicObjectCollection("costaccountentry");//标准科目分录数据
for (int i = 0; i < doDetails.size(); i++) {
acctinfo = doDetails.get(i);
//以数仓科目id作为key科目对象为value
// parentAccts.put(acctinfo.getString("caentry_srcid"),acctinfo);
if(acctinfo.getBoolean("caentry_enable")){
//只加载已启用的科目
parentAccts.put(acctinfo.getString("caentry_number"),acctinfo);
}
}
//循环入参判断哪些科目该修改哪些该新增
for (int i = 0; i < detailsJson.size(); i++) {
json_body = detailsJson.getJSONObject(i);
// acctid = json_body.getString("costsubject_id");//科目id
number = json_body.getString("costsubject_code");//科目编号
name = json_body.getString("costsubject_name");//科目名称
kjkm_num = json_body.getString("accsubject_code");//会计科目编码
kjkm_name = json_body.getString("accsubject_name");//会计科目名称
// ciaccountflag = json_body.getString("ciaccountflag");//科目类别 非建安科目and建安科目
// apportionway = json_body.getString("apportionway");//分摊方式
// taxrate = json_body.getString("taxrate");//税率
parentnumber = json_body.getString("costsubject_pcode");//科目父级code
if(DobeDWUtils.isEmpty(number) || DobeDWUtils.isEmpty(name) || DobeDWUtils.isEmpty(parentnumber)){
//根节点数仓不体现所有科目都会有父级科目编号没有的不处理
logger.info(String.format("成本科目入参为空异常:%s", json_body.toJSONString()));
continue;
}
//先从现有科目集合中获取未获取到则新增
acctinfo = parentAccts.get(number);
if(acctinfo == null){
acctinfo = doDetails.addNew();
// acctinfo.set("caentry_srcid", number);//源ID 用于存储数仓的科目id
// acctinfo.set("caentry_project", projectinfo.getLong("id"));//项目
acctinfo.set("caentry_enable", true);//默认 启用
acctinfo.set("caentry_isstdaccount", true);//是否标准科目
acctinfo.set("caentry_standlibflag", true);//是否标准科目库
acctinfo.set("caentry_isleaf", true);//是否叶子节点新增默认为true
acctinfo.set("caentry_ciaccountflag", "1");//科目类别 建安 1 非建安 0 默认都是建安类
//新增时指定一个ID防止父级和子级都创建的情况下子级拿不到父级id而报错
acctinfo.set("id", ID.genLongId());
// acctinfo.set("caentry_longnumber", number);//科目长编号
// acctinfo.set("caentry_fullname", name);//科目长名称
//将此次新增的科目放到现有科目集合中方便后续科目能获取到父级科目
parentAccts.put(number,acctinfo);
}
//已存在做更新 编号名称长编号名称科目类别等
acctinfo.set("caentry_number", number);
acctinfo.set("caentry_name", name);
// acctinfo.set("caentry_apportionway", null);//分摊方式 基础资料
// acctinfo.set("caentry_taxrate", taxrate);//税率
//创建组织 caentry_createorg
//组织 caentry_org
//业务组织 caentry_useorg
//处理父级科目
parentAcctinfo = parentAccts.get(parentnumber);
if(parentAcctinfo != null){
acctinfo.set("pid", parentAcctinfo.getLong("id"));//设置父级科目
//如果数仓不指定长编码和长名称则需要在此处手动处理
acctinfo.set("caentry_longnumber", parentAcctinfo.getString("caentry_longnumber")+"."+number);
acctinfo.set("caentry_fullname", parentAcctinfo.getString("caentry_fullname")+"_"+name);
//科目级次=父级科目级次+1
acctinfo.set("caentry_level", parentAcctinfo.getInt("caentry_level")+1);
//父级科目的是否叶子节点为否
parentAcctinfo.set("caentry_isleaf", false);//是否叶子节点为否
}else{
logger.info("根据父级科目编号未找到对应科目"+parentnumber);
if (doDetails!=null && doDetails.size()!=0){
//成本科目最少需要一级数据一条:CB
this.dataComparison(detailsJson,doDetails,billinfo);
}
//设置对应会计科目字段id
if(!DobeDWUtils.isEmpty(kjkm_num)){
acctViewinfo = acctViewMap.get(kjkm_num);
if(acctViewinfo == null){
acctViewinfo = QueryServiceHelper.queryOne(acctViewEntity,"id,number,longnumber",new QFilter[]{new QFilter("longnumber","=",kjkm_num)});
}
if(acctViewinfo == null){
DobeDWUtils.saveLog(number,"数仓科目同步",json_body.toString(),kjkm_num+" 会计科目在金蝶中找不到:"+kjkm_name,false,"定时任务");
}else{
acctViewMap.put(kjkm_num,acctViewinfo);
acctinfo.set("caentry_account",acctViewinfo.getLong("id"));
}
}
}
//调用保存操作
OperationResult save = OperationServiceHelper.executeOperate("save", entityName, new DynamicObject[]{billinfo}, OperateOption.create());
if (!save.isSuccess()) {
logger.error(save.getMessage());
}
}
private void dataComparison(JSONArray detailsJson, DynamicObjectCollection doDetails,DynamicObject billinfo) {
// 用于存储需要新增的数据接口中有但系统中没有的
List<JSONObject> toAddList = new ArrayList<>();
int updateCount = 0; // 记录更新条数
int addCount = 0; // 记录新增条数
for (int i = 0; i < detailsJson.size(); i++) {
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");
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);
}
}
}
}
// 打印统计信息
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"));
}
// 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);
}
}
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);
}
// 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()); // 父级 IDCB
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
}
}