package nckd.jimin.jyyy.fi.task;

import kd.bos.algo.DataSet;
import kd.bos.context.RequestContext;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.db.tx.TX;
import kd.bos.db.tx.TXHandle;
import kd.bos.entity.EntityMetadataCache;
import kd.bos.exception.KDException;
import kd.bos.id.ID;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.orm.ORM;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.schedule.executor.AbstractTask;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.QueryServiceHelper;
import kd.bos.servicehelper.coderule.CodeRuleServiceHelper;
import kd.bos.servicehelper.operation.SaveServiceHelper;
import kd.bos.util.CollectionUtils;
import kd.bos.util.StringUtils;
import nckd.jimin.jyyy.fi.common.constant.BillTypeConstants;
import nckd.jimin.jyyy.fi.common.constant.travelcheck.*;
import nckd.jimin.jyyy.fi.common.util.CommonUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 创建商旅对账确认单
 */
public class TravelFinanConfirmCreateTask extends AbstractTask {

    private static final Log logger = LogFactory.getLog(TravelFinanConfirmCreateTask.class);

    /**
     * 执行期间，默认为当前时间
     */
    private Date periodEndDate;

    /**
     * 账期时间，默认为上个月第一天
     */
    private Date periodStartDate;

    @Override
    public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
        logger.info("TravelFinanConfirmCreateTask begin");
        periodEndDate = new Date();
        // 创建当月的财务底稿确认单
       if(map.containsKey("startDate") && map.get("startDate") != null && StringUtils.isNotEmpty(map.get("startDate").toString())){
           SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
           try {
               periodEndDate = sdf.parse((String)map.get("startDate"));
           } catch (ParseException e) {
               throw new RuntimeException(e);
           }
       }
       // 开始日期取当月第一天
        periodEndDate = getFirstDayOfMonth(periodEndDate);
        periodStartDate = getFirstDayOfPreviousMonth(periodEndDate);

        String period = CommonUtils.parsePeriod(periodStartDate);
        DynamicObject financeConfirmInfo = BusinessDataServiceHelper.loadSingle(FinanceBillConfirmConstant.ENTITYID,
                FinanceBillConfirmConstant.ID,
                new QFilter(FinanceBillConfirmConstant.NCKD_CHECKMONTH, QCP.equals, period).toArray());
        if(financeConfirmInfo != null){
//            logger.info(String.format("期间[%s]已经存在商旅对账确认单，请勿重复创建！", period));
//            return;
            financeConfirmInfo = BusinessDataServiceHelper.loadSingle(financeConfirmInfo.getPkValue(),financeConfirmInfo.getDynamicObjectType().getName());
        }else{
            financeConfirmInfo = BusinessDataServiceHelper.newDynamicObject(FinanceBillConfirmConstant.ENTITYID);
            // 创建ID，用ID来清除已创建的数据
            long financeConfirmId = ID.genLongId();
            String number = CodeRuleServiceHelper.getNumber(FinanceBillConfirmConstant.ENTITYID, financeConfirmInfo, null);
            financeConfirmInfo.set(FinanceBillConfirmConstant.KEY_BILLNO, number);
            financeConfirmInfo.set(FinanceBillConfirmConstant.ID, financeConfirmId);
            financeConfirmInfo.set(FinanceBillConfirmConstant.NCKD_CHECKMONTH, period);
            financeConfirmInfo.set(FinanceBillConfirmConstant.KEY_BILLSTATUS, "A");

            DynamicObject currency = BusinessDataServiceHelper.loadSingle("bd_currency", new QFilter("number", QCP.equals, "CNY").toArray());
            financeConfirmInfo.set(FinanceBillConfirmConstant.NCKD_CURRENCY, currency);

        }
        try(TXHandle tx = TX.requiresNew(this.getClass().getName())){
            try {

                // 创建差旅补助
                createBzEntry(financeConfirmInfo);
                // 创建商旅费用
                createSlEntry(financeConfirmInfo);
                // 创建用车汇总
                createYcEntry(financeConfirmInfo);
                // 创建超标明细
                createCbEntry(financeConfirmInfo);
                // 创建退改明细
                createTgEntry(financeConfirmInfo);
                // 创建同性别未同住
                createZsEntry(financeConfirmInfo);
                SaveServiceHelper.save(new DynamicObject[]{financeConfirmInfo});

            }catch (Exception e){
                tx.markRollback();
                logger.error(String.format("创建期间[%s]下的商旅对账确认单失败。", period),e);
                throw e;
            }
        }
        logger.info("TravelFinanConfirmCreateTask end");
    }
    protected void createZsEntry(DynamicObject financeConfirmInfo) {

        DynamicObjectCollection checkingBillCol = QueryServiceHelper.query("er_checkingbill", "billnum", new QFilter[]{
                new QFilter("periodstartdate", QCP.large_equals, periodStartDate),
                new QFilter("periodenddate", QCP.less_than, periodEndDate),
                new QFilter("operationtype", QFilter.in, Arrays.asList("1","5")),
        });
        if(CollectionUtils.isEmpty(checkingBillCol)){
            return;
        }
        List<String> billNumList = checkingBillCol.stream().map(r -> r.getString("billnum")).collect(Collectors.toList());

        // 查询酒店订单中，相同部门、性别、酒店城市中，入住时间存在交集的数据，按照部门、性别、酒店城市进行排序
        DynamicObjectCollection queryHotelCol = QueryServiceHelper.query("er_hotelcheckingbill",
                "id,org.id,oabillnum,sourcebookedid.id applierId,sourcebookedid.gender applierGender,totalamount,cityname,checkindate,checkoutdate," +
                        "hotelname,roomstylename,ordernum", new QFilter[]{
                QFilter.isNotNull("sourcebookedid"),
                        new QFilter("checkingbillnum", QCP.in, billNumList),
                new QFilter("ordertype", QCP.in, Arrays.asList("O","G")),
                new QFilter("orderstatus", QCP.not_in, Arrays.asList("14","10")),
        });

        // 按照部门、性别、酒店城市进行分组
        Map<String, List<DynamicObject>> applierGroupMap = queryHotelCol.stream()
                .filter(dyx -> StringUtils.isNotEmpty(dyx.getString("org.id")) && StringUtils.isNotEmpty(dyx.getString("applierGender"))
                        && StringUtils.isNotEmpty(dyx.getString("cityname")))
                .collect(Collectors.groupingBy(dyx -> String.join("_", dyx.getString("org.id"), dyx.getString("applierGender"), dyx.getString("cityname"))));
        // 创建分录
        Map<String, List<DynamicObject>> filterSameDateHotel = filterSameDateHotel(applierGroupMap);

        long confirmBillId = financeConfirmInfo.getLong("id");
        DynamicObjectCollection zsEntryCol = financeConfirmInfo.getDynamicObjectCollection(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.ENTITYID);
        zsEntryCol.clear();
        List<Long> updateHotelBillIdList = new ArrayList<>();
        for(Map.Entry<String, List<DynamicObject>> sameDeptRow : filterSameDateHotel.entrySet()){
            String sameDeptRowKey = sameDeptRow.getKey();
            List<DynamicObject> hotelList = sameDeptRow.getValue();
            for(DynamicObject hotel : hotelList){
                DynamicObject zsEntry = zsEntryCol.addNew();
                Long applierId = hotel.getLong("applierId");
                DynamicObject applierInfo = BusinessDataServiceHelper.loadSingleFromCache(applierId, "bos_user");
                zsEntry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_SOURCEBOOKEDID, applierInfo);
                zsEntry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_ORDERNUM, hotel.getString("ordernum"));

                createApplierInfo(zsEntry,applierInfo);
                zsEntry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_GENDER, hotel.getString("applierGender"));
                zsEntry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_CHECKINDATE, hotel.getDate("checkindate"));
                zsEntry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_CHECKOUTDATE, hotel.getDate("checkoutdate"));
                zsEntry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_CITYNAME, hotel.getString("cityname"));
                zsEntry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_HOTELNAME, hotel.getString("hotelname"));
                zsEntry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_ROOMTYPE, hotel.getString("roomstylename"));
                zsEntry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_LIVEDAYS, CommonUtils.getDays(hotel.getDate("checkindate"), hotel.getDate("checkoutdate")));
                zsEntry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_TOTALAMOUNT, hotel.getBigDecimal("totalamount"));
                updateHotelBillIdList.add(hotel.getLong("id"));
            }
        }
