package nckd.jimin.jyyy.fi.webapi;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.kingdee.util.StringUtils;
import kd.bos.cache.CacheFactory;
import kd.bos.cache.TempFileCache;
import kd.bos.dataentity.OperateOption;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
import kd.bos.entity.BillEntityType;
import kd.bos.entity.EntityMetadataCache;
import kd.bos.entity.operate.result.OperationResult;
import kd.bos.id.ID;
import kd.bos.openapi.common.custom.annotation.ApiController;
import kd.bos.openapi.common.custom.annotation.ApiMapping;
import kd.bos.openapi.common.custom.annotation.ApiParam;
import kd.bos.openapi.common.custom.annotation.ApiPostMapping;
import kd.bos.openapi.common.result.CustomApiResult;
import kd.bos.openapi.common.result.OpenApiFile;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.AttachmentServiceHelper;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.QueryServiceHelper;
import kd.bos.servicehelper.operation.SaveServiceHelper;
import kd.bos.servicehelper.org.OrgUnitServiceHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 提供给合同系统的新增/更新接口，对应星瀚合同台账单 er_contractbill
 * api编码：contract/uploadFileTemp (附件上传接口)
 * api编码：contract/saveContract （合同单据接口）
 *
 * @author chengchaohua
 * @since 2025/05/06
 */
@ApiController(value = "hetong", desc = "合同台账单接口")
@ApiMapping("/contract")
public class ContractbillApiPlugin implements Serializable {
    private static final Logger log = LoggerFactory.getLogger(ContractbillApiPlugin.class);

    @ApiPostMapping("/uploadFileTemp")
    public CustomApiResult<Map<String,Object>> uploadFileTemp(@ApiParam(value = "文件流",required = true) OpenApiFile file) {
        log.info("合同附件上传-1");
        byte[] fileData = file.getFileData();
        String fileName = file.getFileName();
        Map<String,Object> map = new HashMap<>();
        TempFileCache cache = CacheFactory.getCommonCacheFactory().getTempFileCache();
        String tempUrl = cache.saveAsFullUrl(fileName, fileData,3600);
        CustomApiResult<Map<String,Object>> customApiResult = new CustomApiResult<>();
        map.put("tempurl",tempUrl);
        map.put("fileName",fileName);
        map.put("size",file.getFileData().length);
        customApiResult.setData(map);
        log.info("合同附件上传-2");
        return customApiResult;
    }


