Ver código fonte

SAP凭证同步代码

wangjun 1 dia atrás
pai
commit
04a6af7f87

+ 407 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/mservice/GlVoucherConstantInfo.java

@@ -0,0 +1,407 @@
+package nckd.jimin.jyyy.fi.mservice;
+
+/**
+ * 凭证常量类
+ *
+ * @author 饶德辉
+ * @version 1.0
+ * @date 2025-05-09 14:46:52
+ */
+public class GlVoucherConstantInfo {
+    /**
+     * 实体标识
+     **/
+    public static final String ENTITYID = "gl_voucher";
+    /**
+     * 缺省id字段
+     **/
+    public static final String ID = "ID";
+    /**
+     * 凭证号
+     **/
+    public static final String BILLNO = "BILLNO";
+    /**
+     * 状态
+     **/
+    public static final String BILLSTATUS = "BILLSTATUS";
+    /**
+     * 创建人
+     **/
+    public static final String CREATOR = "CREATOR";
+    /**
+     * 修改人
+     **/
+    public static final String MODIFIER = "MODIFIER";
+    /**
+     * 审核人
+     **/
+    public static final String AUDITOR = "AUDITOR";
+    /**
+     * 审核时间
+     **/
+    public static final String AUDITDATE = "AUDITDATE";
+    /**
+     * 修改时间
+     **/
+    public static final String MODIFYTIME = "MODIFYTIME";
+    /**
+     * 创建时间
+     **/
+    public static final String CREATETIME = "CREATETIME";
+    /**
+     * 核算组织
+     **/
+    public static final String ORG = "ORG";
+    /**
+     * 分录体
+     **/
+    public static final String ENTRIES = "ENTRIES";
+    /**
+     * 分录行号
+     **/
+    public static final String SEQ = "SEQ";
+    /**
+     * 原币借方
+     **/
+    public static final String DEBITORI = "DEBITORI";
+    /**
+     * 汇率
+     **/
+    public static final String LOCALRATE = "LOCALRATE";
+    /**
+     * 借方
+     **/
+    public static final String DEBITLOCAL = "DEBITLOCAL";
+    /**
+     * 贷方
+     **/
+    public static final String CREDITLOCAL = "CREDITLOCAL";
+    /**
+     * 单价
+     **/
+    public static final String PRICE = "PRICE";
+    /**
+     * 原币贷方
+     **/
+    public static final String CREDITORI = "CREDITORI";
+    /**
+     * 摘要
+     **/
+    public static final String EDESCRIPTION = "EDESCRIPTION";
+    /**
+     * 分录方向
+     **/
+    public static final String ENTRYDC = "ENTRYDC";
+    /**
+     * 币别
+     **/
+    public static final String CURRENCY = "CURRENCY";
+    /**
+     * 计量单位
+     **/
+    public static final String MEASUREUNIT = "MEASUREUNIT";
+    /**
+     * 数量
+     **/
+    public static final String QUANTITY = "QUANTITY";
+    /**
+     * 核算维度
+     **/
+    public static final String ASSGRP = "ASSGRP";
+    /**
+     * 主表项目
+     **/
+    public static final String MAINCFITEM = "MAINCFITEM";
+    /**
+     * 补充资料
+     **/
+    public static final String SUPPCFITEM = "SUPPCFITEM";
+    /**
+     * 主表项目金额
+     **/
+    public static final String MAINCFAMOUNT = "MAINCFAMOUNT";
+    /**
+     * 补充资料金额
+     **/
+    public static final String SUPPCFAMOUNT = "SUPPCFAMOUNT";
+    /**
+     * 原币金额
+     **/
+    public static final String ORIAMOUNT = "ORIAMOUNT";
+    /**
+     * 主表核算维度
+     **/
+    public static final String MAINCFASSGRP = "MAINCFASSGRP";
+    /**
+     * 科目
+     **/
+    public static final String ACCOUNT = "ACCOUNT";
+    /**
+     * 到期日
+     **/
+    public static final String EXPIREDATE = "EXPIREDATE";
+    /**
+     * 业务编号
+     **/
+    public static final String BUSINESSNUM = "BUSINESSNUM";
+    /**
+     * 是否dap生成
+     **/
+    public static final String ISDAP = "ISDAP";
+    /**
+     * 业务编号核销记录
+     **/
+    public static final String BIZNUMRECORD = "BIZNUMRECORD";
+    /**
+     * 汇率类型
+     **/
+    public static final String RATETYPE = "RATETYPE";
+    /**
+     * eorg
+     **/
+    public static final String EORG = "EORG";
+    /**
+     * eperiod
+     **/
+    public static final String EPERIOD = "EPERIOD";
+    /**
+     * 公共维度1
+     **/
+    public static final String COMASSIST1 = "COMASSIST1";
+    /**
+     * 公共维度2
+     **/
+    public static final String COMASSIST2 = "COMASSIST2";
+    /**
+     *
+     **/
+    public static final String ACCOUNTINGTYPE = "ACCOUNTINGTYPE";
+    /**
+     * 凭证类型
+     **/
+    public static final String VOUCHERTYPE = "VOUCHERTYPE";
+    /**
+     * 期间
+     **/
+    public static final String PERIOD = "PERIOD";
+    /**
+     * 业务日期
+     **/
+    public static final String BIZDATE = "BIZDATE";
+    /**
+     * 记账日期
+     **/
+    public static final String BOOKEDDATE = "BOOKEDDATE";
+    /**
+     * 账簿类型
+     **/
+    public static final String BOOKTYPE = "BOOKTYPE";
+    /**
+     * 参考消息
+     **/
+    public static final String DESCRIPTION = "DESCRIPTION";
+    /**
+     * 主表项目
+     **/
+    public static final String MAINCF = "MAINCF";
+    /**
+     * 主表项目金额
+     **/
+    public static final String MAINCFAMT = "MAINCFAMT";
+    /**
+     * 补充资料
+     **/
+    public static final String SUPPCF = "SUPPCF";
+    /**
+     * 补充资料金额
+     **/
+    public static final String SUPPCFAMT = "SUPPCFAMT";
+    /**
+     * 现金类科目合计(借方)
+     **/
+    public static final String CASHTOTAL = "CASHTOTAL";
+    /**
+     * 损益类科目合计(借方)
+     **/
+    public static final String PLTOTAL = "PLTOTAL";
+    /**
+     * 本次剩余未指金额
+     **/
+    public static final String CASHUNUSED = "CASHUNUSED";
+    /**
+     * 本次剩余未指金额
+     **/
+    public static final String PLUNUSED = "PLUNUSED";
+    /**
+     * 关联卡片分录
+     **/
+    public static final String RELATIONENTRY = "RELATIONENTRY";
+    /**
+     * 单据编号
+     **/
+    public static final String RELATIONBILLNO = "RELATIONBILLNO";
+    /**
+     * 文本
+     **/
+    public static final String RELATIONBILLNAME = "RELATIONBILLNAME";
+    /**
+     * 文本
+     **/
+    public static final String BILLTAG = "BILLTAG";
+    /**
+     * 文本
+     **/
+    public static final String BILLID = "BILLID";
+    /**
+     * 用户
+     **/
+    public static final String RELATIONUSER = "RELATIONUSER";
+    /**
+     * 凭证
+     **/
+    public static final String VOUCHERTEXT = "VOUCHERTEXT";
+    /**
+     * 凭证号
+     **/
+    public static final String VOUCHERNO = "VOUCHERNO";
+    /**
+     * 文本
+     **/
+    public static final String VOUCHERID = "VOUCHERID";
+    /**
+     * 附件数
+     **/
+    public static final String ATTACHMENT = "ATTACHMENT";
+    /**
+     * 核算维度
+     **/
+    public static final String MCFASSGRP = "MCFASSGRP";
+    /**
+     * 驳回信息
+     **/
+    public static final String ERRORMSG = "ERRORMSG";
+    /**
+     * 账簿
+     **/
+    public static final String BOOK = "BOOK";
+    /**
+     * 作废
+     **/
+    public static final String CANCELLER = "CANCELLER";
+    /**
+     * 来源类型
+     **/
+    public static final String SOURCETYPE = "SOURCETYPE";
+    /**
+     * 过账人
+     **/
+    public static final String POSTER = "POSTER";
+    /**
+     * 复核人
+     **/
+    public static final String CASHIER = "CASHIER";
+    /**
+     * 来源表单类型
+     **/
+    public static final String SOURCEBILLTYPE = "SOURCEBILLTYPE";
+    /**
+     * 序时簿摘要
+     **/
+    public static final String VDESCRIPTION = "VDESCRIPTION";
+    /**
+     * 借方合计
+     **/
+    public static final String DEBITLOCAMOUNT = "DEBITLOCAMOUNT";
+    /**
+     * 贷方合计
+     **/
+    public static final String CREDITLOCAMOUNT = "CREDITLOCAMOUNT";
+    /**
+     * 来源系统
+     **/
+    public static final String SOURCESYS = "SOURCESYS";
+    /**
+     * 是否冲销凭证
+     **/
+    public static final String ISREVERSE = "ISREVERSE";
+    /**
+     * 是否已被冲销
+     **/
+    public static final String HASREVERSE = "HASREVERSE";
+    /**
+     * 组织本位币
+     **/
+    public static final String LOCALCUR = "LOCALCUR";
+    /**
+     * 是否过账
+     **/
+    public static final String ISPOST = "ISPOST";
+    /**
+     * 主表指定状态
+     **/
+    public static final String MAINSTATUS = "MAINSTATUS";
+    /**
+     * 附表指定状态
+     **/
+    public static final String SUPPSTATUS = "SUPPSTATUS";
+    /**
+     * 源单id
+     **/
+    public static final String SOURCEBILL = "SOURCEBILL";
+    /**
+     * 复核状态
+     **/
+    public static final String ISCHECK = "ISCHECK";
+    /**
+     * 发送通知单
+     **/
+    public static final String SENDNOTICE = "SENDNOTICE";
+    /**
+     * 过账时间
+     **/
+    public static final String POSTTIME = "POSTTIME";
+    /**
+     * 审核驳回
+     **/
+    public static final String ERRORSTATUS = "ERRORSTATUS";
+    /**
+     * 制单人
+     **/
+    public static final String SUBMITTER = "SUBMITTER";
+    /**
+     * 财务借方合计
+     **/
+    public static final String FINANCIALDEBITLOCAL = "FINANCIALDEBITLOCAL";
+    /**
+     * 财务贷方合计
+     **/
+    public static final String FINANCIALCREDITLOCAL = "FINANCIALCREDITLOCAL";
+    /**
+     * 预算借方合计
+     **/
+    public static final String BUDGETDEBITLOCAL = "BUDGETDEBITLOCAL";
+    /**
+     * 预算贷方合计
+     **/
+    public static final String BUDGETCREDITLOCAL = "BUDGETCREDITLOCAL";
+    /**
+     * 异构凭证ID
+     **/
+    public static final String EXTSYSTEMVCHID = "EXTSYSTEMVCHID";
+    /**
+     * 异构凭证号
+     **/
+    public static final String EXTSYSTEMVCHNO = "EXTSYSTEMVCHNO";
+    /**
+     * 来源系统
+     **/
+    public static final String SOURCESYSTEM = "SOURCESYSTEM";
+    /**
+     * 冲销类型
+     **/
+    public static final String AGAINSTTYPE = "AGAINSTTYPE";
+    /**
+     * 打印次数
+     **/
+    public static final String PRINTCOUNTFIELD = "PRINTCOUNTFIELD";
+}