//        DynamicObject[] updateHotelBillArray = BusinessDataServiceHelper.load("er_hotelcheckingbill", FinanceBillConfirmConstant.NCKD_ZS_CONFRMID, new QFilter("id", QCP.in, updateHotelBillIdList).toArray());
//        for(DynamicObject  hotel : updateHotelBillArray){
//            hotel.set(FinanceBillConfirmConstant.NCKD_ZS_CONFRMID, confirmBillId);
//        }
//        SaveServiceHelper.save(updateHotelBillArray);
    }

    /**
     * 获取指定日期所在月份的第一天
     * @param stardDate 指定日期
     * @return 该日期所在月份第一天的日期对象，时间为当月1日00:00:00
     */
    public Date getFirstDayOfMonth(Date stardDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(stardDate); // 设置为指定日期
        calendar.set(Calendar.DAY_OF_MONTH, 1); // 设置为该月第一天
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取指定日期的上个月第一天
     * @param stardDate 指定日期
     * @return 上个月第一天的日期对象，时间为当月1日00:00:00
     */
    public Date getFirstDayOfPreviousMonth(Date stardDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(stardDate); // 设置为指定日期
        calendar.add(Calendar.MONTH, -1); // 回退一个月
        calendar.set(Calendar.DAY_OF_MONTH, 1); // 设置为该月第一天
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }


    protected  Map<String, List<DynamicObject>> filterSameDateHotel(Map<String, List<DynamicObject>> applierGroupMap){
        // 过滤出入住时间存在交集的数据
        Map<String, List<DynamicObject>> filteredApplierGroupMap = new HashMap<>();

        // 遍历每个分组，查找有时间重叠的记录
        for (Map.Entry<String, List<DynamicObject>> group : applierGroupMap.entrySet()) {
            List<DynamicObject> recordsWithOverlappingDates = new ArrayList<>();
            List<DynamicObject> recordsInGroup = group.getValue();

            // 对于分组中的每条记录，检查是否与其他记录的入住/离店时间有重叠
            for (DynamicObject currentRecord : recordsInGroup) {
                Date currentCheckin = currentRecord.getDate("checkindate");
                Date currentCheckout = currentRecord.getDate("checkoutdate");

                // 检查当前记录是否与分组中的其他记录存在时间重叠
                boolean hasOverlapping = false;
                for (DynamicObject otherRecord : recordsInGroup) {
                    // 不与自己比较
                    if (currentRecord == otherRecord) {
                        continue;
                    }

                    // 不与同一预定人比较
                    if(currentRecord.getLong("applierId") == otherRecord.getLong("applierId")){
                        continue;
                    }
                    Date otherCheckin = otherRecord.getDate("checkindate");
                    Date otherCheckout = otherRecord.getDate("checkoutdate");

                    // 判断两个时间段是否有重叠:
                    // 当前记录入住日期早于其他记录离店日期
                    // 且 当前记录离店日期晚于其他记录入住日期
                    if (currentCheckin.before(otherCheckout) && currentCheckout.after(otherCheckin)) {
                        hasOverlapping = true;
                        break;
                    }
                }

                // 如果存在时间重叠，则添加到结果列表中
                if (hasOverlapping) {
                    recordsWithOverlappingDates.add(currentRecord);
                }
            }

            // 只有当分组中存在有时间重叠的记录时，才添加到最终结果中
            if (!recordsWithOverlappingDates.isEmpty()) {
                filteredApplierGroupMap.put(group.getKey(), recordsWithOverlappingDates);
            }
        }
        return filteredApplierGroupMap;
    }
    protected void createTgEntry(DynamicObject financeConfirmInfo) {
        // 通过全部结算单，查询关联的订单号，再通过订单号查询指定状态的订单数据

        long confirmBillId = financeConfirmInfo.getLong("id");

        DynamicObjectCollection tgEntryCol = financeConfirmInfo.getDynamicObjectCollection(FinanceBillConfirmConstant.NCKD_TG_ENTRY.ENTITYID);
        tgEntryCol.clear();
        createTgEntryTrain(confirmBillId , tgEntryCol);
        createTgEntryPlain(confirmBillId , tgEntryCol);
        createTgEntryHotel(confirmBillId , tgEntryCol);

    }

    protected void createTgEntryTrain(Long confirmBillId , DynamicObjectCollection tgEntryCol){
        DynamicObjectCollection checkingBillCol = QueryServiceHelper.query("er_checkingbill", "billnum", new QFilter[]{
                new QFilter("periodstartdate", QCP.large_equals, periodStartDate),
                new QFilter("periodenddate", QCP.less_than, periodEndDate),
                new QFilter("operationtype", QFilter.equals, "6"),
        });
        if(CollectionUtils.isEmpty(checkingBillCol)){
            return;
        }

        List<String> billNumList = checkingBillCol.stream().map(r -> r.getString("billnum")).collect(Collectors.toList());

        //火车订单，订单状态=已退票、已改签;
        DynamicObjectCollection trainTgEntryCol = QueryServiceHelper.query("er_traincheckingbill",
                "id,oabillnum,sourcebookedid.id applierId,totalamount,orderstatus,ordertype,ordernum,happenddate,departtime,arrivecity,departcity" +
                        ",refundamount", new QFilter[]{
                        new QFilter("checkingbillnum", QCP.in, billNumList),
                        new QFilter("orderstatus", QFilter.in, Arrays.asList("2","3")),
                        new QFilter("ordertype", QFilter.in, Arrays.asList("G","T"))
                });
        for(DynamicObject trainTgEntry : trainTgEntryCol){
            DynamicObject tgEntry = tgEntryCol.addNew();
            long applierId = trainTgEntry.getLong("applierId");
            DynamicObject applierInfo = BusinessDataServiceHelper.loadSingleFromCache(applierId, "bos_user");
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_TRAVELER, applierInfo);
            createApplierInfo(tgEntry,applierInfo);

            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_ORDERTYPE, "train");
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_TYPE, trainTgEntry.getString("ordertype"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_TRIPREQBILLNO, trainTgEntry.getString("oabillnum"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_ORDERNUM, trainTgEntry.getString("ordernum"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_HAPPENDDATE, trainTgEntry.getDate("happenddate"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_DEPARTIME, trainTgEntry.getDate("departtime"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_TRIPCITY, String.join("-", trainTgEntry.getString("departcity"), trainTgEntry.getString("arrivecity")));
            // 退改金额
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_MODIFYAMT, trainTgEntry.getBigDecimal("refundamount"));
            //tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_SUMAMT, trainTgEntry.getBigDecimal("totalamount"));
        }
//        List<Long> idList = trainTgEntryCol.stream().map(r -> r.getLong("id")).collect(Collectors.toList());
//        DynamicObject[] updateBillArray = BusinessDataServiceHelper.load("er_traincheckingbill", FinanceBillConfirmConstant.NCKD_ZS_CONFRMID, new QFilter("id", QCP.in, idList).toArray());
//        for(DynamicObject updateBill : updateBillArray){
//            updateBill.set(FinanceBillConfirmConstant.NCKD_ZS_CONFRMID, confirmBillId);
//        }
//        SaveServiceHelper.save(updateBillArray);
    }

    protected void createTgEntryPlain(Long confirmBillId , DynamicObjectCollection tgEntryCol){

        DynamicObjectCollection checkingBillCol = QueryServiceHelper.query("er_checkingbill", "billnum", new QFilter[]{
                new QFilter("periodstartdate", QCP.large_equals, periodStartDate),
                new QFilter("periodenddate", QCP.less_than, periodEndDate),
                new QFilter("operationtype", QFilter.in, Arrays.asList("2","4")),
        });
        if(CollectionUtils.isEmpty(checkingBillCol)){
            return;
        }

        List<String> billNumList = checkingBillCol.stream().map(r -> r.getString("billnum")).collect(Collectors.toList());
        // 机票订单，订单状态=已退票、已改签；
        DynamicObjectCollection trainTgEntryCol = QueryServiceHelper.query("er_planecheckingbill",
                "id,oabillnum,sourcebookedid.id applierId,totalamount,orderstatus,ordertype,ordernum,happenddate,takeofftime,fromcityname,tocityname," +
                        "refundamount,endorsementamount", new QFilter[]{
                        new QFilter("checkingbillnum", QCP.in, billNumList),
                        new QFilter("orderstatus", QFilter.in, Arrays.asList("50202","50302")),
                        new QFilter("ordertype", QFilter.in, Arrays.asList("G","T"))
                });
        for(DynamicObject trainTgEntry : trainTgEntryCol){
            DynamicObject tgEntry = tgEntryCol.addNew();
            long applierId = trainTgEntry.getLong("applierId");
            DynamicObject applierInfo = BusinessDataServiceHelper.loadSingleFromCache(applierId, "bos_user");
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_TRAVELER, applierInfo);
            createApplierInfo(tgEntry,applierInfo);

            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_ORDERTYPE, "air");
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_TYPE, trainTgEntry.getString("ordertype"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_TRIPREQBILLNO, trainTgEntry.getString("oabillnum"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_ORDERNUM, trainTgEntry.getString("ordernum"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_HAPPENDDATE, trainTgEntry.getDate("happenddate"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_DEPARTIME, trainTgEntry.getDate("takeofftime"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_TRIPCITY, String.join("-", trainTgEntry.getString("fromcityname"), trainTgEntry.getString("tocityname")));
            // 退改金额
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_MODIFYAMT, CommonUtils.add(trainTgEntry.getBigDecimal("refundamount"), trainTgEntry.getBigDecimal("endorsementamount")));
            //tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_SUMAMT, trainTgEntry.getBigDecimal("totalamount"));
        }
//        List<Long> idList = trainTgEntryCol.stream().map(r -> r.getLong("id")).collect(Collectors.toList());
//        DynamicObject[] updateBillArray = BusinessDataServiceHelper.load("er_planecheckingbill", FinanceBillConfirmConstant.NCKD_ZS_CONFRMID, new QFilter("id", QCP.in, idList).toArray());
//        for(DynamicObject updateBill : updateBillArray){
//            updateBill.set(FinanceBillConfirmConstant.NCKD_ZS_CONFRMID, confirmBillId);
//        }
//        SaveServiceHelper.save(updateBillArray);
    }

    protected void createTgEntryHotel(Long confirmBillId , DynamicObjectCollection tgEntryCol){

        DynamicObjectCollection checkingBillCol = QueryServiceHelper.query("er_checkingbill", "billnum", new QFilter[]{
                new QFilter("periodstartdate", QCP.large_equals, periodStartDate),
                new QFilter("periodenddate", QCP.less_than, periodEndDate),
                new QFilter("operationtype", QFilter.in, Arrays.asList("1","5")),
        });
        if(CollectionUtils.isEmpty(checkingBillCol)){
            return;
        }

        List<String> billNumList = checkingBillCol.stream().map(r -> r.getString("billnum")).collect(Collectors.toList());
        // 酒店订单，订单状态=已退订；
        DynamicObjectCollection hotelTgEntryCol = QueryServiceHelper.query("er_hotelcheckingbill",
                "id,oabillnum,server,sourcebookedid.id applierId,totalamount,orderstatus,ordertype,ordernum,happenddate," +
                        "unbookfee,checkindate", new QFilter[]{
                        new QFilter("checkingbillnum", QCP.in, billNumList),
                        new QFilter("orderstatus", QFilter.equals, "10"),
                        new QFilter("ordertype", QFilter.in, Arrays.asList("G","T"))
                });
        for(DynamicObject trainTgEntry : hotelTgEntryCol){
            DynamicObject tgEntry = tgEntryCol.addNew();
            long applierId = trainTgEntry.getLong("applierId");
            DynamicObject applierInfo = BusinessDataServiceHelper.loadSingleFromCache(applierId, "bos_user");
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_TRAVELER, applierInfo);
            createApplierInfo(tgEntry,applierInfo);

            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_ORDERTYPE, "hotal");
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_TYPE, trainTgEntry.getString("ordertype"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_TRIPREQBILLNO, trainTgEntry.getString("oabillnum"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_ORDERNUM, trainTgEntry.getString("ordernum"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_HAPPENDDATE, trainTgEntry.getDate("happenddate"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_DEPARTIME, trainTgEntry.getDate("checkindate"));
            //tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_TRIPCTY, trainTgEntry.getString("arrivecity"));
            // 退改金额
            tgEntry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_MODIFYAMT, trainTgEntry.getBigDecimal("unbookfee"));
        }
//        List<Long> idList = hotelTgEntryCol.stream().map(r -> r.getLong("id")).collect(Collectors.toList());
//        DynamicObject[] updateBillArray = BusinessDataServiceHelper.load("er_hotelcheckingbill", FinanceBillConfirmConstant.NCKD_ZS_CONFRMID, new QFilter("id", QCP.in, idList).toArray());
//        for(DynamicObject updateBill : updateBillArray){
//            updateBill.set(FinanceBillConfirmConstant.NCKD_ZS_CONFRMID, confirmBillId);
//        }
//        SaveServiceHelper.save(updateBillArray);
    }

    protected void createCbEntry(DynamicObject financeConfirmInfo) {
        long confirmBillId = financeConfirmInfo.getLong("id");
        DynamicObjectCollection cbEntryCol = financeConfirmInfo.getDynamicObjectCollection(FinanceBillConfirmConstant.NCKD_CB_ENTRY.ENTITYID);
        cbEntryCol.clear();
        createCbEntryTrain(confirmBillId , cbEntryCol);
        createCbEntryPlain(confirmBillId , cbEntryCol);
        createCbEntryHotel(confirmBillId , cbEntryCol);
        createCbEntryVehicle(confirmBillId , cbEntryCol);
    }

    protected void createCbEntryTrain(Long confirmBillId , DynamicObjectCollection tgEntryCol){

        DynamicObjectCollection checkingBillCol = QueryServiceHelper.query("er_checkingbill", "billnum", new QFilter[]{
                new QFilter("periodstartdate", QCP.large_equals, periodStartDate),
                new QFilter("periodenddate", QCP.less_than, periodEndDate),
//                new QFilter(FinanceBillConfirmConstant.NCKD_CB_CONFRMID, QFilter.equals, 0)
//                        .or(QFilter.isNull(FinanceBillConfirmConstant.NCKD_CB_CONFRMID)),
                new QFilter("operationtype", QFilter.equals, "6"),
        });
        if(CollectionUtils.isEmpty(checkingBillCol)){
            return;
        }
        List<String> billNumList = checkingBillCol.stream().map(r -> r.getString("billnum")).collect(Collectors.toList());

        DynamicObjectCollection trainTgEntryCol = QueryServiceHelper.query("er_traincheckingbill",
                "id,oabillnum,sourcebookedid.id applierId,totalamount,orderstatus,ordertype,ordernum,happenddate", new QFilter[]{
                        new QFilter("checkingbillnum", QCP.in, billNumList)
                });
        // 通过火车订单过滤出超标的订单
        List<String> parentOrderList = trainTgEntryCol.stream().map(r -> r.getString("ordernum")).collect(Collectors.toList());
        Map<String, String> orderOverDescMap = QueryServiceHelper.query("er_trainbill", "ordernum,overdesc", new QFilter[]{
                        new QFilter("ordernum", QCP.in, parentOrderList),
                        QFilter.isNotNull("overdesc")
                }).stream()
                .filter(r -> StringUtils.isNotEmpty(r.getString("overdesc")))
                .collect(Collectors.toMap(r -> r.getString("ordernum"), r -> r.getString("overdesc")));
        for(DynamicObject trainTgEntry : trainTgEntryCol){
            if(orderOverDescMap.containsKey(trainTgEntry.getString("ordernum"))){
                DynamicObject tgEntry = tgEntryCol.addNew();
                long applierId = trainTgEntry.getLong("applierId");
                DynamicObject applierInfo = BusinessDataServiceHelper.loadSingleFromCache(applierId, "bos_user");
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_TRAVELER, applierInfo);
                createApplierInfo(tgEntry,applierInfo);
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_TRIPREQBILLNO, trainTgEntry.getString("oabillnum"));
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_ORDERBILLNO, trainTgEntry.getString("ordernum"));
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_ORDERAMT, trainTgEntry.getBigDecimal("totalamount"));
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_TYPE, "train");
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_STANDARD, BigDecimal.ZERO);
                String standardInfo = "";
                // 通过员工的岗位，查询对应的报销级别
                DynamicObject reimLeverSettingInfo = QueryServiceHelper.queryOne("er_reimbursesetting_rel", "reimburselevel.id", new QFilter("user", QCP.equals, applierInfo.getLong("id")).toArray());
                if(reimLeverSettingInfo != null && reimLeverSettingInfo.getLong("reimburselevel.id") != 0L){
                    // 通过差旅报销级别，查询对应的报销标准
                    DynamicObject tripStandard = BusinessDataServiceHelper.loadSingle("er_tripstandard_vehicle","seats",new QFilter[]{
                            new QFilter("reimburselevel.fbasedataid.id", QCP.equals, reimLeverSettingInfo.getLong("reimburselevel.id")),
                            new QFilter("standardtype", QCP.equals, "train")
                    });
                    if(tripStandard != null){
                        standardInfo = tripStandard.getDynamicObjectCollection("seats")
                                .stream()
                                .map(r -> r.getDynamicObject("fbasedataid").getString("name"))
                                .collect(Collectors.joining(";"));
                    }
                }
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_STANDARD_INFO, standardInfo);
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_OVERREASON, orderOverDescMap.get(trainTgEntry.getString("ordernum")));
            }
        }
