Kaynağa Gözat

1、增加会计科目二级科目的同步。

wanghaiwu 12 saat önce
ebeveyn
işleme
6746d6e6e1

+ 50 - 0
code/jyyy/nckd-jimin-jyyy-bd/src/main/java/nckd/jimin/jyyy/bd/task/SynAccountForSAPTask.java

@@ -0,0 +1,50 @@
+package nckd.jimin.jyyy.bd.task;
+
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.exception.KDException;
+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.StopTask;
+import kd.bos.schedule.executor.AbstractTask;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import nckd.jimin.jyyy.bd.task.impl.SynSapServiceImpl;
+
+import java.util.Map;
+
+/**
+ * 调度任务类
+ * 插件说明:查询SAP的会计科目同步至星瀚
+ * @author wanghaiwu_kd
+ * @date 2025/04/23
+ */
+public class SynAccountForSAPTask extends AbstractTask implements StopTask {
+    private static final Log logger = LogFactory.getLog(SynAccountForSAPTask.class);
+    @Override
+    public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
+        //使用状态=启用
+        QFilter qFilter = new QFilter("enable", QCP.equals, "1");
+        //数据状态=已审核
+        qFilter.and(new QFilter("status", QCP.equals, "C"));
+        //属性核算组织=是
+        qFilter.and(new QFilter("fisaccounting", QCP.equals, "1"));
+        DynamicObject[] orgLst = BusinessDataServiceHelper.load("bos_org", "id, number", qFilter.toArray());
+
+        SynSapServiceImpl synSapService = new SynSapServiceImpl();
+        //轮询组织,将成本信息缓存到Map中
+        for(DynamicObject org : orgLst) {
+            String orgNumber = org.getString("number");
+            logger.info("------同步会计科目 " + orgNumber + "----------");
+
+            Map<String, String> result = synSapService.synAccountForSap(orgNumber);
+
+            if(!result.get("code").equals("200")){
+                logger.info("同步会计科目失败, " + "组织编码:"+orgNumber +",错误:" + result.get("msg"));
+            } else{
+                logger.info("同步会计科目成功, " + "组织编码:"+orgNumber +",信息:" + result.get("msg"));
+            }
+        }
+    }
+}

+ 27 - 0
code/jyyy/nckd-jimin-jyyy-bd/src/main/java/nckd/jimin/jyyy/bd/task/SyncSapUtils.java

@@ -121,6 +121,33 @@ public class SyncSapUtils {
         return json.toString();
     }
 