    @ApiPostMapping(value = "/saveContract", desc = "保存合同台账单")
    public CustomApiResult<Boolean> saveContract(@ApiParam("单据信息") Map<String, Object> billData
            ,@ApiParam("附件面板") Map<String, List<Map<String,Object>>> allAttachmentsData
    ) {
        log.info("保存合同台账单-接口最前面标记日志，合同号:" + billData.get("contractcode"));
        // 接口返回结果
        CustomApiResult<Boolean> result = new CustomApiResult<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 0）数据校验
        // 收支类型
        if(!"1".equals(billData.get("incometype"))) {
            result.setMessage("收支类型不是1，星瀚不接收"); // 返回状态还是成功的，只是不接收
            return result;
        }
        // 合同类型
        String contracttypev = (String)billData.get("contracttype");
        if (StringUtils.isEmpty(contracttypev)) {
            result.setMessage("合同类型不能为空");
            result.setStatus(false);
            return result;
        }

        DynamicObject contracttype = BusinessDataServiceHelper.loadSingle("pmct_conttype","id,name",new QFilter[]{new QFilter("number",QCP.equals,contracttypev)});
        if (contracttype == null) {
            result.setMessage("合同类型:" + contracttypev + "未在星瀚维护");
            result.setStatus(false);
            return result;
        }

        // fapplierid 经办人:入参格式 员工编码_名称 ，由根据人员信息带出主职的公司、部门、职位、手机
        String fapplierid = (String)billData.get("applierid");
        if (StringUtils.isEmpty(fapplierid)) {
            result.setMessage("经办人fapplierid未传值");
            result.setStatus(false);
            return result;
        }
        String gonghao = fapplierid.split("_")[0]; // 提取员工工号
        // dpt 部门，ispartjob 兼职，position 职位
        DynamicObject applicatuser = BusinessDataServiceHelper.loadSingle("bos_user","id,name,number,phone,entryentity,entryentity.dpt,entryentity.ispartjob,entryentity.position",new QFilter[]{new QFilter("number",QCP.equals,gonghao)});
        if (applicatuser == null) {
            result.setMessage("经办人工号未在星瀚系统出现");
            result.setStatus(false);
            return result;
        }

        DynamicObjectCollection bumenlist = applicatuser.getDynamicObjectCollection("entryentity"); // 分录部门信息
        if (bumenlist == null || bumenlist.size() == 0) {
            result.setMessage("经办人未在星瀚系统人员中维护部门信息");
            result.setStatus(false);
            return result;
        }
        boolean haveZhuZhi = false; // 是否有主任职
        DynamicObject bumen = null; // 部门
        String zhiwei = " "; // 职位
        for (DynamicObject dynamicObject : bumenlist) {
            boolean ispartjob = dynamicObject.getBoolean("ispartjob");// 兼职: 字符串 1 是，0 否
            if (!ispartjob) {
                // 非兼职
                haveZhuZhi = true;
                bumen = dynamicObject.getDynamicObject("dpt");
                zhiwei = dynamicObject.getString("position");
            }
        }
        if (haveZhuZhi == false) {
            result.setMessage("经办人未在星瀚系统人员部门信息无主任职记录");
            result.setStatus(false);
            return result;
        }
        if (bumen == null) {
            result.setMessage("经办人在星瀚系统人员部门信息无部门值");
            result.setStatus(false);
            return result;
        }

        // 通过部门查公司
        QFilter qFilterGs = new QFilter("number", "=", bumen.get("number"));
        DynamicObject[] costdept = BusinessDataServiceHelper.load("bos_adminorg", "id,name,number", new QFilter[]{qFilterGs}); // bos_adminorg行政组织
        Map<String, Object> companyInfoMap = OrgUnitServiceHelper.getCompanyfromOrg(costdept[0].get("id"));
        DynamicObject org = BusinessDataServiceHelper.loadSingle(companyInfoMap.get("id"),"bos_org"); // 公司对象
        if (org == null) {
            result.setMessage("在星瀚系统未查询到经办人的公司信息");
            result.setStatus(false);
            return result;
        }

        // 合同号（原始）
        String fcontractcode = (String)billData.get("contractcode");
        if (StringUtils.isEmpty(fapplierid)) {
            result.setMessage("经办人fapplierid未传值");
            result.setStatus(false);
            return result;
        }

        String nckd_contractcodenew = (String)billData.get("nckd_contractcodenew"); // 合同号（最新）
        String fcontractname = (String)billData.get("contractname"); // 合同名称
        String fdescription = (String)billData.get("description"); // 合同说明
        if (StringUtils.isEmpty(fdescription)) {
            fdescription = "无";
        }

        String fsigndate = (String)billData.get("signdate"); // 签订日期
        if (StringUtils.isEmpty(fsigndate)) {
            result.setMessage("签订日期signdate未传值");
            result.setStatus(false);
            return result;
        }
        String fbizdate = (String)billData.get("bizdate"); // 申请日期
        String fstartdate = (String)billData.get("startdate"); // 起始日期
        String fenddate = (String)billData.get("enddate"); // 截止日期

        String contractcurrency = (String)billData.get("contractcurrency"); // 币种
        if (StringUtils.isEmpty(contractcurrency)) {
            result.setMessage("币种contractcurrency未传值");
            result.setStatus(false);
            return result;
        }
        DynamicObject bizhong = BusinessDataServiceHelper.loadSingle("bd_currency","id,name",new QFilter[]{new QFilter("number",QCP.equals,contractcurrency)});
        if (bizhong == null) {
            result.setMessage("币种编码contractcurrency:" + contractcurrency + "，星瀚未维护");
            result.setStatus(false);
            return result;
        }
        String projectower = (String)billData.get("projectower"); // 合同干系人
        if (StringUtils.isEmpty(projectower)) {
            result.setMessage("合同干系人projectower未传值");
            result.setStatus(false);
            return result;
        }
        // 甲方纳税号
        String fjiafangxinyongcode = (String)billData.get("jiafangxinyongcode"); // 甲方统一社会信用代码
        if (StringUtils.isEmpty(fjiafangxinyongcode)) {
            result.setMessage("甲方统一社会信用代码jiafangxinyongcode未传值");
            result.setStatus(false);
            return result;
        }

        String fjiafangcontactperson = (String)billData.get("jiafangcontactperson"); // 甲方联系人
        if (StringUtils.isEmpty(fjiafangcontactperson)) {
            result.setMessage("甲方联系人jiafangcontactperson未传值");
            result.setStatus(false);
            return result;
        }
        // 合同来源
        String nckd_sources = (String)billData.get("nckd_sources");
        if (StringUtils.isEmpty(nckd_sources)) {
            result.setMessage("合同来源nckd_sources未传值");
            result.setStatus(false);
            return result;
        }
        // 签约方：乙方集合
        JSONArray contractpartyAry = (JSONArray) billData.get("contractparty");
        if (contractpartyAry == null || contractpartyAry.size() == 0) {
            result.setMessage("签约方contractparty未传值");
            result.setStatus(false);
            return result;
        }

        // 付款计划集合
        JSONArray fukuanplanAry = (JSONArray) billData.get("fukuanplan");
        if(fukuanplanAry.size() > 1) {
            result.setMessage("付款计划只能传一条记录"); // 已经和客户确认了，他们只会有一条，而我们对第二次同笔数据送入接口会做更新，只有一笔也不需要定位那条分录
            result.setStatus(false);
            return result;
        }

        // 1）单据组装
        String entityNumber = "er_contractbill"; // 合同台账单 单据标识
        QFilter qFilter = new QFilter("contractcode", QCP.equals,fcontractcode); // 合同号（原始）
        DynamicObject dynamicObject = null;
        boolean isnew = true; // 标记：是新的合同，不是第二次送入进行更新的
        if(QueryServiceHelper.exists(entityNumber,new QFilter[]{qFilter})){
            // 合同台账的合同号（原始）已存在
            isnew = false;
            dynamicObject = BusinessDataServiceHelper.loadSingle(entityNumber,new QFilter[]{qFilter});
            String contractcodenewhistory = dynamicObject.getString("nckd_contractcodenew");// 合同号（最新）
            if (!StringUtils.isEmpty(nckd_contractcodenew)) {
                // 有送合同号(新)
                if (StringUtils.isEmpty(contractcodenewhistory)) {
                    // 单据合同号(新)无值，本次直接赋值
                    dynamicObject.set("nckd_contractcodenew",nckd_contractcodenew);
                } else {
                    String[] invoshuzu = contractcodenewhistory.split(","); // 单据现有的合同号（最新）
                    Set<String> linkedHashSet = new LinkedHashSet<>(Arrays.asList(invoshuzu)); // 按顺序排序，而且排重
                    linkedHashSet.add(nckd_contractcodenew); // 添加新的合同号（最新）
                    dynamicObject.set("nckd_contractcodenew",String.join(",",linkedHashSet)); // 合同号（最新），多个用逗号隔开
                }
            }
        } else {
            // 不存在，创建新对象
            dynamicObject = BusinessDataServiceHelper.newDynamicObject(entityNumber); // 单据标识
            dynamicObject.set("id", ID.genLongId()); // 创建id值

            dynamicObject.set("creator",applicatuser); // 创建人
            dynamicObject.set("createtime",new Date()); // 创建时间

            dynamicObject.set("formid", "er_contractbill"); // 表单ID
            dynamicObject.set("isenableinvoice", true); // 启用发票云
            dynamicObject.set("currency", 1); // 本位币种
        }
        long pkid = dynamicObject.getLong("id");

        BillEntityType dataEntityType = (BillEntityType) dynamicObject.getDataEntityType();
        String appId = dataEntityType.getAppId(); // 获取单据的应用id

        dynamicObject.set("billstatus","E"); // 单据状态， A-暂存,E-审核通过
        //单据其他业务字段赋值
        dynamicObject.set("tel",applicatuser.getString("phone"));// 联系方式，申请人手机号
        // 甲方：ftaxregnum 纳税识别号
        DynamicObject company = BusinessDataServiceHelper.loadSingle("bos_org","id,name",new QFilter[]{new QFilter("uniformsocialcreditcode",QCP.equals,fjiafangxinyongcode)});
        if (company == null) {
            result.setMessage("甲方统一社会信用代码未在星瀚系统存在:" + fjiafangxinyongcode);
            result.setStatus(false);
            return result;
        }
        dynamicObject.set("costcompany",company); // 核算组织
        dynamicObject.set("company",org); // 公司,取经办人的公司（例如：上海济煜医药）
        dynamicObject.set("org",bumen); // 经办人部门,取经办人的主岗部门
        dynamicObject.set("costdept",bumen); // 费用承担部门,取经办人的主岗部门
        dynamicObject.set("applierpositionstr",zhiwei); // 经办人职位

        DynamicObject stdbilltype = BusinessDataServiceHelper.loadSingle("bos_billtype","id,name",new QFilter[]{new QFilter("number",QCP.equals,"er_contractbill_BT_S")});
        dynamicObject.set("stdbilltype",stdbilltype); // 单据类型:基础资料 合同台账

        dynamicObject.set("detailtype","biztype_applybill"); //（影响列表记录显示） 单据类型:biztype_applybill 合同台账 ,biztype_changebill 合同变更,biztype_stopbill 合同终止

        dynamicObject.set("contracttype",contracttype); // 合同类型
        dynamicObject.set("contractcode",fcontractcode); // 合同号
        dynamicObject.set("contractname",fcontractname); // 合同名称

        try {
            dynamicObject.set("signdate",sdf.parse(fsigndate)); // 签订日期
//            dynamicObject.set("changedate",sdf.parse(fstartdate)); // 变更日期
            if (StringUtils.isEmpty(fbizdate)) {
                dynamicObject.set("bizdate",sdf.parse(fsigndate)); // 申请日期，无值取签订日期
            } else {
                dynamicObject.set("bizdate",sdf.parse(fbizdate)); // 申请日期
            }

            if (StringUtils.isEmpty(fstartdate)) {
                dynamicObject.set("startdate",sdf.parse(fsigndate)); // 起始日期，无值取签订日期
            } else {
                dynamicObject.set("startdate",sdf.parse(fstartdate)); // 起始日期
            }

            if (StringUtils.isEmpty(fenddate)) {
                dynamicObject.set("enddate",sdf.parse(fsigndate)); // 截止日期，无值取签订日期
            } else {
                dynamicObject.set("enddate",sdf.parse(fenddate)); // 截止日期
            }
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        dynamicObject.set("changedate",new Date()); // 变更日期
        dynamicObject.set("description",fdescription);  // 合同说明
        dynamicObject.set("partbtype","bd_supplier"); // 乙方类型（隐藏字段）

        dynamicObject.set("iscurrency",true); // 默认设置多币种

        dynamicObject.set("contractcurrency",bizhong); // 币种

        BigDecimal huilv = new BigDecimal(0); // 汇率
        if ("CNY".equals(contractcurrency)) {
            // CNY 人民币
            huilv = new BigDecimal(1);
            dynamicObject.set("changerate",1); // 汇率(需根据币别查询最新汇率)
        } else {
            DynamicObject CNY = BusinessDataServiceHelper.loadSingle("bd_currency","id,name",new QFilter[]{new QFilter("number",QCP.equals,"CNY")});

            // orgcur 原币,cur 目标币(指定人民币),effectdate 生效日期
            DynamicObject[] huilvAry = BusinessDataServiceHelper.load("bd_exrate_tree","id,orgcur,cur,excval,effectdate",
                    new QFilter[]{new QFilter("orgcur",QCP.equals,bizhong.getLong("id"))
                            .and("cur",QCP.equals,CNY.getLong("id"))
                            .and("enable",QCP.equals,'1')},"effectdate desc"); // 日期倒序排


            if(huilvAry.length > 0) {
                huilv = huilvAry[0].getBigDecimal("excval"); // 直接汇率值
            } else {
                result.setMessage("星瀚系统未维护" + contractcurrency + "币别与人民币的汇率");
                result.setStatus(false);
                return result;
            }
        }
        dynamicObject.set("changerate",huilv); // 汇率(需根据币别查询最新汇率)

        dynamicObject.set("applier",applicatuser); // 经办人
        dynamicObject.set("modifier",applicatuser); // 修改人
        dynamicObject.set("modifytime",new Date()); // 修改时间
        dynamicObject.set("nckd_sources",nckd_sources); // 合同来源
        // 合同干系人(多基础资料)
        String gx_gonghao = projectower.split("_")[0];
        DynamicObject gx_user = BusinessDataServiceHelper.loadSingle("bos_user","id",new QFilter[]{new QFilter("number",QCP.equals,gx_gonghao)});
        DynamicObjectCollection userColl = dynamicObject.getDynamicObjectCollection("projectower"); // 多基础资料标识
        DynamicObject newUser = new DynamicObject(userColl.getDynamicObjectType()); // 获取基础资料类型
        newUser.set("fbasedataId", gx_user);
        userColl.add(newUser);
        dynamicObject.set("projectower",userColl);

        // 1.2）签约方分录
        DynamicObjectCollection newColl = dynamicObject.getDynamicObjectCollection("contractpartyentry"); // 单据体标识
        newColl.clear();
        // 甲方
        DynamicObject newEntry = new DynamicObject(newColl.getDynamicObjectType());
        newEntry.set("signcontract", "0"); // 签约方，甲方-0，乙方-1，其他方-2
        newEntry.set("partytype", "bos_org"); // 默认公司，签约方类型:bos_org 公司,bd_supplier 供应商,bd_customer 客户
        newEntry.set("contractparty", company); // 签约方名称
        newEntry.set("contactperson", fjiafangcontactperson); // 联系人，文本
        newColl.add(newEntry);
        // 乙方
        for (Object item : contractpartyAry) {
            JSONObject jsb = (JSONObject)item;
            String signcontract = jsb.getString("signcontract"); // 签约方:乙方:1，其他方:2
            if (StringUtils.isEmpty(signcontract)) {
                result.setMessage("乙方签约方signcontract未传值");
                result.setStatus(false);
                return result;
            }
            String fxinyongcode = jsb.getString("xinyongcode"); // 统一社会信用代码
            if (StringUtils.isEmpty(fxinyongcode)) {
                result.setMessage("乙方统一社会信用代码xinyongcode未传值");
                result.setStatus(false);
                return result;
            }
            String fcontactperson = jsb.getString("contactperson"); // 乙方联系人
            if (StringUtils.isEmpty(fcontactperson)) {
                result.setMessage("乙方联系人contactperson未传值");
                result.setStatus(false);
                return result;
            }
            DynamicObject newEntry2 = new DynamicObject(newColl.getDynamicObjectType());
            newEntry2.set("signcontract", signcontract); // 签约方，甲方-0，乙方-1，其他方-2
            newEntry2.set("partytype", "bd_supplier"); // 签约方类型:bos_org 公司,bd_supplier 供应商,bd_customer 客户
            DynamicObject supplier = BusinessDataServiceHelper.loadSingle("bd_supplier","id,name",new QFilter[]{new QFilter("societycreditcode",QCP.equals,fxinyongcode)});
            if (supplier == null) {
                result.setMessage("乙方统一社会信用代码" + fxinyongcode + "未在星瀚供应商中查询到");
                result.setStatus(false);
                return result;
            }
            newEntry2.set("contractparty", supplier); // 签约方名称（基础资料对象）
            newEntry2.set("contactperson", fcontactperson); // 联系人，文本
            newColl.add(newEntry2);
        }
        dynamicObject.set("contractpartyentry", newColl); // 签约方分录

        // 1.3）付款计划分录
        DynamicObjectCollection plannewColl = dynamicObject.getDynamicObjectCollection("expenseentryentity"); // 单据体标识
//        plannewColl.clear();
        BigDecimal hetongjinetotalfist = new BigDecimal(0); // 合同总额(初始)--头表
        BigDecimal hetongjinetotalfistBen = new BigDecimal(0); // 合同总额(初始)-本位币--头表
        BigDecimal yifutotal = new BigDecimal(0); // 已付金额--头表
        BigDecimal yifutotalBen = new BigDecimal(0); // 已付金额-本位币--头表
        BigDecimal yibaoxiaototal = new BigDecimal(0); // 已报销金额--头表
        BigDecimal yibaoxiaototalBen = new BigDecimal(0); // 已报销金额-本位币--头表
        for (Object item : fukuanplanAry) {
            JSONObject jsb = (JSONObject)item;
            String fpayterms = jsb.getString("payterms"); // 付款条件
            if (StringUtils.isEmpty(fpayterms)) {
                result.setMessage("付款条件payterms未传值");
                result.setStatus(false);
                return result;
            }
            BigDecimal fexpapplyamount = jsb.getBigDecimal("expapplyamount"); // 含税金额
            if (fexpapplyamount == null) {
                result.setMessage("含税金额expapplyamount未传值");
                result.setStatus(false);
                return result;
            }
            BigDecimal fexpapplyamountBen =fexpapplyamount.multiply(huilv).setScale(2, RoundingMode.HALF_UP); // 含税金额(本位币) = 含税金额本位币 * 汇率，四舍五入

            // 确认合同单据本次是新增还是更新，分录接口只允许送一条记录
            DynamicObject newEntry3 = null;
            if (isnew) {
                // 新增(接口第一次调)
                newEntry3 = new DynamicObject(plannewColl.getDynamicObjectType());
                newEntry3.set("seq",1); // 分录序号
                newEntry3.set("reimbursedamount",0); // 已报销金额
                newEntry3.set("reimbursedcurramount",0); // 已报销金额(本位币)
                newEntry3.set("oriexppayedamount",0); // 已付金额
                newEntry3.set("exppayedamount",0); // 已付金额(本位币)
                newEntry3.set("oriexpnotpayamount",fexpapplyamount); // 未付金额
                newEntry3.set("expnotpayamount",fexpapplyamountBen); // 未付金额(本位币)，四舍五入
                newEntry3.set("canloanamount",fexpapplyamount); // 可预付金额
                newEntry3.set("canloancurramount",fexpapplyamountBen); // 可预付金额(本位币)
                newEntry3.set("orgiexpebalanceamount",fexpapplyamount); // 可报销金额
                newEntry3.set("expebalanceamount",fexpapplyamountBen); // 可报销金额(本位币)
                newEntry3.set("expquotetype","0"); // 换算方式:直接汇率 0，间接汇率 1
            } else {
                // 更新
                newEntry3 = plannewColl.get(0); // 分录只有一条记录
                // 未付金额=含税金额 - 已付金额，未付金额(本位币)=含税金额(本位币) - 已付金额(本位币)
                newEntry3.set("oriexpnotpayamount",fexpapplyamount.subtract(newEntry3.getBigDecimal("oriexppayedamount"))); // 未付金额
                newEntry3.set("expnotpayamount",fexpapplyamountBen.subtract(newEntry3.getBigDecimal("exppayedamount"))); // 未付金额(本位币)
                // 可预付金额=含税金额 - 已预付金额，可预付金额(本位币)=含税金额(本位币) - 已预付金额(本位币)
                newEntry3.set("canloanamount",fexpapplyamount.subtract(newEntry3.getBigDecimal("pushedamount"))); // 可预付金额
                newEntry3.set("canloancurramount",fexpapplyamountBen.subtract(newEntry3.getBigDecimal("pushedcurramount"))); // 可预付金额(本位币)
                // 可报销金额=含税金额 - 已报销金额，可报销金额(本位币)=含税金额(本位币) - 已报销金额(本位币)
                newEntry3.set("orgiexpebalanceamount",fexpapplyamount.subtract(newEntry3.getBigDecimal("reimbursedamount"))); // 可报销金额
                newEntry3.set("expebalanceamount",fexpapplyamountBen.subtract(newEntry3.getBigDecimal("reimbursedcurramount"))); // 可报销金额(本位币)

                // 累加给头表字段
                yifutotal = yifutotal.add(newEntry3.getBigDecimal("oriexppayedamount")); // 已付金额--头表
                yifutotalBen = yifutotalBen.add(newEntry3.getBigDecimal("exppayedamount")); // 已付金额-本位币--头表
                yibaoxiaototal = yibaoxiaototal.add(newEntry3.getBigDecimal("reimbursedamount")); // 已报销金额--头表
                yibaoxiaototalBen = yibaoxiaototalBen.add(newEntry3.getBigDecimal("reimbursedcurramount")); // 已报销金额-本位币--头表
            }

            newEntry3.set("orientryamount",fexpapplyamount); // 不含税金额
            newEntry3.set("acorientryamount",fexpapplyamount); // 变更后不含税
            newEntry3.set("expenseamount",fexpapplyamount); // 含税金额
            newEntry3.set("acexpeapproveamount",fexpapplyamount); // 变更后含税金额
            newEntry3.set("currexpenseamount",fexpapplyamountBen); // 含税金额(本位币),四舍五入
            newEntry3.set("acexpeapprovecurramount",fexpapplyamountBen); // 变更后含税金额(本位币)

            // 累加给头表字段
            hetongjinetotalfist = hetongjinetotalfist.add(fexpapplyamount); // 进行累加付给合同金额
            hetongjinetotalfistBen = hetongjinetotalfistBen.add(fexpapplyamountBen); // 进行累加付给合同金额(本位币)

            DynamicObject fukuantype = BusinessDataServiceHelper.loadSingle("cas_paymentbilltype","id,name",new QFilter[]{new QFilter("number",QCP.equals,"201")});
            newEntry3.set("paymenttypeid",fukuantype); // 付款类型
            newEntry3.set("payterms",fpayterms); // 付款条件
            try {
                newEntry3.set("happendate",sdf.parse("2999-12-31")); // 预计付款日期
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
            newEntry3.set("entrycostdept",company); // 费用承担部门
            newEntry3.set("entrycostcompany",company); // 费用承担公司
            newEntry3.set("exchangerate",huilv); // 汇率
            // 固定值 FYXM99.01 合同款
            DynamicObject feiyongproject = BusinessDataServiceHelper.loadSingle("er_expenseitemedit","id,name",new QFilter[]{new QFilter("number",QCP.equals,"FYXM99.01")});
            newEntry3.set("expenseitem",feiyongproject); // 费用项目

            // 项目
            String std_project = jsb.getString("projectid"); // 项目编码
            QFilter qFilterpj = new QFilter("number", QCP.equals, std_project)
                    .and("createorg",QCP.not_equals,2220437039650717696L); // 创建组织 不等于 上海济煜医药科技股份有限公司北京分公司
            DynamicObject[] projectList = BusinessDataServiceHelper.load("bd_project", "id,name", new QFilter[]{qFilterpj});
            if (projectList != null && projectList.length > 0) {
                newEntry3.set("std_project",projectList[0]);
                dynamicObject.set("nckd_project", projectList[0]); // 头表项目字段
            }

            newEntry3.set("entrycurrency",bizhong); // 分录币别（和头表一致）

            if (isnew) {
                plannewColl.add(newEntry3);
            }
        }

        // 1.4）头表金额字段处理：合同总额(初始)值为0时，为框架合同，则星瀚不需要处理，付款计划栏、以及合同总价栏的合同总额（初始）、合同总额（变更后）
        if (hetongjinetotalfist.compareTo(BigDecimal.ZERO) == 0) {
            dynamicObject.set("frameworkcontract",true); // 框架合同：是
            dynamicObject.set("contractamount", 0); // 合同总额(初始)
            dynamicObject.set("oriapplyamount", 0); // 合同总额(变更后)
            dynamicObject.set("originalamount", 0); // 合同总额(不含税)
            dynamicObject.set("orinotpayamount", 0); // 未付金额
            plannewColl.clear(); // 付款计划分录无记录
        } else {
            dynamicObject.set("frameworkcontract",false); // 框架合同：否
            dynamicObject.set("contractamount", hetongjinetotalfist); // 头表字段：合同总额(初始)
            dynamicObject.set("oriapplyamount", hetongjinetotalfist); // 头表字段：合同总额(变更后)
            dynamicObject.set("applyamount", hetongjinetotalfist.multiply(huilv).setScale(2, RoundingMode.HALF_UP)); // 头表字段：合同总额(变更后)本位币 = 合同总额(变更后) * 汇率
            dynamicObject.set("originalamount", hetongjinetotalfist); // 头表字段：合同总额(不含税)
            if (isnew) {
                // 第一次合同送入,新增
                dynamicObject.set("oripayedamount", 0); // 头表字段：已付金额
                dynamicObject.set("payedamount", 0); // 头表字段：已付金额（本位币）
                dynamicObject.set("oriusedamount", 0); // 头表字段：已报销金额
                dynamicObject.set("usedamount", 0); // 头表字段：已报销金额(本位币)
                dynamicObject.set("orinotpayamount", hetongjinetotalfist); // 头表字段：未付金额
                dynamicObject.set("notpayamount",hetongjinetotalfistBen ); // 头表字段：未付金额(本位币)
                dynamicObject.set("oricanloanamount", hetongjinetotalfist); // 头表字段：可预付金额
                dynamicObject.set("billcanloanamount", hetongjinetotalfistBen); // 头表字段：可预付金额(本位币)
                dynamicObject.set("oribalanceamount", hetongjinetotalfist); // 头表字段：可报销金额
                dynamicObject.set("balanceamount", hetongjinetotalfistBen); // 头表字段：可报销金额(本位币)
                dynamicObject.set("oriavailableamount", hetongjinetotalfist); // 头表字段：可用金额
                dynamicObject.set("availableamount", hetongjinetotalfistBen); // 头表字段：可用金额(本位币)
            } else {
                // 第二次合同送入，更新
                // a)头表字段：已付金额,已付金额（本位币）是星翰系统反写到合同台账单上的
                BigDecimal oripayedamount = dynamicObject.getBigDecimal("oripayedamount"); // 头表字段：已付金额
                BigDecimal payedamount = dynamicObject.getBigDecimal("payedamount"); // 头表字段：已付金额（本位币）
                // b)头表字段：已报销金额,已报销金额（本位币）是星翰系统反写到合同台账单上的
                BigDecimal oriusedamount = dynamicObject.getBigDecimal("oriusedamount"); // 头表字段：已报销金额
                BigDecimal usedamount = dynamicObject.getBigDecimal("usedamount"); // 头表字段：已报销金额(本位币)
                // c)头表字段：已预付金额,已预付金额（本位币）是星翰系统反写到合同台账单上的
                BigDecimal oriloanedamount = dynamicObject.getBigDecimal("oriloanedamount"); // 头表字段：已预付金额
                BigDecimal loanedamount = dynamicObject.getBigDecimal("loanedamount"); // 头表字段：已预付金额(本位币)

                // d)未付金额=合同金额 - 已付金额，未付金额(本位币)=合同金额(本位币) - 已付金额(本位币)
                dynamicObject.set("orinotpayamount", hetongjinetotalfist.subtract(oripayedamount)); // 头表字段：未付金额
                dynamicObject.set("notpayamount", hetongjinetotalfistBen.subtract(payedamount)); // 头表字段：未付金额(本位币)
                // e)可预付金额=合同金额 - 已预付金额，可预付金额(本位币)=合同金额(本位币) - 已预付金额(本位币)
                dynamicObject.set("oricanloanamount", hetongjinetotalfist.subtract(oriloanedamount)); // 头表字段：可预付金额
                dynamicObject.set("billcanloanamount", hetongjinetotalfistBen.subtract(loanedamount)); // 头表字段：可预付金额(本位币)
                // f)可报销金额=合同金额 - 已报销金额，可报销金额(本位币)=合同金额(本位币) - 已报销金额(本位币)
                dynamicObject.set("oribalanceamount", hetongjinetotalfist.subtract(oriusedamount)); // 头表字段：可报销金额
                dynamicObject.set("balanceamount", hetongjinetotalfist.subtract(usedamount)); // 头表字段：可报销金额(本位币)
                // g)可用金额=合同金额 - 已付金额，可用金额(本位币)=合同金额(本位币) - 已付金额(本位币)
                dynamicObject.set("oriavailableamount", hetongjinetotalfist.subtract(oripayedamount)); // 头表字段：可用金额
                dynamicObject.set("availableamount", hetongjinetotalfistBen.subtract(payedamount)); // 头表字段：可用金额(本位币)
            }

            dynamicObject.set("expenseentryentity", plannewColl); // 付款计划分录
        }

        // 1.5）先单据保存
        OperationResult opResult = SaveServiceHelper.saveOperate(entityNumber, new DynamicObject[]{dynamicObject}, OperateOption.create());

        if (!opResult.isSuccess()) {
            // 保存失败
            result.setMessage(opResult.getMessage());
            result.setStatus(false);
            return result;
        }

        // 2）相同的单据第二次送入接口，新文件和历史文件重名时，删掉历史文件，新增新文件
        // 获取历史单据全部附件
       List<Map<String, Object>> atts = AttachmentServiceHelper.getAttachments(entityNumber, dynamicObject.getPkValue(),"attachmentpanel");
        if (!atts.isEmpty()) {
            Iterator<Map<String, Object>> iterator = atts.iterator();
            // 遍历所有附件
            while (iterator.hasNext()) {
                Map map2 = iterator.next();
                String oldfileName = map2.get("name").toString();
                if (attIsExist(allAttachmentsData,oldfileName)) {
                    // 接口送来的附件已经在历史单据中存在，需要删掉历史单据的附件
                    String formId = map2.get("entityNum").toString();
                    Object pkId = map2.get("billPkId"); // 单据id
                    Object fileUid = map2.get("uid");
                    //从数据库中删除上一次保存的附件
                    AttachmentServiceHelper.remove(formId, pkId, fileUid);
                }
            }
        }

        // 3）接口送入的附件全部保存入库
        if (allAttachmentsData != null) {
            Map<String, Object> attachmentInfos = new HashMap<>();
            for (Map.Entry<String, List<Map<String,Object>>> entry : allAttachmentsData.entrySet()) {
                if ("attachmentpanel".equals(entry.getKey())) {
                    // 取‘附件面板’的附件集合
                    List<Map<String, Object>> fileList = entry.getValue();
                    List<Map<String, Object>> attachments = new ArrayList<>();
                    for (int i= 0; i < fileList.size(); i++) {
                        Map<String, Object> map = fileList.get(i);
                        StringBuffer uid = new StringBuffer();
                        uid.append("rc-upload-").append(new Date().getTime()).append("-");
                        Map<String,Object> attachmentInfo = new HashMap<>();
                        attachmentInfo.put("entityNumber", entityNumber);
                        attachmentInfo.put("name", map.get("fileName"));
                        if (StringUtils.isEmpty((String)map.get("tempurl"))) {
                            result.setMessage("文件服务器临时路径tempurl未传值");
                            result.setStatus(false);
                            return result;
                        }
                        attachmentInfo.put("url", map.get("tempurl"));
                        attachmentInfo.put("size", map.get("size"));
                        attachmentInfo.put("status", map.get("status"));
                        attachmentInfo.put("uid", uid.toString() + i);
                        attachments.add(attachmentInfo);
                    }
                    attachmentInfos.put("attachmentpanel",attachments);
                }
            }

            AttachmentServiceHelper.saveTempAttachments(entityNumber, pkid, appId, attachmentInfos);

        }

        result.setMessage("成功");
        return result;
    }

    /**
     * 检查历史附件文件名是否存在本次接口送入的附件中
     * @param sendallAttachmentsData 接口送入的附件集合
     * @param oldfileName 历史附件名称
     * @return true：存在 ，false：不存在
     */
    boolean attIsExist(Map<String, List<Map<String,Object>>> sendallAttachmentsData, String oldfileName) {
        if (sendallAttachmentsData != null) {
            for (Map.Entry<String, List<Map<String,Object>>> entry : sendallAttachmentsData.entrySet()) {
                if ("attachmentpanel".equals(entry.getKey())) {
                    // 取‘附件面板’的附件集合
                    List<Map<String, Object>> fileList = entry.getValue();
                    for (int i= 0; i < fileList.size(); i++) {
                        Map<String, Object> map = fileList.get(i);
                        String newfilename =  map.get("fileName").toString();
                        if (oldfileName.equals(newfilename)) {
                            // 接口送入的附件名称，已经存在历史合同单据中，需要删掉历史合同单据的附件
                            return true; // 已存在
                        }
                    }
                }
            }
        }
        return false; // 不存在
    }

}