//        List<Long> updateIdList = checkingBillCol.stream().map(r -> r.getLong("id")).collect(Collectors.toList());
//        DynamicObject[] updateBillArray = BusinessDataServiceHelper.load("er_checkingbill", FinanceBillConfirmConstant.NCKD_CB_CONFRMID, new QFilter("id", QCP.in, updateIdList).toArray());
//        for(DynamicObject updateBill : updateBillArray){
//            updateBill.set(FinanceBillConfirmConstant.NCKD_CB_CONFRMID, confirmBillId);
//        }
//        SaveServiceHelper.save(updateBillArray);
    }


    protected void createCbEntryPlain(Long confirmBillId , DynamicObjectCollection tgEntryCol){

        DynamicObjectCollection checkingBillCol = QueryServiceHelper.query("er_checkingbill", "billnum", new QFilter[]{
                new QFilter("periodstartdate", QCP.large_equals, periodStartDate),
                new QFilter("periodenddate", QCP.less_than, periodEndDate),
//                new QFilter(FinanceBillConfirmConstant.NCKD_CB_CONFRMID, QFilter.equals, 0)
//                        .or(QFilter.isNull(FinanceBillConfirmConstant.NCKD_CB_CONFRMID)),
                new QFilter("operationtype", QFilter.in, Arrays.asList("2","4")),
        });
        if(CollectionUtils.isEmpty(checkingBillCol)){
            return;
        }
        List<String> billNumList = checkingBillCol.stream().map(r -> r.getString("billnum")).collect(Collectors.toList());

        DynamicObjectCollection trainTgEntryCol = QueryServiceHelper.query("er_planecheckingbill",
                "id,oabillnum,sourcebookedid.id applierId,totalamount,orderstatus,ordertype,ordernum,happenddate," +
                        "ticketprice,refundamount,endorsementamount,discount", new QFilter[]{
                        new QFilter("checkingbillnum", QCP.in, billNumList)
                });
        // 通过火车订单过滤出超标的订单
        List<String> parentOrderList = trainTgEntryCol.stream().map(r -> r.getString("ordernum")).collect(Collectors.toList());
        Map<String, DynamicObject> orderOverDescMap = QueryServiceHelper.query("er_planebill", "ordernum,overdesc,standprice", new QFilter[]{
                        new QFilter("ordernum", QCP.in, parentOrderList)
                }).stream()
                .collect(Collectors.toMap(r -> r.getString("ordernum"), r -> r));
        for(DynamicObject trainTgEntry : trainTgEntryCol){
            // 机票超标的或者折扣额度大于60%
            BigDecimal discount = Optional.ofNullable(trainTgEntry.getBigDecimal("discount")).orElse(BigDecimal.ZERO);
            // 额度超标
            Boolean isOverDiscount = discount.compareTo(new BigDecimal(60)) > 0?true:false;

            if(orderOverDescMap.containsKey(trainTgEntry.getString("ordernum"))){

                DynamicObject planOrderInfo = orderOverDescMap.get(trainTgEntry.getString("ordernum"));

                if(StringUtils.isEmpty(planOrderInfo.getString("overdesc")) || !isOverDiscount){
                    continue;
                }

                DynamicObject tgEntry = tgEntryCol.addNew();

                long applierId = trainTgEntry.getLong("applierId");
                // 机票价格
                BigDecimal ticketPrice = Optional.ofNullable(trainTgEntry.getBigDecimal("ticketprice")).orElse(BigDecimal.ZERO);

                BigDecimal standPrice = Optional.ofNullable(planOrderInfo.getBigDecimal("standprice")).orElse(BigDecimal.ZERO);

                DynamicObject applierInfo = BusinessDataServiceHelper.loadSingleFromCache(applierId, "bos_user");
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_TRAVELER, applierInfo);
                createApplierInfo(tgEntry,applierInfo);
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_TRIPREQBILLNO, trainTgEntry.getString("oabillnum"));
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_ORDERBILLNO, trainTgEntry.getString("ordernum"));
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_ORDERAMT, ticketPrice);
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_TYPE, "air");
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_STANDARD, BigDecimal.ZERO);

                if(isOverDiscount){
                    // 机票价格-标准价格*0.6
                    tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_EXCSTAMT, ticketPrice.subtract(standPrice.multiply(new BigDecimal(0.6))));
                }
                String standardInfo = "";
                // 通过员工的岗位，查询对应的报销级别
                DynamicObject reimLeverSettingInfo = QueryServiceHelper.queryOne("er_reimbursesetting_rel", "reimburselevel.id", new QFilter("user", QCP.equals, applierInfo.getLong("id")).toArray());
                if(reimLeverSettingInfo != null && reimLeverSettingInfo.getLong("reimburselevel.id") != 0L){
                    // 通过差旅报销级别，查询对应的报销标准
                    DynamicObject tripStandard = BusinessDataServiceHelper.loadSingle("er_tripstandard_vehicle","seats",new QFilter[]{
                            new QFilter("reimburselevel.fbasedataid.id", QCP.equals, reimLeverSettingInfo.getLong("reimburselevel.id")),
                            new QFilter("standardtype", QCP.equals, "air")
                    });
                    if(tripStandard != null){
                        standardInfo = tripStandard.getDynamicObjectCollection("seats")
                                .stream()
                                .map(r -> r.getDynamicObject("fbasedataid").getString("name"))
                                .collect(Collectors.joining(";"));
                    }
                }
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_STANDARD_INFO, discount.toPlainString());
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_OVERREASON, planOrderInfo.getString("overdesc"));
            }
        }