+    /**
+     * 构造会计科目接口入参
+     * @param companyCode
+     * @return
+     */
+    public static String getAccountData(String companyCode)
+    {
+        JSONObject json = new JSONObject();
+        //公司代码必填
+        json.put("BUKRS", companyCode);
+        json.put("SAKNR", "");
+        json.put("TXT50", "");
+        json.put("ERDAT", "");
+
+        JSONObject itemMap = new JSONObject();
+        itemMap.put("BUKRS", "");
+        itemMap.put("SAKNR", "");
+        itemMap.put("TXT50", "");
+        itemMap.put("ERDAT", "");
+
+        JSONObject etMap = new JSONObject();
+        etMap.put("item", itemMap);
+
+        json.put("ET_ITEM", etMap);
+        return json.toString();
+    }
+
     /**
      * 获取字符串中最后一个 '.' 之前的部分
      *

+ 335 - 0
code/jyyy/nckd-jimin-jyyy-bd/src/main/java/nckd/jimin/jyyy/bd/task/impl/SynSapServiceImpl.java

@@ -3,8 +3,14 @@ package nckd.jimin.jyyy.bd.task.impl;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import kd.bos.basedata.service.BaseDataServiceImpl;
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.OperateOption;
 import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.entity.LocaleString;
+import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
 import kd.bos.db.DB;
+import kd.bos.entity.operate.result.OperationResult;
 import kd.bos.ext.fi.plugin.ArApConvert.util.EmptyUtils;
 import kd.bos.logging.Log;
 import kd.bos.logging.LogFactory;
@@ -12,6 +18,7 @@ import kd.bos.orm.query.QCP;
 import kd.bos.orm.query.QFilter;
 import kd.bos.servicehelper.BusinessDataServiceHelper;
 import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.servicehelper.basedata.BaseDataServiceHelper;
 import kd.bos.servicehelper.operation.SaveServiceHelper;
 import kd.bos.util.StringUtils;
 import nckd.jimin.jyyy.bd.common.oauth.FanWeiUtils;
@@ -691,4 +698,332 @@ public class SynSapServiceImpl implements SynSapService {
         }
         return result;
     }
+
+
+    /**
+     * 同步会计科目
+     * @param companyCode
+     * @return
+     */
+    public Map<String, String> synAccountForSap(String companyCode) {
+        Map<String, String> result = new HashMap<>();
+        logger.info("同步SAP主数据_会计科目");
+
+        String data = SyncSapUtils.getAccountData(companyCode);
+        String url = "account";
+
+        logger.info("同步SAP主数据_会计科目,参数:" + data);
+
+        String response = SyncSapUtils.postDataToSAP(url, data);
+        if (StringUtils.isEmpty(response)) {
+            result.put("code", "300");
+            result.put("msg", "同步SAP主数据_会计科目,同步失败");
+            return result;
+        }
+        JSONObject rData = JSONObject.parseObject(response);
+        String etype = rData.getString("E_TYPE");
+
+        if (!"S".equals(etype)) {
+            result.put("code", "301");
+            result.put("msg", "同步SAP主数据_会计科目,E_TYPE:" + etype + ",错误信息:" + rData.getString("E_MESSGE"));
+            return result;
+        }
+
+        JSONObject rEtItem = rData.getJSONObject("ET_ITEM");
+        if (rEtItem == null) {
+            result.put("code", "302");
+            result.put("msg", "同步SAP主数据_会计科目,ET_ITEM参数为空");
+            return result;
+        }
+
+        JSONArray rItemArray = rEtItem.getJSONArray("item");
+        if (rItemArray == null) {
+            result.put("code", "303");
+            result.put("msg", "同步SAP主数据_会计科目,item参数为空");
+            return result;
+        }
+
+        String entityAccount = "bd_accountview";
+
+        //先遍历出所有的会计科目编码
+        List<String> costNumList = rItemArray.stream().map(JSONObject.class::cast)
+                                                        .filter(json -> json.getString("SAKNR").length() > 4)
+                                                        .map(json -> json.getString("SAKNR"))
+                                                        .collect(Collectors.toList());
+
+        List<String> parentList = rItemArray.stream().map(JSONObject.class::cast)
+                .filter(json -> json.getString("SAKNR").length() > 4)
+                .map(json -> json.getString("SAKNR").substring(0, 4))
+                .collect(Collectors.toList());
+
+        List<String> parentNumList = parentList.stream().distinct().collect(Collectors.toList());
+
+
+        DynamicObject accountDyn =  BusinessDataServiceHelper.newDynamicObject(entityAccount);
+
+        QFilter qFilter = new QFilter("number", QCP.in, costNumList);
+        qFilter.and(new QFilter("accounttable.number", QCP.equals, "0001"));
+
+        List<Object> listIDs = QueryServiceHelper.queryPrimaryKeys(entityAccount, new QFilter[]{qFilter}, null, Integer.MAX_VALUE);
+
+        DynamicObject[] accountDyns = BusinessDataServiceHelper.load(listIDs.toArray(), accountDyn.getDynamicObjectType());
+        Map<String, DynamicObject> accountMaps = Arrays.stream(accountDyns)
+                                                            .collect(Collectors.toMap(
+                                                                    detail -> detail.getString("number"),
+                                                                    detail -> detail, // 整个 DynamicObject 作为 value
+                                                                    (existing, replacement) -> existing // 保留前面的值
+                                                            ));
+
+        qFilter = new QFilter("number", QCP.in, parentNumList);
+        qFilter.and(new QFilter("accounttable.number", QCP.equals, "0001"));
+
+        listIDs = QueryServiceHelper.queryPrimaryKeys(entityAccount, new QFilter[]{qFilter}, null, Integer.MAX_VALUE);
+        DynamicObject[] parentDyns = BusinessDataServiceHelper.load(listIDs.toArray(), accountDyn.getDynamicObjectType());
+        Map<String, DynamicObject> parentMaps = Arrays.stream(parentDyns)
+                .collect(Collectors.toMap(
+                        detail -> detail.getString("number"),
+                        detail -> detail, // 整个 DynamicObject 作为 value
+                        (existing, replacement) -> existing // 保留前面的值
+                ));
+
+
+        StringBuilder err = new StringBuilder();
+        SimpleDateFormat shortformat = new SimpleDateFormat("yyyy-MM-dd");
+        List<DynamicObject> accountList = new ArrayList<>();
+
+        RequestContext rc = RequestContext.get();
+        DynamicObject user = BusinessDataServiceHelper.loadSingle(rc.getCurrUserId(), "bos_user");
+
+        QFilter qf = new QFilter("number", QCP.equals, companyCode);
+        DynamicObject companyDyn = BusinessDataServiceHelper.loadSingle("bos_org", new QFilter[]{qf});
+
+        List<Long> dataIds = new ArrayList();
+
+        for (int i = 0; i < rItemArray.size(); ++i) {
+            JSONObject item = rItemArray.getJSONObject(i);
+            String number = item.getString("SAKNR");
+
+            String name = item.getString("TXT50");
+            if (i == 0 && (StringUtils.isEmpty(number) || StringUtils.isEmpty(name))) {
+                continue;
+            }
+
+            if (StringUtils.isEmpty(number) || StringUtils.isEmpty(name)) {
+                err.append("/n 存在编号或名称为空, " + number + name);
+                continue;
+            }
+
+            if (number.length() <= 4) {
+                err.append("/n 一级会计科目不做同步, " + number + name);
+                continue;
+            }
+
+//            //测试
+//            if(!"1001010000".equals(number)){
+//                continue;
+//            }
+//            number = "1001010052";
+
+            //上级科目编码
+            String parentNumber = number.substring(0, 4);
+            DynamicObject parent = parentMaps.get(parentNumber);
+            if(parent == null){
+                err.append("/n 一级会计科目在星瀚中不存在, " + number + name);
+                continue;
+            }
+
+            String sDateStr = item.getString("ERDAT");
+            Date sDate;
+            Date eDate;
+            try {
+                sDate = shortformat.parse("1900-01-01");
+                eDate = shortformat.parse("2999-12-31");
+
+                if(StringUtils.isEmpty(sDateStr)){
+                    sDate = shortformat.parse(sDateStr);
+                }
+            } catch (ParseException e) {
+                result.put("code", "303");
+                result.put("msg", "当前日期格式异常");
+                return result;
+            }
+
+            DynamicObject accountInfo = accountMaps.get(number);
+            if (accountInfo == null) {
+                long Id = DB.genLongId("T_BD_Account");
+                accountInfo = BusinessDataServiceHelper.newDynamicObject(entityAccount);
+
+                //基本信息
+                accountInfo.set("id", Id);
+                accountInfo.set("number", number);//编号
+                accountInfo.set("startdate", sDate);//版本化日期
+                accountInfo.set("enddate", eDate);//失效日期
+                accountInfo.set("parent", parent);//上级科目
+                accountInfo.set("creator", user);
+                accountInfo.set("createorg", parent.getDynamicObject("createorg"));//创建组织
+                accountInfo.set("org", parent.getDynamicObject("org"));//创建组织
+                accountInfo.set("useorg", parent.getDynamicObject("createorg"));
+                accountInfo.set("srccreateorg", parent.getDynamicObject("srccreateorg"));//创建组织
+                accountInfo.set("longnumber", parent.getString("number") + "_" + number);
+                accountInfo.set("fullname", new LocaleString(parent.getString("name") + "_" + name));
+
+                accountInfo.set("accounttable", parent.getDynamicObject("accounttable"));//科目表
+                accountInfo.set("ctrlstrategy", parent.getString("ctrlstrategy"));//控制策略,默认逐级分配
+                accountInfo.set("accounttype", parent.getDynamicObject("accounttype"));//科目类型
+                accountInfo.set("pltype", parent.getString("pltype"));//损益类型
+                accountInfo.set("dc", parent.getString("dc"));//余额方向
+                accountInfo.set("level", 2);//级次
+
+                //控制信息
+                accountInfo.set("accrualdirection", parent.getString("accrualdirection"));//科目录入方向控制
+                accountInfo.set("control", parent.getString("control"));//受控系统
+                accountInfo.set("orgcontrollevel", "2");//控制级次
+                accountInfo.set("isallowca", parent.getBoolean("isallowca"));//允许公司增加下级科目
+                accountInfo.set("ismanual", parent.getBoolean("ismanual"));//允许公司增加下级科目
+
+                //科目属性
+                accountInfo.set("iscash", parent.getBoolean("iscash"));//现金科目
+                accountInfo.set("isbank", parent.getBoolean("isbank"));//银行科目
+                accountInfo.set("iscashequivalent", parent.getBoolean("iscashequivalent"));//现金等价物
+                accountInfo.set("isjournal", parent.getBoolean("isjournal"));//登日记账
+                accountInfo.set("acnotice", parent.getBoolean("acnotice"));//往来通知
+                accountInfo.set("bw", parent.getBoolean("bw"));//表外科目
+                accountInfo.set("ischangecurrency", parent.getBoolean("ischangecurrency"));//期末调汇
+                accountInfo.set("isqty", parent.getBoolean("isqty"));//数量核算
+                accountInfo.set("measureunitgroup", parent.getDynamicObject("measureunitgroup"));//计量单位分组
+                accountInfo.set("measureunit", parent.getDynamicObject("measureunit"));//计量单位
+                accountInfo.set("accheck", parent.getBoolean("accheck"));//往来核算
+                accountInfo.set("isassist", parent.getBoolean("isassist"));//是否包含核算项目
+
+                //核算维度
+                DynamicObjectCollection assgrpEntrys = accountInfo.getDynamicObjectCollection("checkitementry");
+
+                //上级科目核算维度
+                List<String> parentItemList = new ArrayList<String>();
+                DynamicObjectCollection parentEntrys = parent.getDynamicObjectCollection("checkitementry");
+                if(parentEntrys.size() > 0){
+                    for(DynamicObject parentEntry : parentEntrys){
+                        DynamicObjectType assgrpType = assgrpEntrys.getDynamicObjectType();
+
+                        DynamicObject asstrp = new DynamicObject(assgrpType);
+                        asstrp.set("asstactitem", parentEntry.getDynamicObject("asstactitem"));//核算维度
+                        asstrp.set("isrequire", parentEntry.getBoolean("isrequire"));//必录
+                        asstrp.set("isdetail", parentEntry.getBoolean("isdetail"));//明细
+                        asstrp.set("enaccheck", parentEntry.getBoolean("enaccheck"));//往来核算
+
+                        assgrpEntrys.add(asstrp);
+
+                        parentItemList.add(parentEntry.getDynamicObject("asstactitem").getString("number"));
+                    }
+                }
+
+                String mitkz = item.getString("MITKZ");
+                String katyp = item.getString("KATYP");
+
+                if(StringUtils.isNotEmpty(mitkz) && ("D".equals(mitkz) || "K".equals(mitkz))){//核算维度默认为供应商
+                    if(!parentItemList.contains("JY003")) {
+                        QFilter assgFilter = new QFilter("number", QCP.equals, "JY003");
+                        DynamicObject asstType = BusinessDataServiceHelper.loadSingle("bd_asstacttype", assgFilter.toArray());
+
+                        DynamicObjectType assgrpType = assgrpEntrys.getDynamicObjectType();
+                        DynamicObject asstrp = new DynamicObject(assgrpType);
+                        asstrp.set("asstactitem", asstType);//核算维度
+                        asstrp.set("isrequire", true);//必录
+                        asstrp.set("isdetail", true);//明细
+                        asstrp.set("enaccheck", false);//往来核算
+
+                        assgrpEntrys.add(asstrp);
+                    }
+                } else if(StringUtils.isNotEmpty(katyp) && "1".equals(katyp)){//核算维度
+                    //成本中心
+                    QFilter assgFilter = new QFilter("number", QCP.equals, "JY001");
+                    DynamicObject asstType = BusinessDataServiceHelper.loadSingle("bd_asstacttype", assgFilter.toArray());
+                    DynamicObjectType assgrpType = assgrpEntrys.getDynamicObjectType();
+
+                    if(!parentItemList.contains("JY001")) {
+                        DynamicObject asstrp = new DynamicObject(assgrpType);
+                        asstrp.set("asstactitem", asstType);//核算维度
+                        asstrp.set("isrequire", true);//必录
+                        asstrp.set("isdetail", true);//明细
+                        asstrp.set("enaccheck", false);//往来核算
+
+                        assgrpEntrys.add(asstrp);
+                    }
+
+                    //一级科目是5002和5301的,核算维度是成本中心 + 项目
+                    if("5002".equals(parentNumber) || "5301".equals(parentNumber)){
+                        if(!parentItemList.contains("JY002")) {
+                            //项目
+                            assgFilter = new QFilter("number", QCP.equals, "JY002");
+                            asstType = BusinessDataServiceHelper.loadSingle("bd_asstacttype", assgFilter.toArray());
+
+                            DynamicObject asstrp2 = new DynamicObject(assgrpType);
+                            asstrp2.set("asstactitem", asstType);//核算维度
+                            asstrp2.set("isrequire", false);//必录
+                            asstrp2.set("isdetail", true);//明细
+                            asstrp2.set("enaccheck", false);//往来核算
+
+                            assgrpEntrys.add(asstrp2);
+                        }
+                    }
+                }
+                //币别核算
+                accountInfo.set("acctcurrency", parent.getString("acctcurrency"));
+            } else {
+                if(!dataIds.contains(accountInfo.getLong("parent.id"))) {
+                    dataIds.add(accountInfo.getLong("parent.id"));
+                }
+                dataIds.add(accountInfo.getLong("id"));
+
+                continue;
+            }
+
+            accountInfo.set("name", name);//科目名称
+            accountInfo.set("status", "C");//单据状态
+            accountInfo.set("enable", "1");//使用状态
+
+            logger.info("同步SAP主数据_会计科目,id:" + accountInfo.getLong("id") + "  -->  " + Long.valueOf(accountInfo.getString("id")));
+
+            accountInfo.set("masterid", Long.valueOf(accountInfo.getString("id")));
+            accountList.add(accountInfo);
+
+            if(!dataIds.contains(accountInfo.getLong("parent.id"))) {
+                dataIds.add(accountInfo.getLong("parent.id"));
+            }
+            dataIds.add(accountInfo.getLong("id"));
+        }
+
+        if (accountList.size() > 0) {
+            DynamicObject[] saveDynamicObject = accountList.toArray(new DynamicObject[accountList.size()]);
+//            Object[] save = SaveServiceHelper.save(saveDynamicObject);
+
+            OperationResult resultSave = SaveServiceHelper.saveOperate(entityAccount, saveDynamicObject, OperateOption.create());
+
+//            int length = save.length;
+//            logger.info("同步[会计科目]完成,本次新增数量:{}," + err, length);
+
+            result.put("code", "200");
+            result.put("msg", "同步SAP主数据_会计科目,执行成功,本次同步数量" + saveDynamicObject.length + err);
+        } else {
+            result.put("code", "304");
+            result.put("msg", "同步SAP主数据_会计科目_没有数据");
+        }
+
+        if(dataIds.size() > 0) {
+            //批量分配
+            List<Long> orgIds = new ArrayList();
+            orgIds.add(companyDyn.getLong("id"));
+
+            Map<Long, Map<Long, String>> resultValue = BaseDataServiceHelper.batchAssignWithDetail(entityAccount, DEFAULT_ORG_ID, dataIds, orgIds);
+            if (!resultValue.isEmpty()) {
+                result.put("code", "200");
+                result.put("msg", "同步SAP主数据_会计科目,保存成功,但分配失败");
+            }
+
+        }
+
+        logger.info("会计科目同步结果:" + result.toString());
+
+        return result;
+    }
 }