+ 100 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/mservice/SAPParamHelper.java

@@ -0,0 +1,100 @@
+package nckd.jimin.jyyy.fi.mservice;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public final class SAPParamHelper {
+
+    // 静态字段表示每个字段的名称
+    public static final String ZZTM = "ZZTM";     // 账套名
+    public static final String BUKRS = "BUKRS";   // 公司代码
+    public static final String WAERS = "WAERS";   // 帽子货币码
+    public static final String BLDAT = "BLDAT";   // 凭证日期
+    public static final String BUDAT = "BUDAT";   // 过账日期
+    public static final String BKTXT = "BKTXT";   // 凭证抬头文本
+    public static final String XBLNR = "XBLNR";   // 参照
+    public static final String BLART = "BLART";   // 凭证类型
+    public static final String USNAM = "USNAM";   // 用户名
+    public static final String BUZEI = "BUZEI";   // 行项目
+    public static final String BSCHL = "BSCHL";   // 过账码
+    public static final String UMSKZ = "UMSKZ";   // 特别总账标识
+    public static final String HKONT = "HKONT";   // 总账科目
+    public static final String LIFNR = "LIFNR";   // 供应商编码
+    public static final String WRBTR = "WRBTR";   // 凭证货币金额
+    public static final String ZUONR = "ZUONR";   // 分配
+    public static final String SGTXT = "SGTXT";   // 项目文本
+    public static final String KOSTL = "KOSTL";   // 成本中心
+    public static final String PROJK = "PROJK";   // WBS元素
+    public static final String PRCTR = "PRCTR";   // 利润中心
+    public static final String RSTGR = "RSTGR";   // 原因代码
+    public static final String ZFBDT = "ZFBDT";   // 到期日
+    public static final String MWSKZ = "MWSKZ";   // 税码
+    public static final String DMBTR = "DMBTR";   // 本币金额
+    public static final String VBUND = "VBUND";   // 贸易合作伙伴的公司标识
+    public static final String XREF1 = "XREF1";   // 参考 1
+    public static final String XREF2 = "XREF2";   // 参考 2
+    public static final String XREF3 = "XREF3";   // 参考 3
+    public static final String ZZATTRI1 = "ZZATTRI1"; // 文本串
+    public static final String ZZATTRI2 = "ZZATTRI2"; // 文本串
+    public static final String ZZATTRI3 = "ZZATTRI3"; // 文本串
+    public static final String ZTERM = "ZTERM";   // 付款条件代码
+    public static final String KUNNR = "KUNNR";   // 客户编号
+    public static final String AUFNR = "AUFNR";   // 订单号
+
+    // 私有构造函数,防止实例化
+    private SAPParamHelper() {
+        throw new UnsupportedOperationException("该类不允许实例化");
+    }
+
+    // 描述映射关系
+    private static final Map<String, String> FIELD_DESCRIPTIONS = new HashMap<>();
+
+    static {
+        FIELD_DESCRIPTIONS.put(ZZTM, "账套名");
+        FIELD_DESCRIPTIONS.put(BUKRS, "公司代码");
+        FIELD_DESCRIPTIONS.put(WAERS, "币种");
+        FIELD_DESCRIPTIONS.put(BLDAT, "凭证日期");
+        FIELD_DESCRIPTIONS.put(BUDAT, "过账日期");
+        FIELD_DESCRIPTIONS.put(BKTXT, "凭证抬头文本");
+        FIELD_DESCRIPTIONS.put(BLART, "凭证类型");
+        FIELD_DESCRIPTIONS.put(USNAM, "用户名");
+        FIELD_DESCRIPTIONS.put(BUZEI, "行项目");
+        FIELD_DESCRIPTIONS.put(BSCHL, "过账码");
+        FIELD_DESCRIPTIONS.put(UMSKZ, "特别总账标识");
+        FIELD_DESCRIPTIONS.put(HKONT, "总账科目");
+        FIELD_DESCRIPTIONS.put(LIFNR, "供应商编码");
+        FIELD_DESCRIPTIONS.put(WRBTR, "凭证货币金额");
+        FIELD_DESCRIPTIONS.put(ZUONR, "分配");
+        FIELD_DESCRIPTIONS.put(SGTXT, "项目文本");
+        FIELD_DESCRIPTIONS.put(KOSTL, "成本中心");
+        FIELD_DESCRIPTIONS.put(PROJK, "WBS元素");
+        FIELD_DESCRIPTIONS.put(PRCTR, "利润中心");
+        FIELD_DESCRIPTIONS.put(RSTGR, "原因代码");
+        FIELD_DESCRIPTIONS.put(ZFBDT, "到期日");
+        FIELD_DESCRIPTIONS.put(MWSKZ, "税码");
+        FIELD_DESCRIPTIONS.put(DMBTR, "本币金额");
+        FIELD_DESCRIPTIONS.put(VBUND, "贸易合作伙伴的公司标识");
+        FIELD_DESCRIPTIONS.put(XREF1, "参考 1");
+        FIELD_DESCRIPTIONS.put(XREF2, "参考 2");
+        FIELD_DESCRIPTIONS.put(XREF3, "参考 3");
+        FIELD_DESCRIPTIONS.put(ZZATTRI1, "文本串1");
+        FIELD_DESCRIPTIONS.put(ZZATTRI2, "文本串2");
+        FIELD_DESCRIPTIONS.put(ZZATTRI3, "文本串3");
+        FIELD_DESCRIPTIONS.put(ZTERM, "付款条件代码");
+        FIELD_DESCRIPTIONS.put(KUNNR, "客户编号");
+        FIELD_DESCRIPTIONS.put(AUFNR, "订单号");
+    }
+
+    /**
+     * 获取字段的中文描述
+     *
+     * @param fieldName 字段名称
+     * @return 对应的中文描述
+     */
+    public static String getDescription(String fieldName) {
+        String description = FIELD_DESCRIPTIONS.get(fieldName);
+        return description != null ? description : "未知字段";
+    }
+}
+
+