//        List<Long> updateIdList = checkingBillCol.stream().map(r -> r.getLong("id")).collect(Collectors.toList());
//        DynamicObject[] updateBillArray = BusinessDataServiceHelper.load("er_checkingbill", FinanceBillConfirmConstant.NCKD_CB_CONFRMID, new QFilter("id", QCP.in, updateIdList).toArray());
//        for(DynamicObject updateBill : updateBillArray){
//            updateBill.set(FinanceBillConfirmConstant.NCKD_CB_CONFRMID, confirmBillId);
//        }
//        SaveServiceHelper.save(updateBillArray);
    }

    protected void createCbEntryHotel(Long confirmBillId , DynamicObjectCollection tgEntryCol){

        DynamicObjectCollection checkingBillCol = QueryServiceHelper.query("er_checkingbill", "billnum", new QFilter[]{
                new QFilter("periodstartdate", QCP.large_equals, periodStartDate),
                new QFilter("periodenddate", QCP.less_than, periodEndDate),
//                new QFilter(FinanceBillConfirmConstant.NCKD_CB_CONFRMID, QFilter.equals, 0)
//                        .or(QFilter.isNull(FinanceBillConfirmConstant.NCKD_CB_CONFRMID)),
                new QFilter("operationtype", QFilter.in, Arrays.asList("1","5")),
        });
        if(CollectionUtils.isEmpty(checkingBillCol)){
            return;
        }

        List<String> billNumList = checkingBillCol.stream().map(r -> r.getString("billnum")).collect(Collectors.toList());
        DynamicObjectCollection trainTgEntryCol = QueryServiceHelper.query("er_hotelcheckingbill",
                "id,oabillnum,server,sourcebookedid.id applierId,totalamount,orderstatus,ordertype,ordernum,happenddate" +
                        ",unbookfee,checkindate,hotelname,cityname", new QFilter[]{
                        new QFilter("checkingbillnum", QCP.in, billNumList)
                });
        // 通过火车订单过滤出超标的订单
        List<String> parentOrderList = trainTgEntryCol.stream().map(r -> r.getString("ordernum")).collect(Collectors.toList());
        Map<String, String> orderOverDescMap = QueryServiceHelper.query("er_hotelbill", "ordernum,overdesc", new QFilter[]{
                        new QFilter("ordernum", QCP.in, parentOrderList),
                        QFilter.isNotNull("overdesc")
                }).stream()
                .filter(r -> StringUtils.isNotEmpty(r.getString("overdesc")))
                .collect(Collectors.toMap(r -> r.getString("ordernum"), r -> r.getString("overdesc")));
        for(DynamicObject trainTgEntry : trainTgEntryCol){
            if(orderOverDescMap.containsKey(trainTgEntry.getString("ordernum"))){
                DynamicObject tgEntry = tgEntryCol.addNew();

                long applierId = trainTgEntry.getLong("applierId");
                DynamicObject applierInfo = BusinessDataServiceHelper.loadSingleFromCache(applierId, "bos_user");
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_TRAVELER, applierInfo);
                createApplierInfo(tgEntry,applierInfo);
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_TRIPREQBILLNO, trainTgEntry.getString("oabillnum"));
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_ORDERBILLNO, trainTgEntry.getString("ordernum"));
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_ORDERAMT, trainTgEntry.getBigDecimal("totalamount"));
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_TYPE, "hotal");
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_STANDARD, BigDecimal.ZERO);
                // 通过员工的岗位，查询对应的报销级别
                DynamicObject reimLeverSettingInfo = QueryServiceHelper.queryOne("er_reimbursesetting_rel", "reimburselevel.id", new QFilter("user", QCP.equals, applierInfo.getLong("id")).toArray());
                if(reimLeverSettingInfo != null && reimLeverSettingInfo.getLong("reimburselevel.id") != 0L){
                    // 通过差旅报销级别，查询报销标准金额
                    String cityName = trainTgEntry.getString("cityname");
                    tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_CITYNAME, cityName);
                    // 查询行政区划
                    DynamicObject cityInfo = QueryServiceHelper.queryOne("bd_admindivision", "id", new QFilter("name", QCP.like, cityName + "%").toArray());
                    if(cityInfo != null){
                        // 查询出差地域
                        DynamicObject tripArea = QueryServiceHelper.queryOne("er_triparea", "id", new QFilter("citysf7.fbasedataid", QCP.equals, cityInfo.getLong("id")).toArray());
                        if(tripArea != null){
                            // 住宿补助标准
                            DynamicObject hotelStandard = QueryServiceHelper.queryOne("er_tripstand_accmodation", "entryentity.standardamount", new QFilter[]{
                                    new QFilter("reimburselevel.fbasedataid", QCP.equals, reimLeverSettingInfo.getLong("reimburselevel.id")),
                                    new QFilter("entryentity.triparea", QCP.equals, tripArea.getLong("id")),
                                    new QFilter("entryentity.tripstandardtype.number", QCP.equals, "002"),
                            });
                            if(hotelStandard != null){
                                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_STANDARD, hotelStandard.getBigDecimal("entryentity.standardamount"));
                            }
                        }

                    }

                }
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_STANDARD_INFO, trainTgEntry.getString("hotelname"));
                tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_OVERREASON, orderOverDescMap.get(trainTgEntry.getString("ordernum")));
            }
        }
//        List<Long> updateIdList = checkingBillCol.stream().map(r -> r.getLong("id")).collect(Collectors.toList());
//        DynamicObject[] updateBillArray = BusinessDataServiceHelper.load("er_checkingbill", FinanceBillConfirmConstant.NCKD_CB_CONFRMID, new QFilter("id", QCP.in, updateIdList).toArray());
//        for(DynamicObject updateBill : updateBillArray){
//            updateBill.set(FinanceBillConfirmConstant.NCKD_CB_CONFRMID, confirmBillId);
//        }
//        SaveServiceHelper.save(updateBillArray);
    }

    protected void createCbEntryVehicle(Long confirmBillId , DynamicObjectCollection tgEntryCol){

        DynamicObjectCollection checkingBillCol = QueryServiceHelper.query("er_checkingbill", "billnum", new QFilter[]{
                new QFilter("periodstartdate", QCP.large_equals, periodStartDate),
                new QFilter("periodenddate", QCP.less_than, periodEndDate),
//                new QFilter(FinanceBillConfirmConstant.NCKD_CB_CONFRMID, QFilter.equals, 0)
//                        .or(QFilter.isNull(FinanceBillConfirmConstant.NCKD_CB_CONFRMID)),
                new QFilter("operationtype", QFilter.equals, "3"),
        });
        if(CollectionUtils.isEmpty(checkingBillCol)){
            return;
        }

        List<String> billNumList = checkingBillCol.stream().map(r -> r.getString("billnum")).collect(Collectors.toList());
        DynamicObjectCollection trainTgEntryCol = QueryServiceHelper.query("er_vehiclecheckingbill",
                "id,oabillnum,sourcebookedid.id applierId,totalamount,orderstatus,ordertype,ordernum,happenddate", new QFilter[]{
                        new QFilter("checkingbillnum", QCP.in, billNumList)
                });
        for(DynamicObject trainTgEntry : trainTgEntryCol){
            long applierId = trainTgEntry.getLong("applierId");
            DynamicObject applierInfo = BusinessDataServiceHelper.loadSingleFromCache(applierId, "bos_user");
            BigDecimal orderPrice = Optional.ofNullable(trainTgEntry.getBigDecimal("totalamount")).orElse(BigDecimal.ZERO);

            BigDecimal standardAmount = null;
            // 通过员工的岗位，查询对应的报销级别
            DynamicObject jobLeverInfo = QueryServiceHelper.queryOne(BillTypeConstants.HRPI_EMPJOBREL, "joblevel.id", new QFilter[]{
                    new QFilter("businessstatus", QCP.equals, "1"),
                    new QFilter("datastatus", QCP.equals, "1"),
                    new QFilter("iscurrentversion", QCP.equals, "1"),
                    new QFilter("person.number", QCP.equals, applierInfo.getString("number"))
            });
            if(jobLeverInfo != null){
                DynamicObject checkStandard = QueryServiceHelper.queryOne("nckd_checkstandard", "nckd_amount", new QFilter[]{
                        new QFilter("nckd_type", QCP.equals, "001"),
                        new QFilter("nckd_multi_joblever.fbasedataid", QCP.equals, jobLeverInfo.getLong("joblevel.id"))
                });
                if(checkStandard != null){
                    standardAmount = checkStandard.getBigDecimal("nckd_amount");
                }
            }
            BigDecimal cbAmount = BigDecimal.ZERO;
            Boolean isOver = false;
            if(standardAmount != null){
                cbAmount = orderPrice.subtract(standardAmount);
                if(cbAmount.compareTo(BigDecimal.ZERO) > 0){
                    // 超标金额没有大于0，则没有超标
                    isOver = true;
                }
            }

            if(!isOver){
                continue;
            }
            DynamicObject tgEntry = tgEntryCol.addNew();
            tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_STANDARD, standardAmount);
            tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_EXCSTAMT, cbAmount);

            tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_TRAVELER, applierInfo);
            createApplierInfo(tgEntry,applierInfo);
            tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_TRIPREQBILLNO, trainTgEntry.getString("oabillnum"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_ORDERBILLNO, trainTgEntry.getString("ordernum"));
            tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_ORDERAMT, orderPrice);
            tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_TYPE, "taxi");
            tgEntry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_STANDARD, BigDecimal.ZERO);

        }
//        List<Long> updateIdList = checkingBillCol.stream().map(r -> r.getLong("id")).collect(Collectors.toList());
//        DynamicObject[] updateBillArray = BusinessDataServiceHelper.load("er_checkingbill", FinanceBillConfirmConstant.NCKD_CB_CONFRMID, new QFilter("id", QCP.in, updateIdList).toArray());
//        for(DynamicObject updateBill : updateBillArray){
//            updateBill.set(FinanceBillConfirmConstant.NCKD_CB_CONFRMID, confirmBillId);
//        }
//        SaveServiceHelper.save(updateBillArray);
    }
    protected void createYcEntry(DynamicObject financeConfirmInfo) {

        DynamicObjectCollection ycEntryCol = financeConfirmInfo.getDynamicObjectCollection(FinanceBillConfirmConstant.NCKD_YC_ENTRY.ENTITYID);
        ycEntryCol.clear();
        long confirmBillId = financeConfirmInfo.getLong("id");

        DynamicObjectCollection checkingBillCol = QueryServiceHelper.query("er_checkingbill", "billnum", new QFilter[]{
                new QFilter("periodstartdate", QCP.large_equals, periodStartDate),
                new QFilter("periodenddate", QCP.less_than, periodEndDate),
//                new QFilter(FinanceBillConfirmConstant.NCKD_YC_CONFRMID, QFilter.equals, 0)
//                        .or(QFilter.isNull(FinanceBillConfirmConstant.NCKD_YC_CONFRMID)),
                new QFilter("operationtype", QFilter.equals, "3"),
        });
        if(CollectionUtils.isEmpty(checkingBillCol)){
            return;
        }
        List<String> billNumList = checkingBillCol.stream().map(r -> r.getString("billnum")).collect(Collectors.toList());
        // 查询用车结算单
        DynamicObjectCollection vehicleCheckCol = QueryServiceHelper.query("er_vehiclecheckingbill",
                "id,oabillnum,server,sourcebookedid.id applierId,totalamount,vehicletype", new QFilter[]{
                new QFilter("checkingbillnum", QCP.in, billNumList)
        });
        if(CollectionUtils.isEmpty(vehicleCheckCol)){
            return;
        }

        Map<String, List<DynamicObject>> applierGroupList = vehicleCheckCol.stream()
                .collect(Collectors.groupingBy(r -> r.getLong("applierId") + "_" + r.getString("vehicletype")));
        for (Map.Entry<String, List<DynamicObject>> applierRow : applierGroupList.entrySet()) {
            String applierId = applierRow.getKey().split("_")[0];
            String vehicletype = applierRow.getKey().split("_")[1];
            List<DynamicObject> dataList = applierRow.getValue();
            DynamicObject ycEntry = ycEntryCol.addNew();
            DynamicObject applierInfo = BusinessDataServiceHelper.loadSingleFromCache(Long.valueOf(applierId), "bos_user");
            ycEntry.set(FinanceBillConfirmConstant.NCKD_YC_ENTRY.NCKD_YC_TRAVELER, applierInfo);
            createApplierInfo(ycEntry,applierInfo);
            BigDecimal totalAmount = dataList.stream()
                    .map(r -> r.getBigDecimal("totalamount")).reduce(BigDecimal.ZERO, BigDecimal::add);
            ycEntry.set(FinanceBillConfirmConstant.NCKD_YC_ENTRY.NCKD_YC_AMOUNT, totalAmount);
            ycEntry.set("nckd_yc_vehicletype", vehicletype);
        }

//        List<Long> vehicleBillIdList = checkingBillCol.stream().map(r -> r.getLong("id")).collect(Collectors.toList());
//        DynamicObject[] vehicleCheckBillArray = BusinessDataServiceHelper.load("er_checkingbill", FinanceBillConfirmConstant.NCKD_YC_CONFRMID, new QFilter("id", QCP.in, vehicleBillIdList).toArray());
//        for(DynamicObject vehicleCheckBill : vehicleCheckBillArray){
//            vehicleCheckBill.set(FinanceBillConfirmConstant.NCKD_YC_CONFRMID, confirmBillId);
//        }
//        SaveServiceHelper.save(vehicleCheckBillArray);
    }

    protected void createSlEntry(DynamicObject financeConfirmInfo) {

        DynamicObjectCollection checkingBillCol = QueryServiceHelper.query("er_checkingbill", "billnum", new QFilter[]{
                new QFilter("periodstartdate", QCP.large_equals, periodStartDate),
                new QFilter("periodenddate", QCP.less_than, periodEndDate),
//                new QFilter(FinanceBillConfirmConstant.NCKD_SL_CONFRMID, QFilter.equals, 0)
//                        .or(QFilter.isNull(FinanceBillConfirmConstant.NCKD_SL_CONFRMID)),
                new QFilter("operationtype", QFilter.in, Arrays.asList("1","2","4","5","6")),
        });
        if(CollectionUtils.isEmpty(checkingBillCol)){
            return;
        }
        List<String> billNumList = checkingBillCol.stream().map(r -> r.getString("billnum")).collect(Collectors.toList());
        DynamicObjectCollection slOrderDataCol = QueryServiceHelper.query("er_allcheckingbill",
                "id,oabillnum,server,sourcebookedid.id applierId,totalamount,operationtype,ordernum", new QFilter[]{
                new QFilter("checkingbillnum", QCP.in, billNumList)
        });


        long confirmBillId = financeConfirmInfo.getLong("id");
        DynamicObjectCollection slEntryCol = financeConfirmInfo.getDynamicObjectCollection(FinanceBillConfirmConstant.NCKD_SL_ENTRY.ENTITYID);
        slEntryCol.clear();
        // 按照出差人分组汇总
        Map<Long, List<DynamicObject>> applierGroupMap = slOrderDataCol.stream().collect(Collectors.groupingBy(r -> r.getLong("applierId")));
        for (Map.Entry<Long, List<DynamicObject>> applierRow : applierGroupMap.entrySet()) {
            Long applierId = applierRow.getKey();
            List<DynamicObject> dataList = applierRow.getValue();
            DynamicObject slEntry = slEntryCol.addNew();
            DynamicObject applierInfo = BusinessDataServiceHelper.loadSingleFromCache(applierId, "bos_user");
            slEntry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_TRAVELER, applierInfo);
            createApplierInfo(slEntry,applierInfo);
            // 服务商已经和实施沟通，取第一个就行，按理只会出现同城
            slEntry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_SERVER,dataList.get(0).getString("server"));
            // 对火车订单金额合计
            List<String> trainNoList = dataList.stream()
                    .filter(r -> "6".equals(r.getString("operationtype")))
                    .map(r -> r.getString("ordernum")).collect(Collectors.toList());
            DynamicObjectCollection trainCheckingCol = QueryServiceHelper.query("er_traincheckingbill", "id,servicefee,ticketprice", new QFilter[]{
                    new QFilter("ordernum", QCP.in, trainNoList)
            });
            BigDecimal trainServiceAmount = trainCheckingCol
                    .stream().map(r -> r.getBigDecimal("servicefee")).reduce(BigDecimal.ZERO, BigDecimal::add);
            slEntry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_TRAINSERVICEFEE, trainServiceAmount);

            BigDecimal trainTotalAmount = dataList.stream()
                    .filter(r -> "6".equals(r.getString("operationtype")))
                    .map(r -> r.getBigDecimal("totalamount")).reduce(BigDecimal.ZERO, BigDecimal::add);
            slEntry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_TRAINPAYAMT, trainTotalAmount);
            // 对机票订单金额合计
            List<String> planNoList = dataList.stream()
                    .filter(r -> "2".equals(r.getString("operationtype")) || "4".equals(r.getString("operationtype")))
                    .map(r -> r.getString("ordernum")).collect(Collectors.toList());
            BigDecimal planeServiceAmount = QueryServiceHelper.query("er_planecheckingbill", "id,servicefee", new QFilter[]{
                    new QFilter("ordernum", QCP.in, planNoList)
            }).stream().map(r -> r.getBigDecimal("servicefee")).reduce(BigDecimal.ZERO, BigDecimal::add);
            slEntry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_PLANSERVICEFEE, planeServiceAmount);

            BigDecimal planeTotalAmount = dataList.stream()
                    .filter(r -> "2".equals(r.getString("operationtype")) || "4".equals(r.getString("operationtype")))
                    .map(r -> r.getBigDecimal("totalamount")).reduce(BigDecimal.ZERO, BigDecimal::add);
            slEntry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_PLANPAYAMT, planeTotalAmount);
            // 对酒店订单金额合计
            List<String> hotelNoList = dataList.stream()
                    .filter(r ->"1".equals(r.getString("operationtype")) || "5".equals(r.getString("operationtype")))
                    .map(r -> r.getString("ordernum")).collect(Collectors.toList());
            BigDecimal hotelServiceAmount = QueryServiceHelper.query("er_hotelcheckingbill", "id,servicefee", new QFilter[]{
                    new QFilter("ordernum", QCP.in, hotelNoList)
            }).stream().map(r -> r.getBigDecimal("servicefee")).reduce(BigDecimal.ZERO, BigDecimal::add);
            slEntry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_HOTELSERVICEFEEJD, hotelServiceAmount);

            BigDecimal hotelTotalAmount = dataList.stream()
                    .filter(r ->"1".equals(r.getString("operationtype")) || "5".equals(r.getString("operationtype")))
                    .map(r -> r.getBigDecimal("totalamount")).reduce(BigDecimal.ZERO, BigDecimal::add);
            slEntry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_HOTELPAYAMT, hotelTotalAmount);
            slEntry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_ORDERAMT, trainTotalAmount.add(planeTotalAmount).add(hotelTotalAmount));

        }