+ 8 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/mservice/SynSapService.java

@@ -0,0 +1,8 @@
+package nckd.jimin.jyyy.fi.mservice;
+
+import java.util.Map;
+
+public interface SynSapService {
+
+    public abstract Map<String, String> synVoucherForSap(String companyCode);
+}

+ 316 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/mservice/SyncSapFIUtils.java

@@ -0,0 +1,316 @@
+package nckd.jimin.jyyy.fi.mservice;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.exception.KDBizException;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.sdk.util.KHttpClientUtils;
+import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.util.StringUtils;
+import nckd.base.helper.CommonHelperUtils;
+
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+public class SyncSapFIUtils {
+    /**
+     * 向SAP系统发送POST请求并返回结果
+     * 该方法主要用于与SAP系统进行数据交互,通过POST请求发送JSON数据,并接收SAP系统的响应
+     *
+     * @param jsonData 要发送的JSON数据
+     * @return SAP系统的响应结果,以字符串形式返回
+     * @throws KDBizException 如果请求失败,抛出业务异常
+     */
+    public static String postDataToSAP( String jsonData)
+    {
+        try {
+            Map<String, String> mapentity = CommonHelperUtils.getCommonParams("SAP");
+            if(mapentity == null){
+                return null;
+            }
+            String param_voucher_url = mapentity.get("voucher_url");
+            String param_username = mapentity.get("username");
+            String param_password = mapentity.get("password");
+
+            if( StringUtils.isEmpty(param_username) || StringUtils.isEmpty(param_password)
+                    || StringUtils.isEmpty(param_voucher_url) ){
+                return null;
+            }
+
+            String encoded = Base64.getEncoder().encodeToString((param_username + ":" + param_password).getBytes());
+            Map<String, String> header = new HashMap<>();
+            header.put("Content-Type", "application/json; charset=UTF-8");
+            header.put("Authorization", "Basic " + encoded);
+
+            String result = KHttpClientUtils.postjson(param_voucher_url, header, jsonData);
+            return result;
+        } catch (Exception e) {
+            throw new KDBizException("请求SAP接口失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 获取字符串中最后一个 '.' 之前的部分
+     *
+     * @param str 输入字符串
+     * @return 第一个 '.' 之前的部分,如果没有 '.' 则返回NULL
+     */
+    public static String getProjectNumberForParent(String str) {
+        int firstDotIndex = str.indexOf('.');
+        if (firstDotIndex == -1) {
+            return null; // 没有找到 '.',返回NULL
+        }
+        return str.substring(0, firstDotIndex);
+    }
+
+
+    public static  JSONObject convertCosmicVoucherToSAPForEntry(DynamicObject voucher,String maincfitemNumber,Map<String, String> auxpropertiesMap) {
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+
+        //账套代码
+        String ZZTM = "FDZT";  //法定账套
+        //公司代码
+        String BUKRS = voucher.getString("org.number");
+        //币制代码
+        String WAERS = StringUtils.isEmpty(voucher.getString("entries.currency.number")) ? "" : voucher.getString("entries.currency.number");
+        //凭证摘要
+        String BKTXT = StringUtils.isEmpty(voucher.getString("description")) ?  "" :  voucher.getString("description");
+
+        String BUZEI = voucher.getString("entries.seq"); //凭证条目
+        String HKONT = voucher.getString("entries.account.number"); //科目
+        int entrydc = voucher.getInt("entries.entrydc"); //凭证方向  1 借贷方  -1 贷方
+        BigDecimal WRBTR = BigDecimal.ZERO;
+        BigDecimal DMBTR = BigDecimal.ZERO;
+        if(entrydc == 1){
+            WRBTR = voucher.getBigDecimal("entries.debitori"); //原币金额
+            DMBTR = voucher.getBigDecimal("entries.debitlocal"); //本币金额
+        }else if((entrydc == -1)){
+            WRBTR = voucher.getBigDecimal("entries.creditori");  //原币金额
+            DMBTR = voucher.getBigDecimal("entries.creditlocal"); //本币金额
+        }
+
+        String SGTXT = voucher.getString("entries.edescription");
+        String PRCTR = "";  //成本中心
+        String PROJK = "";  //项目
+        String KOSTL = ""; //部门
+        String KUNNR = "";  //客户
+        String RSTGR = ""; //现金流量项目
+        String LIFNR = ""; //供应商
+        String VBUND = "";
+        String ZFBDT = "";
+        Date expiredate = voucher.getDate("entries.expiredate");
+        if(expiredate != null){
+            ZFBDT = sdf.format(expiredate); //到期日
+        }
+        String XREF1 = getXREF1(HKONT);  //凭证辅助项1
+        String XREF2 = "";
+        String XREF3 = "";
+        String ZZATTRI1 = "";
+        String ZZATTRI2 = "";
+        String ZZATTRI3 = "";
+
+        //现金流量项目    科目HKONT为1002*行项目需填写,现金流量表项
+        if(StringUtils.isNotEmpty(HKONT)  && (HKONT.startsWith("1002"))) {
+            RSTGR = maincfitemNumber;
+        }
+        //核算维度
+        if(auxpropertiesMap != null && auxpropertiesMap.size() > 0){
+            if(StringUtils.isNotEmpty(auxpropertiesMap.get("bos_adminorg"))){
+                KOSTL = auxpropertiesMap.get("bos_adminorg");  //部门
+            }
+            if(StringUtils.isNotEmpty(auxpropertiesMap.get("bd_customer"))){
+                KUNNR = auxpropertiesMap.get("bd_customer");   //客户
+            }
+            if(StringUtils.isNotEmpty(auxpropertiesMap.get("bd_supplier"))){
+                LIFNR = auxpropertiesMap.get("bd_supplier");   //供应商
+            }
+            if(StringUtils.isNotEmpty(auxpropertiesMap.get("bos_costcenter"))){
+                PRCTR = auxpropertiesMap.get("bos_costcenter");   //成本中心
+            }
+            if(StringUtils.isNotEmpty(auxpropertiesMap.get("bd_project"))){
+                PROJK = auxpropertiesMap.get("bd_project");  //项目
+            }
+        }
+
+        JSONObject ENTRYITEMINFO = new JSONObject();
+
+        ENTRYITEMINFO.put("BKTXT", BKTXT); //凭证摘要
+        ENTRYITEMINFO.put("ZZTM", ZZTM);   //账套代码
+        ENTRYITEMINFO.put("BUZEI", BUZEI); //凭证条目
+        ENTRYITEMINFO.put("HKONT", HKONT); //科目
+        ENTRYITEMINFO.put("PRCTR", PRCTR); //成本中心
+        ENTRYITEMINFO.put("PROJK", PROJK); //项目
+        ENTRYITEMINFO.put("RSTGR", RSTGR); //现金流量项目
+        ENTRYITEMINFO.put("SGTXT", SGTXT); //凭证摘要
+        ENTRYITEMINFO.put("WAERS", WAERS); //币种
+        ENTRYITEMINFO.put("WRBTR", WRBTR); //原币金额
+        ENTRYITEMINFO.put("DMBTR", DMBTR); //本币金额
+        ENTRYITEMINFO.put("ZFBDT", ZFBDT); //到期日
+        ENTRYITEMINFO.put("MWSKZ", "");    //税控
+        ENTRYITEMINFO.put("KOSTL", KOSTL); //部门
+        ENTRYITEMINFO.put("LIFNR", LIFNR); //供应商
+        ENTRYITEMINFO.put("KUNNR", KUNNR); //客户
+        ENTRYITEMINFO.put("ZTERM", "");    //账期
+        ENTRYITEMINFO.put("XREF1", XREF1);
+        ENTRYITEMINFO.put("XREF2", XREF2);
+        ENTRYITEMINFO.put("XREF3", XREF3);
+        ENTRYITEMINFO.put("ZZATTRI1", ZZATTRI1);
+        ENTRYITEMINFO.put("ZZATTRI2", ZZATTRI2);
+        ENTRYITEMINFO.put("ZZATTRI3", ZZATTRI3);
+        ENTRYITEMINFO.put("VBUND", VBUND); //
+
+        return ENTRYITEMINFO;
+    }
+
+    public static JSONObject convertCosmicVoucherToSAPForHead(DynamicObject voucher) {
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+
+        JSONObject HEADERITEMINFO = new JSONObject();
+
+        //账套代码
+        String ZZTM = "FDZT";  //法定账套
+        //公司代码
+        String BUKRS = voucher.getString("org.number");
+        //币制代码
+        String WAERS = StringUtils.isEmpty(voucher.getString("entries.currency.number")) ? "" : voucher.getString("entries.currency.number");
+        //制单人
+        String USNAM = voucher.getString("submitter.number");
+        //业务日期
+        String BLDAT = sdf.format(voucher.getDate(GlVoucherConstantInfo.BIZDATE));
+        //凭证日期
+        String BUDAT = sdf.format(voucher.getDate(GlVoucherConstantInfo.BOOKEDDATE));
+        //凭证摘要
+        String BKTXT = StringUtils.isEmpty(voucher.getString("description")) ?  "" :  voucher.getString("description");
+
+        HEADERITEMINFO.put(SAPParamHelper.ZZTM, ZZTM);  //账套代码
+        HEADERITEMINFO.put(SAPParamHelper.BUKRS, BUKRS); //公司代码
+        HEADERITEMINFO.put(SAPParamHelper.WAERS, WAERS); //币种
+        HEADERITEMINFO.put(SAPParamHelper.BLDAT, BLDAT); //业务日期
+        HEADERITEMINFO.put(SAPParamHelper.BUDAT, BUDAT); //凭证日期
+        HEADERITEMINFO.put(SAPParamHelper.BKTXT, BKTXT); //凭证摘要
+        HEADERITEMINFO.put(SAPParamHelper.USNAM, USNAM); //创建人
+
+        return HEADERITEMINFO;
+    }
+
+    public static  String getVoucherData(JSONObject HEADERITEMINFO,JSONArray ENTRY_ITEM) {
+
+        JSONObject BILL = new JSONObject();
+
+        JSONObject OT_HEADER = new JSONObject();
+        JSONArray HEADER_ITEM = new JSONArray();
+
+        JSONObject OT_ITEM = new JSONObject();
+        //JSONArray ENTRY_ITEM = new JSONArray();
+
+        OT_ITEM.put("item", ENTRY_ITEM);
+
+        HEADER_ITEM.add(HEADERITEMINFO);
+        OT_HEADER.put("item", HEADER_ITEM);
+
+        BILL.put("OT_HEADER", OT_HEADER);
+        BILL.put("OT_ITEM", OT_ITEM);
+
+        return BILL.toJSONString();
+    }
+
+    /**
+     * 获取科目核算维度,现金流量项目
+     * @param voucher
+     * @return  示例  {银行账户=f000003, 合作金融机构=f000011, f000003=2059435197476122624, bd_accountbanks=361604200018150008791, f000011=2050711196931206145, bd_finorginfo=FI-003314}
+     */
+    public static Map<String, String> getAssGrp(DynamicObject voucher)
+    {
+        Map<String, String> auxpropertiesMap = new HashMap<>();
+        // 获取辅助属性的值
+        String value = voucher.getString("entries.assgrp.value");
+        if (StringUtils.isEmpty(value)) {
+            return auxpropertiesMap;
+        }
+        JSONObject jsonObject = JSON.parseObject(value);
+        Map<String, String> assgrp = new HashMap<>();
+        Set<String> keys = jsonObject.keySet();
+        for (String key : keys) {
+            String value1 = jsonObject.getString(key);
+            assgrp.put(key, value1);
+        }
+        System.out.println("turborao test assgrp" + assgrp.toString());
+
+        QFilter auxpropFilter = new QFilter("flexfield", QCP.in, keys);
+        DynamicObjectCollection auxproperties = QueryServiceHelper.query("bd_auxproperty", "number,name,flexfield,valuesource", auxpropFilter.toArray());
+
+        for (DynamicObject auxproperty : auxproperties) {
+            String auxName = auxproperty.getString("name");
+            String flexfield = auxproperty.getString("flexfield");
+            String baseEntity = auxproperty.getString("valuesource");
+            if (kd.bos.dataentity.utils.StringUtils.isNotEmpty(baseEntity)) {
+                String auxValue = assgrp.get(flexfield);
+                auxpropertiesMap.put(flexfield, auxValue);
+                if (kd.bos.dataentity.utils.StringUtils.isNotEmpty(auxValue)) {
+                    QFilter baseEntityFilter = new QFilter("id", QCP.equals, Long.valueOf(auxValue));
+                    DynamicObject baseEntityDyn = QueryServiceHelper.queryOne(baseEntity, "id,number,name", baseEntityFilter.toArray());
+                    String baseEntityNumber = baseEntityDyn.getString("number");
+                    auxpropertiesMap.put(baseEntity, baseEntityNumber);
+                }
+            }
+            // 将 auxNumber 和 auxName 存入 Map
+            auxpropertiesMap.put(auxName, flexfield);
+        }
+
+        // 获取现金流量项目
+        String cfitemNumber = voucher.getString("entries.maincfitem.number");
+        String cfitemName = voucher.getString("entries.maincfitem.name");
+
+        if(kd.bos.dataentity.utils.StringUtils.isNotEmpty(cfitemNumber)){
+            auxpropertiesMap.put("maincfitemNumber",  cfitemNumber);
+            auxpropertiesMap.put("maincfitemName",  cfitemName);
+        }
+        return auxpropertiesMap;
+    }
+
+    public static String getXREF1(String accountNumber)
+    {
+        if ((accountNumber.startsWith("1001")) || (accountNumber.startsWith("1002")) || (accountNumber.startsWith("1012"))) {
+            return "1";
+        }
+        return "0";
+    }
+
+    public static String getVoucherFieldForQuery() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(GlVoucherConstantInfo.ID).append(",");  //  凭证号
+        sb.append(GlVoucherConstantInfo.BILLNO).append(",");  //  凭证号
+        sb.append(GlVoucherConstantInfo.BIZDATE).append(",");  //  业务日期
+        sb.append(GlVoucherConstantInfo.BOOKEDDATE).append(",");  //  记账日期
+        sb.append(GlVoucherConstantInfo.DESCRIPTION).append(",");  //  凭证描述
+        sb.append(GlVoucherConstantInfo.VOUCHERTYPE).append(",");  //   凭证类型
+        sb.append(GlVoucherConstantInfo.ORG).append(",");  //  公司
+        sb.append(GlVoucherConstantInfo.ORG).append(".number").append(",");  //   公司编码
+        sb.append(GlVoucherConstantInfo.SUBMITTER).append(",");  //   制单人
+        sb.append(GlVoucherConstantInfo.SUBMITTER).append(".number").append(",");  //   制单人编码
+        sb.append("entries,"); //  凭证行
+        sb.append("entries.").append(GlVoucherConstantInfo.CURRENCY).append(",");  //  凭证行币种
+        sb.append("entries.").append(GlVoucherConstantInfo.CURRENCY).append(".number").append(",");  //  凭证行币种
+        sb.append("entries.").append(GlVoucherConstantInfo.DEBITLOCAL).append(",");  //  凭证行借方金额
+        sb.append("entries.").append(GlVoucherConstantInfo.CREDITLOCAL).append(",");  //   凭证行贷方金额
+        sb.append("entries.").append(GlVoucherConstantInfo.ENTRYDC).append(","); //  凭证行方向
+        sb.append("entries.").append(GlVoucherConstantInfo.ACCOUNT).append(",");  //  凭证行科目
+        sb.append("entries.").append(GlVoucherConstantInfo.ACCOUNT).append(".number").append(","); //  凭证行科目编码
+        sb.append("entries.").append(GlVoucherConstantInfo.EXPIREDATE).append(","); //  凭证行凭证有效期
+        sb.append("entries.").append(GlVoucherConstantInfo.ASSGRP).append(",");
+        sb.append("entries.").append(GlVoucherConstantInfo.ASSGRP).append(".value").append(",");
+        sb.append("entries.").append(GlVoucherConstantInfo.MAINCFITEM).append(","); // 凭证行 现金流量项目
+        sb.append("entries.").append(GlVoucherConstantInfo.MAINCFITEM).append(".number").append(",");  // 凭证行 现金流量项目 编码
+        sb.append("entries.").append(GlVoucherConstantInfo.MAINCFITEM).append(".name").append(",");  // 凭证行 现金流量项目名称
+        sb.append("entries.").append(GlVoucherConstantInfo.EDESCRIPTION);  //  凭证行描述
+
+        return sb.toString();
+    }
+}

+ 120 - 0
code/jyyy/nckd-jimin-jyyy-fi/src/main/java/nckd/jimin/jyyy/fi/mservice/impl/SynSapFIServiceImpl.java

@@ -0,0 +1,120 @@
+package nckd.jimin.jyyy.fi.mservice.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+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.servicehelper.QueryServiceHelper;
+
+import kd.bos.util.StringUtils;
+import nckd.jimin.jyyy.fi.mservice.SynSapService;
+import nckd.jimin.jyyy.fi.mservice.SyncSapFIUtils;
+
+import java.util.*;
+
+
+/**
+ * 同步SAP凭证
+ *
+ * @author turborao
+ * @date 2025/5/12 19:38
+ */
+public class SynSapFIServiceImpl implements SynSapService {
+    private static final Log logger = LogFactory.getLog(SynSapFIServiceImpl.class);
+
+
+    /**
+     * 同步SAP凭证
+     *
+     * 本方法负责从苍穹系统同步凭证到SAP凭证中
+     *
+     * @param companyCode 公司代码,用于过滤特定公司的项目信息
+     * @return 返回一个包含同步结果的Map,包括状态码(code)和消息(msg)
+     */
+    @Override
+    public Map<String, String> synVoucherForSap(String companyCode) {
+        Map<String, String> result = new HashMap<>();
+
+        QFilter qf1 = new QFilter("billstatus", QCP.equals, "C");
+        QFilter qf2 = new QFilter("org.number", QCP.equals, companyCode);
+
+        String selectFields = SyncSapFIUtils.getVoucherFieldForQuery();
+        DynamicObjectCollection voucherDyns = QueryServiceHelper.query("gl_voucher", selectFields, new QFilter[]{qf1,qf2});
+
+        String billid = "";
+
+        JSONArray ENTRY_ITEM = new JSONArray();  //凭证分录
+        JSONObject HEADERITEMINFO = new JSONObject();  //凭证表头
+        //现金流量项目编码 不在现金科目行上,需要单独处理下
+        String maincfitemNumber  = "";
+        StringBuilder err = new StringBuilder();
+        int count = 0;
+        //voucherDyns 凭证表头与分录平铺
+        for(DynamicObject voucherRow : voucherDyns) {
+            String id = voucherRow.getString("id");
+
+            String voucherInfo = companyCode + "|" + voucherRow.getString("vouchertype") + "|" + voucherRow.getString("billno");
+            Map<String, String> auxpropertiesMap = SyncSapFIUtils.getAssGrp(voucherRow);
+
+            //判断 是不是另一张凭证
+            if(billid.equals(id)) {
+                if(StringUtils.isNotEmpty(auxpropertiesMap.get("maincfitemNumber"))){
+                    maincfitemNumber = auxpropertiesMap.get("maincfitemNumber");
+                }
+                /////处理凭证分录
+                JSONObject entry = SyncSapFIUtils.convertCosmicVoucherToSAPForEntry(voucherRow,maincfitemNumber,auxpropertiesMap);
+                ENTRY_ITEM.add(entry);
+            } else {
+                ///当走到另一张凭证时,处理凭证表头
+                maincfitemNumber = "";
+                HEADERITEMINFO = new JSONObject(); //凭证表头  清空
+                ENTRY_ITEM = new JSONArray();  //凭证分录  清空
+
+                if(StringUtils.isNotEmpty(auxpropertiesMap.get("maincfitemNumber"))){
+                    maincfitemNumber = auxpropertiesMap.get("maincfitemNumber");
+                }
+                ////处理凭证表头
+                HEADERITEMINFO = SyncSapFIUtils.convertCosmicVoucherToSAPForHead(voucherRow);
+                JSONObject entry = SyncSapFIUtils.convertCosmicVoucherToSAPForEntry(voucherRow,maincfitemNumber,auxpropertiesMap);
+                ENTRY_ITEM.add(entry);
+
+                String jsonData = SyncSapFIUtils.getVoucherData(HEADERITEMINFO,ENTRY_ITEM);
+                System.out.println("凭证 info:"+voucherInfo);
+                System.out.println("凭证 post:"+jsonData);
+                //String response = SyncSapFIUtils.postDataToSAP(jsonData);
+                String response = "{\"E_TYPE\":\"S\",\"E_MESSGE\":\"成功\"}";
+                System.out.println("凭证 return:"+response);
+                if(StringUtils.isEmpty(response)){
+                    err.append("同步失败,凭证:"+voucherInfo);
+                    return result;
+                }
+                JSONObject rData = JSONObject.parseObject(response);
+
+                String etype = rData.getString("E_TYPE");
+
+                if(!"S".equals(etype)){
+                    err.append("/n 凭证:"+voucherInfo+",E_TYPE:"+etype+",错误信息:"+rData.getString("E_MESSGE"));
+                    return result;
+                }else{
+                    count++;
+                }
+            }
+            billid = id;
+        }
+
+        if(StringUtils.isEmpty(err.toString())) {
+            result.put("code", "200");
+            result.put("msg", "同步SAP凭证,执行成功,本次同步数量"+count);
+        }else{
+            result.put("code", "300");
+            result.put("msg", "同步SAP凭证,本次同步成功数量"+count +",失败信息:"+ err);
+        }
+
+        return result;
+    }
+
+}