//        List<Long> allBillIdList = checkingBillCol.stream().map(r -> r.getLong("id")).collect(Collectors.toList());
//        DynamicObject[] allCheckBillArray = BusinessDataServiceHelper.load("er_checkingbill", FinanceBillConfirmConstant.NCKD_SL_CONFRMID, new QFilter("id", QCP.in, allBillIdList).toArray());
//        for(DynamicObject allCheckBill : allCheckBillArray){
//            allCheckBill.set(FinanceBillConfirmConstant.NCKD_SL_CONFRMID, confirmBillId);
//        }
//        SaveServiceHelper.save(allCheckBillArray);
    }
    protected DynamicObjectCollection getSlOrderDataCol(){

        // 查询火车订单
        DataSet trainCheckDataSet = QueryServiceHelper.queryDataSet(this.getClass().getName(), "er_traincheckingbill", "'er_traincheckingbill' type,id,oabillnum,server,sourcebookedid.id applierId,totalamount", new QFilter[]{
                new QFilter("happenddate", QCP.less_equals, new Date()),
                new QFilter(FinanceBillConfirmConstant.NCKD_SL_CONFRMID, QFilter.equals, 0),
        }, "");

        // 查询机票订单
        DataSet planeCheckDataSet = QueryServiceHelper.queryDataSet(this.getClass().getName(), "er_planecheckingbill", "'er_planecheckingbill' type,id,oabillnum,server,sourcebookedid.id applierId,totalamount", new QFilter[]{
                new QFilter("happenddate", QCP.less_equals, new Date()),
                new QFilter(FinanceBillConfirmConstant.NCKD_SL_CONFRMID, QFilter.equals, 0),
        }, "");

        // 查询酒店订单
        DataSet hotelCheckDataSet = QueryServiceHelper.queryDataSet(this.getClass().getName(), "er_hotelcheckingbill", "'er_hotelcheckingbill' type,id,oabillnum,server,sourcebookedid.id applierId,totalamount", new QFilter[]{
                new QFilter("happenddate", QCP.less_equals, new Date()),
                new QFilter(FinanceBillConfirmConstant.NCKD_SL_CONFRMID, QFilter.equals, 0),
        }, "");
        DataSet sumDataSet = CommonUtils.joinDataSetList(Arrays.asList(trainCheckDataSet, planeCheckDataSet, hotelCheckDataSet));
        return ORM.create().toPlainDynamicObjectCollection(sumDataSet);
    }



    protected void createBzEntry(DynamicObject financeConfirmInfo){
        long confirmBillId = financeConfirmInfo.getLong(FinanceBillConfirmConstant.ID);
        // 查询出差申请单
        DynamicObjectCollection tripReqBillCol = QueryServiceHelper.query(TripReqBillConstant.ENTITYID, String.join(",",TripReqBillConstant.ID,TripReqBillConstant.BILLNO), new QFilter[]{
                // 状态为审核通过、已付款、关闭
                new QFilter(TripReqBillConstant.KEY_BILLSTATUS, QFilter.in, Arrays.asList("E", "G", "I")),
                new QFilter(FinanceBillConfirmConstant.NCKD_BZ_CONFRMID, QFilter.equals, 0L)
                        .or(QFilter.isNull(FinanceBillConfirmConstant.NCKD_BZ_CONFRMID)),
                new QFilter(FinanceBillConfirmConstant.NCKD_SUP_CHECKID, QFilter.equals, 0L)
                        .or(QFilter.isNull(FinanceBillConfirmConstant.NCKD_SUP_CHECKID)),
                new QFilter(TripReqBillConstant.RENDDATE, QFilter.less_than, periodEndDate),
        },"createtime desc" );
        if(tripReqBillCol == null || tripReqBillCol.size() == 0){
            return ;
        }
        List<Object> tripReqBillIdList = tripReqBillCol.stream().map(r -> r.get(TripReqBillConstant.ID)).collect(Collectors.toList());
        // 创建财务对账底稿
        createTravelFinanDraft(financeConfirmInfo,tripReqBillIdList);
        DynamicObjectCollection bzEntryCol = financeConfirmInfo.getDynamicObjectCollection(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.ENTITYID);
        // 查询关联的商旅补助底稿数据
        List<Long> draftBillIdList = QueryServiceHelper.query(TravelFinanDraftConstant.ENTITYID, TravelFinanDraftConstant.ID,
                        new QFilter(FinanceBillConfirmConstant.NCKD_BZ_CONFRMID, QCP.equals, confirmBillId)
                                .and(new QFilter(TravelFinanDraftConstant.NCKD_SUMDAYS,QCP.large_than,0)).toArray())
                .stream().map(r -> r.getLong(TravelFinanDraftConstant.ID)).collect(Collectors.toList());
        // 创建商旅对账确认补助
        createCheckBzEntry(bzEntryCol,draftBillIdList);
    }

    protected void createCheckBzEntry(DynamicObjectCollection bzEntryCol,List<Long> draftBillIdList){
        DynamicObject[] draftBillArray = BusinessDataServiceHelper.load(draftBillIdList.toArray(), EntityMetadataCache.getDataEntityType(TravelFinanDraftConstant.ENTITYID_F7));

        // 按照出差人分组
        Map<Long, List<DynamicObject>> applyGroupMap = Arrays.stream(draftBillArray)
                .collect(Collectors.groupingBy(r -> r.getDynamicObject(TravelFinanDraftConstant.NCKD_TRIPREQBILL).getDynamicObject(TripReqBillConstant.APPLIER).getLong(TripReqBillConstant.ID)));

        for(Map.Entry<Long, List<DynamicObject>> applierRow : applyGroupMap.entrySet()){
            DynamicObject bzEntry = bzEntryCol.addNew();
            Long applierId = applierRow.getKey();
            List<DynamicObject> applierDraftList = applierRow.getValue();
            int sumDays = 0 ;
            BigDecimal sumAmount = BigDecimal.ZERO;
            for(DynamicObject draftEntry : applierDraftList){
                sumDays += draftEntry.getInt(TravelFinanDraftConstant.NCKD_SUMDAYS);
                sumAmount = sumAmount.add(draftEntry.getBigDecimal(TravelFinanDraftConstant.NCKD_AMOUNT));
            }
            DynamicObject applierInfo = BusinessDataServiceHelper.loadSingleFromCache(applierId, "bos_user");
            bzEntry.set(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.NCKD_BZ_TRAVELER, applierInfo);
            bzEntry.set(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.NCKD_BZ_TRAVELDAYS, sumDays);
            bzEntry.set(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.NCKD_BZ_SUMDAYS, sumDays);
            bzEntry.set(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.NCKD_BZ_AMOUNT, sumAmount);
            bzEntry.set(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.NCKD_BZ_CHECKAMT, sumAmount);
            // 设置出差人信息，工号、部门、岗位。 银行账户、开户行
            createApplierInfo(bzEntry,applierInfo);
        }
    }

    protected void createApplierInfo(DynamicObject entry , DynamicObject traveler){
        if(traveler != null) {
            String entryEntityName = entry.getDynamicObjectType().getName();
            // 获取员工信息
            DynamicObject userInfo = QueryServiceHelper.queryOne("bos_user", "number,entryentity.dpt,entryentity.orgstructure.fullname,entryentity.post.name",new QFilter[]{
                    new QFilter(FinanceBillConfirmConstant.ID, QCP.equals, traveler.getLong(FinanceBillConfirmConstant.ID)),
                    new QFilter("entryentity.ispartjob", QCP.equals, Boolean.FALSE),
            });
            long deptId = userInfo.getLong("entryentity.dpt");
            DynamicObject orgRelation = BusinessDataServiceHelper.loadSingle("bos_org_orgrelation_dept", "fromorg", new QFilter("toorg", QCP.equals, deptId).toArray());
            DynamicObject company = Objects.isNull(orgRelation)?null:orgRelation.getDynamicObject("fromorg");
            // 部门秘书设置
            DynamicObject deptSecretarySetting = getTravelDeptSecretary(traveler.getLong(FinanceBillConfirmConstant.ID), deptId);
            DynamicObject travelDeptSecretary = Optional.ofNullable(deptSecretarySetting).map(r -> r.getDynamicObject(DepSecretaryConstant.NCKD_SECRETARY)).orElse(null);

            DynamicObject secretaryUpAuditor = Optional.ofNullable(deptSecretarySetting).map(r -> r.getDynamicObject(DepSecretaryConstant.NCKD_UPAUDITOR)).orElse(null);

            DynamicObject legalPerson = BusinessDataServiceHelper.loadSingle("hrpi_empentrel","enterprise",new QFilter[]{
                    new QFilter("person.number", QCP.equals, userInfo.getString("number")),
                    new QFilter("businessstatus", QCP.equals, "1"),
                    new QFilter("iscurrentversion", QCP.equals, "1"),
                    new QFilter("datastatus", QCP.equals, "1"),
            });
            DynamicObject legalPersonEmpentrel = null;
            if(legalPerson != null){
                legalPersonEmpentrel = legalPerson.getDynamicObject("enterprise");
            }

            if (FinanceBillConfirmConstant.NCKD_BZ_ENTRY.ENTITYID.equals(entryEntityName)) {
                entry.set(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.NCKD_BZ_DEPFULLNAME, userInfo.getString("entryentity.orgstructure.fullname"));
                entry.set(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.NCKD_BZ_POST, userInfo.getString("entryentity.post.name"));
                entry.set(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.NCKD_BZ_COMPANY, company);
                entry.set(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.NCKD_BZ_LEGAL, legalPersonEmpentrel);

                entry.set(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.NCKD_BZ_DEPSECRETARY, travelDeptSecretary);
                entry.set(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.NCKD_BZ_USERLEADER, secretaryUpAuditor);
                // 收款信息通过薪酬发放设置hsas_paysetting中获取
                DynamicObject hrPaySetting = QueryServiceHelper.queryOne("hsas_paysetting", "entryentity.perbankcard.bankcardnum,entryentity.perbankcard.bankdeposit", new QFilter[]{
                        new QFilter("salaryfile.person.number", QCP.equals, traveler.getString("number")),
                        new QFilter("iscurrentversion", QCP.equals, "1"),
                        new QFilter("datastatus", QCP.equals, "1"),
                        new QFilter("entryentity.perbankcard.accountrelation.number", QCP.equals, "1010_S")
                });
                if (hrPaySetting != null) {
                    entry.set(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.NCKD_BZ_ACCOUNT, hrPaySetting.getString("entryentity.perbankcard.bankcardnum"));
                    entry.set(FinanceBillConfirmConstant.NCKD_BZ_ENTRY.NCKD_BZ_PAYERBANK, hrPaySetting.get("entryentity.perbankcard.bankdeposit"));
                }
            }
            if (FinanceBillConfirmConstant.NCKD_SL_ENTRY.ENTITYID.equals(entryEntityName)) {
                entry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_DEPFULLNAME, userInfo.getString("entryentity.orgstructure.fullname"));
                entry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_POST, userInfo.getString("entryentity.post.name"));
                entry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_COMPANY, company);
                entry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_LEGAL, legalPersonEmpentrel);
                entry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_DEPSECRETARY, travelDeptSecretary);
                entry.set(FinanceBillConfirmConstant.NCKD_SL_ENTRY.NCKD_SL_USERLEADER, secretaryUpAuditor);
            }

            if(FinanceBillConfirmConstant.NCKD_YC_ENTRY.ENTITYID.equals(entryEntityName)){
                entry.set(FinanceBillConfirmConstant.NCKD_YC_ENTRY.NCKD_YC_DEPFULLNAME, userInfo.getString("entryentity.orgstructure.fullname"));
                entry.set(FinanceBillConfirmConstant.NCKD_YC_ENTRY.NCKD_YC_POST, userInfo.getString("entryentity.post.name"));
                entry.set(FinanceBillConfirmConstant.NCKD_YC_ENTRY.NCKD_YC_COMPANY, company);
                entry.set(FinanceBillConfirmConstant.NCKD_YC_ENTRY.NCKD_YC_LEGAL, legalPersonEmpentrel);

                entry.set(FinanceBillConfirmConstant.NCKD_YC_ENTRY.NCKD_YC_DEPSECRETARY, travelDeptSecretary);
                entry.set(FinanceBillConfirmConstant.NCKD_YC_ENTRY.NCKD_YC_USERLEADER, secretaryUpAuditor);
            }
            if(FinanceBillConfirmConstant.NCKD_CB_ENTRY.ENTITYID.equals(entryEntityName)){
                entry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_DEPFULLNAME, userInfo.getString("entryentity.orgstructure.fullname"));
                entry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_POST, userInfo.getString("entryentity.post.name"));
                entry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_COMPANY, company);
                entry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_LEGAL, legalPersonEmpentrel);

                entry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_DEPSECRETARY, travelDeptSecretary);
                entry.set(FinanceBillConfirmConstant.NCKD_CB_ENTRY.NCKD_CB_USERLEADER, secretaryUpAuditor);
            }

            if(FinanceBillConfirmConstant.NCKD_TG_ENTRY.ENTITYID.equals(entryEntityName)){
                entry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_DEPFULLNAME, userInfo.getString("entryentity.orgstructure.fullname"));
                entry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_POST, userInfo.getString("entryentity.post.name"));
                entry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_DEPSECRETARY, travelDeptSecretary);
                entry.set(FinanceBillConfirmConstant.NCKD_TG_ENTRY.NCKD_TG_USERLEADER, secretaryUpAuditor);
            }

            if(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.ENTITYID.equals(entryEntityName)){
                entry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_DEPFULLNAME, userInfo.getString("entryentity.orgstructure.fullname"));
                entry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_POST, userInfo.getString("entryentity.post.name"));
                entry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_DEPSECRETARY, travelDeptSecretary);
                entry.set(FinanceBillConfirmConstant.NCKD_ZS_ENTRY.NCKD_ZS_USERLEADER, secretaryUpAuditor);
            }
        }
    }

    /**
     * 创建财务对账底稿单据
     * @param financeConfirmInfo 来源商旅对账确认单ID
     * @param tripReqBillIdList 出差申请单ID
     */
    protected void createTravelFinanDraft(DynamicObject financeConfirmInfo, List<Object> tripReqBillIdList) {
        long confirmBillId = financeConfirmInfo.getLong(FinanceBillConfirmConstant.ID);
        // 创建商旅财务对账底稿
        DynamicObject[] tripReqBillArray = BusinessDataServiceHelper.load(tripReqBillIdList.toArray(), EntityMetadataCache.getDataEntityType(TripReqBillConstant.ENTITYID_F7));
        List<String> tripReqBillNumberList = Arrays.stream(tripReqBillArray).map(r -> r.getString(TripReqBillConstant.BILLNO)).collect(Collectors.toList());
        // 获取关联的火车订单
        Map<String, List<DynamicObject>> trainBillMap = QueryServiceHelper.query("er_trainbill", "oabillnum,ordernum,departtime,arrivetime,departcity,arrivecity,totalamount,orderstatus,ordertype",
                        new QFilter("oabillnum", QCP.in, tripReqBillNumberList).toArray())
                .stream()
                .collect(Collectors.groupingBy(r -> r.getString("oabillnum")));

        // 获取机票订单
        Map<String, List<DynamicObject>> planBillMap = QueryServiceHelper.query("er_planebill", "oabillnum,ordernum,takeofftime,landingtime,fromcityname,tocityname,totalamount,orderstatus,ordertype",
                        new QFilter("oabillnum", QCP.in, tripReqBillNumberList).toArray())
                .stream()
                .collect(Collectors.groupingBy(r -> r.getString("oabillnum")));

        // 获取机票订单
        Map<String, List<DynamicObject>> hotelBillMap = QueryServiceHelper.query("er_hotelbill", "oabillnum,ordernum,checkindate,checkoutdate,cityname,totalamount,orderstatus,ordertype",
                        new QFilter("oabillnum", QCP.in, tripReqBillNumberList).toArray())
                .stream()
                .collect(Collectors.groupingBy(r -> r.getString("oabillnum")));

        // 获取关联的差旅报销发票分录 -》 发票与费用明细分录 联查 行程信息分录 通过源单行程分录ID 联查出差申请
        Map<String, List<DynamicObject>> tripReimInvoiceData = getTripReimInvoiceData(tripReqBillNumberList);

        for(DynamicObject tripReqBill : tripReqBillArray){
            String billno = tripReqBill.getString(TripReqBillConstant.BILLNO);
            DynamicObject travelFinanDraftInfo = BusinessDataServiceHelper.newDynamicObject(TravelFinanDraftConstant.ENTITYID);
            travelFinanDraftInfo.set(FinanceBillConfirmConstant.NCKD_BZ_CONFRMID, confirmBillId);
            travelFinanDraftInfo.set(TravelFinanDraftConstant.NCKD_TRIPREQBILL, tripReqBill);
            travelFinanDraftInfo.set(TravelFinanDraftConstant.ORG, tripReqBill.get(TripReqBillConstant.COMPANY));
            travelFinanDraftInfo.set(TravelFinanDraftConstant.NCKD_DEPT, tripReqBill.get(TripReqBillConstant.ORG));
            travelFinanDraftInfo.set(TravelFinanDraftConstant.NCKD_CONFIRMSTATUS, "10");
            travelFinanDraftInfo.set(TravelFinanDraftConstant.KEY_BILLNO,tripReqBill.getString(TripReqBillConstant.BILLNO));

            BigDecimal bzAmount = CommonUtils.getBzAmount(tripReqBill.getDynamicObject(TripReqBillConstant.APPLIER));
            DynamicObjectCollection draftEntryCol = travelFinanDraftInfo.getDynamicObjectCollection(TravelFinanDraftConstant.NCKD_DETAILENTITY.ENTITYID);
            if(trainBillMap.containsKey(billno) && trainBillMap.get(billno) != null){
                List<DynamicObject> trainBillList = trainBillMap.get(billno);
                trainBillList.stream().forEach(trainBill -> getDraftData(draftEntryCol.addNew(),"6",trainBill.getString("ordernum"),
                        trainBill.getDate("departtime"),trainBill.getDate("arrivetime"),
                        trainBill.getString("departcity"),trainBill.getString("arrivecity"), trainBill.getBigDecimal("totalamount"),
                        trainBill.getString("orderstatus"),trainBill.getString("ordertype")));
            }
            if(planBillMap.containsKey(billno) && planBillMap.get(billno) != null){
                List<DynamicObject> planBillList = planBillMap.get(billno);
                planBillList.stream().forEach(planBill -> getDraftData(draftEntryCol.addNew(),"2",planBill.getString("ordernum"),
                        planBill.getDate("takeofftime"),planBill.getDate("landingtime"),
                        planBill.getString("fromcityname"),planBill.getString("tocityname"),planBill.getBigDecimal("totalamount"),
                        planBill.getString("orderstatus"),planBill.getString("ordertype")));
            }
            if(hotelBillMap.containsKey(billno) && hotelBillMap.get(billno) != null){
                List<DynamicObject> hotelBillList = hotelBillMap.get(billno);
                hotelBillList.stream().forEach(hotelBill -> getDraftData(draftEntryCol.addNew(),"1",hotelBill.getString("ordernum"),
                        hotelBill.getDate("checkindate"),hotelBill.getDate("checkoutdate"),
                        null,hotelBill.getString("cityname"),hotelBill.getBigDecimal("totalamount"),
                        hotelBill.getString("orderstatus"),hotelBill.getString("ordertype")));
            }
            if(tripReimInvoiceData.containsKey(billno) && tripReimInvoiceData.get(billno) != null){
                List<DynamicObject> tripReimInvoiceList = tripReimInvoiceData.get(billno);
                tripReimInvoiceList.stream().forEach(tripReimInvoice -> getDraftData(draftEntryCol.addNew(),"7",
                        String.join("-",tripReimInvoice.getString("tripBillno"),tripReimInvoice.getString("invoiceentry.invoiceno")),
                        tripReimInvoice.getDate("invoiceentry.carrierdate"),tripReimInvoice.getDate("invoiceentry.carrierdate"),
                        tripReimInvoice.getString("invoiceentry.istartcity"),tripReimInvoice.getString("invoiceentry.idestcity"),tripReimInvoice.getBigDecimal("invoiceentry.totalamount")));
            };

            // 获取draftEntryCol所有的开始时间和结束时间，在获取其中的最早时间和最晚时间
            List<Date> allDateList = new ArrayList<>();
            for(DynamicObject draftEntry : draftEntryCol){
                if("1".equals(draftEntry.getString(TravelFinanDraftConstant.NCKD_DETAILENTITY.NCKD_SOURCE))){
                    continue;
                }
                Date startDate = draftEntry.getDate(TravelFinanDraftConstant.NCKD_DETAILENTITY.NCKD_STARTDATE);
                Date endDate = draftEntry.getDate(TravelFinanDraftConstant.NCKD_DETAILENTITY.NCKD_FINISHDATE);
                if(startDate != null){
                    allDateList.add(startDate);
                }
                if(endDate != null){
                    allDateList.add(endDate);
                }
            }

            Date earliestTime = allDateList.stream()
                    .min(Comparator.comparing(Date::getTime)).orElse(null);
            Date latestTime = allDateList.stream()
                    .max(Comparator.comparing(Date::getTime)).orElse(null);
            //获取latestTime与earliestTime 的日期相差天数，加上1
            if(earliestTime != null && latestTime != null){
                int days = CommonUtils.getDaysByWorkCalandar(earliestTime, latestTime, tripReqBill.getDynamicObject(TripReqBillConstant.COMPANY));
                travelFinanDraftInfo.set(TravelFinanDraftConstant.NCKD_SUMDAYS, days);
                // 查询补助金额
                travelFinanDraftInfo.set(TravelFinanDraftConstant.NCKD_AMOUNT, bzAmount.multiply(BigDecimal.valueOf(days)));
            }
            tripReqBill.set(FinanceBillConfirmConstant.NCKD_BZ_CONFRMID, confirmBillId);
            // 分录为空的时候不创建底稿，但是更新
            SaveServiceHelper.save(new DynamicObject[]{ travelFinanDraftInfo });
            SaveServiceHelper.save(new DynamicObject[]{ tripReqBill });
        }
    }




    protected DynamicObject getDraftData( DynamicObject draftEntry , String source, String orderNum, Date startTime,
                                          Date endTime , String from , String to , BigDecimal amount){
        draftEntry.set(TravelFinanDraftConstant.NCKD_DETAILENTITY.NCKD_SOURCE, source);
        draftEntry.set(TravelFinanDraftConstant.NCKD_DETAILENTITY.NCKD_ORDER_NUMBER, orderNum);
        draftEntry.set(TravelFinanDraftConstant.NCKD_DETAILENTITY.NCKD_STARTDATE, startTime);
        draftEntry.set(TravelFinanDraftConstant.NCKD_DETAILENTITY.NCKD_FINISHDATE, endTime);
        draftEntry.set(TravelFinanDraftConstant.NCKD_DETAILENTITY.NCKD_FROM, from);
        draftEntry.set(TravelFinanDraftConstant.NCKD_DETAILENTITY.NCKD_TO, to);
        draftEntry.set(TravelFinanDraftConstant.NCKD_DETAILENTITY.NCKD_ORDER_AMOUNT, amount);
        return draftEntry;
    }

    protected DynamicObject getDraftData( DynamicObject draftEntry , String source, String orderNum, Date startTime,
                                          Date endTime , String from , String to , BigDecimal amount , String sourceStatus , String orderType){
        DynamicObject draftData = getDraftData(draftEntry, source, orderNum, startTime, endTime, from, to, amount);
        String sourceStatusValue = "";
        //国内火车
        if("6".equals(source)){
            switch (sourceStatus) {
                case "1":
                    sourceStatusValue = "已出票";
                    break;
                case "2":
                    sourceStatusValue = "已改签";
                    break;
                case "3":
                    sourceStatusValue = "已退票";
                    break;
                case "4":
                    sourceStatusValue = "出票失败";
                    break;
                case "5":
                    sourceStatusValue = "出票失败退款";
                    break;
                case "6":
                    sourceStatusValue = "改签中";
                    break;
                case "7":
                    sourceStatusValue = "退票中";
                    break;
                default:
                    sourceStatusValue = "未知";
                    break;
            }

            //国内机票
        }else if("2".equals(source)){
            switch (sourceStatus) {
                case "40000":
                    sourceStatusValue = "已出票";
                    break;
                case "50301":
                    sourceStatusValue = "改签中";
                    break;
                case "50302":
                    sourceStatusValue = "已改签";
                    break;
                case "50201":
                    sourceStatusValue = "退票中";
                    break;
                case "50202":
                    sourceStatusValue = "已退票";
                    break;
                case "10000":
                    sourceStatusValue = "已提交";
                    break;
                case "20000":
                    sourceStatusValue = "已预订";
                    break;
                case "40100":
                    sourceStatusValue = "出票中";
                    break;
                case "50203":
                    sourceStatusValue = "已部分出票";
                    break;
                case "55555":
                    sourceStatusValue = "改签失败";
                    break;
                case "55554":
                    sourceStatusValue = "改签已取消";
                    break;
                case "30000":
                    sourceStatusValue = "已取消";
                    break;
                default:
                    sourceStatusValue = "未知";
                    break;
            }

            //国内酒店
        }else if("1".equals(source)){
            switch (sourceStatus) {
                case "1":
                    sourceStatusValue = "待审批";
                    break;
                case "2":
                    sourceStatusValue = "待支付";
                    break;
                case "3":
                    sourceStatusValue = "待确认";
                    break;
                case "5":
                    sourceStatusValue = "已确认";
                    break;
                case "6":
                    sourceStatusValue = "满房";
                    break;
                case "7":
                    sourceStatusValue = "已离店";
                    break;
                case "8":
                    sourceStatusValue = "待退订";
                    break;
                case "10":
                    sourceStatusValue = "已退订";
                    break;
                case "14":
                    sourceStatusValue = "已取消";
                    break;
                default:
                    sourceStatusValue = "未知";
                    break;
            }
        }
        draftData.set(TravelFinanDraftConstant.NCKD_DETAILENTITY.NCKD_ORDERSTATUS, sourceStatusValue);
        draftData.set(TravelFinanDraftConstant.NCKD_DETAILENTITY.NCKD_ORDERTYPE, orderType);
        return draftEntry;
    }



    protected Map<String, List<DynamicObject>> getTripReimInvoiceData(List<String> tripReqBillNumberList){

        // 查询关联的行程分录ID
        DataSet queryTripReqEntryDataSet = QueryServiceHelper.queryDataSet(this.getClass().getName(), TripReqBillConstant.ENTITYID,
                "billno,tripentry.id", new QFilter("billno", QCP.in, tripReqBillNumberList).toArray(), "");
        Set tripEntryIdSet = CommonUtils.getFiledFromDataSet(queryTripReqEntryDataSet, "tripentry.id");
        // 通过行程分录ID 联查差旅报销行程
        // 差旅报销单行程分录ID -> 出差申请分录ID映射
        DataSet tripReimEntryDataSet = QueryServiceHelper.queryDataSet(this.getClass().getName(), BillTypeConstants.ER_TRIPREIMBURSEBILL, "tripentry.tripentrysourceid,tripentry.entryentity.id",
                new QFilter("tripentry.tripentrysourceid", QCP.in, tripEntryIdSet).toArray(), "");
        Set tripReimEntryIdSet = CommonUtils.getFiledFromDataSet(tripReimEntryDataSet, "tripentry.entryentity.id");

        // 获取行程信息分录下的发票信息
        DataSet queryReimInvoiceEntryDataSet = QueryServiceHelper.queryDataSet(this.getClass().getName(), BillTypeConstants.ER_TRIPREIMBURSEBILL, "invoiceitementry.itementryid,invoiceitementry.invoiceheadentryid",
                new QFilter("invoiceitementry.itementryid", QCP.in, tripReimEntryIdSet).toArray(), "");
        Set invoiceEntryIdSet = CommonUtils.getFiledFromDataSet(queryReimInvoiceEntryDataSet, "invoiceitementry.invoiceheadentryid");


        // 查询发票相关信息
        DataSet queryInvoiceEntryDataSet = QueryServiceHelper.queryDataSet(this.getClass().getName(), BillTypeConstants.ER_TRIPREIMBURSEBILL, "billno,invoiceentry.id,invoiceentry.invoiceno,invoiceentry.carrierdate,invoiceentry.istartcity,invoiceentry.idestcity,invoiceentry.totalamount",
                new QFilter("invoiceentry.id", QCP.in, invoiceEntryIdSet).toArray(), "");

        // 建议出差申请和发票明细的关联关系
        DataSet queryReimInvoiceDataSet = queryTripReqEntryDataSet.leftJoin(tripReimEntryDataSet)
                .on("tripentry.id", "tripentry.tripentrysourceid").select("billno", "tripentry.entryentity.id").finish()
                .leftJoin(queryReimInvoiceEntryDataSet)
                .on("tripentry.entryentity.id", "invoiceitementry.itementryid").select("billno", "invoiceitementry.invoiceheadentryid").finish()
                .leftJoin(queryInvoiceEntryDataSet)
                .on("invoiceitementry.invoiceheadentryid", "invoiceentry.id").select(new String[]{ "billno" }, new String[]{ "billno tripBillno","invoiceentry.invoiceno", "invoiceentry.carrierdate", "invoiceentry.istartcity","invoiceentry.idestcity", "invoiceentry.totalamount" }).finish();
        DynamicObjectCollection reimInvoiceCol = ORM.create().toPlainDynamicObjectCollection(queryReimInvoiceDataSet);
        return reimInvoiceCol.stream().filter(r -> !Objects.isNull(r.getString("invoiceentry.invoiceno"))).collect(Collectors.groupingBy(r -> r.getString("billno")));

    }

    /**
     * 获取出差人部门秘书
     * @param applierId
     * @param deptId
     * @return
     */
    protected DynamicObject getTravelDeptSecretary(Long applierId , Long deptId){
        // 优先从秘书特殊人员配置中取，如果没有特殊配置，则从部门秘书中取
        DynamicObject speSettingInfo = QueryServiceHelper.queryOne(SecretarySpeSettingConstant.ENTITYID,
                SecretarySpeSettingConstant.NCKD_ORG_CHECK, new QFilter(SecretarySpeSettingConstant.NCKD_USER, QCP.equals, applierId).toArray());
        Long checkOrg = 0L;
        if(speSettingInfo != null){
            checkOrg = speSettingInfo.getLong(SecretarySpeSettingConstant.NCKD_ORG_CHECK);
        }else{
            checkOrg = deptId;
        }
        // 查询部门秘书配置
        return BusinessDataServiceHelper.loadSingle(DepSecretaryConstant.ENTITYID, String.join(",", DepSecretaryConstant.NCKD_SECRETARY, DepSecretaryConstant.NCKD_UPAUDITOR),
                new QFilter(CommonUtils.join(DepSecretaryConstant.ENTITYID_ENTRY, DepSecretaryConstant.NCKD_ORG), QCP.equals, checkOrg).toArray());
    }
}
