Parcourir la source

fix:结算单查询接口(同步 火车结算单 酒店结算单 机票结算单)

sbtjtserver/gw-zhaojq01 il y a 3 semaines
Parent
commit
978f915a2e

+ 443 - 0
nckd-fi/src/main/java/nckd/fi/er/task/DomesticFlightSettlementTask.java

@@ -0,0 +1,443 @@
+package nckd.fi.er.task;
+
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.exception.KDBizException;
+import kd.bos.exception.KDException;
+import kd.bos.krpc.common.logger.Logger;
+import kd.bos.krpc.common.logger.LoggerFactory;
+import kd.bos.schedule.executor.AbstractTask;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import nckd.base.common.utils.DateUtil;
+import nckd.base.common.utils.ParamUtils;
+import nckd.base.common.utils.TripSyncUtils;
+import org.apache.commons.lang3.ObjectUtils;
+
+import java.util.*;
+
+/**
+ * Created with IntelliJ IDEA.
+ *
+ * @Author: 赵嘉琪
+ * @Date: 2025/12/19
+ * @Description:结算单(国内机票)
+ */
+public class DomesticFlightSettlementTask extends AbstractTask {
+    private static Logger log = LoggerFactory.getLogger(DomesticFlightSettlementTask.class);
+
+    /**
+     * 总页码,不处理总数,
+     * 每当当前页码数据小于1000 停止接口查询
+     */
+    private final static int totalPage = 1000;
+
+    /**
+     * 每页条数,最多500条   实际1000条
+     */
+    private final static int size = 1000;
+
+    @Override
+    public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
+        log.info("结算单(国内机票)查询接口 调度计划开始执行");
+        List<Map<String, Object>> resultLists = getResult();
+        if (ObjectUtils.isEmpty(resultLists)) {
+            log.info("结算单(国内机票)查询接口 暂无数据-----");
+            return;
+        }
+        for (Map<String, Object> resultMap : resultLists) {
+            try {
+                // 从结果映射中提取各字段
+                extractAndProcessFields(resultMap);
+            } catch (Exception e) {
+                log.info("处理火车票结算数据时发生异常,数据内容: " + resultMap, e);
+            }
+        }
+
+    }
+
+    /**
+     * 从单条数据映射中提取字段并处理
+     *
+     * @param resultMap 单条数据映射
+     */
+    private void extractAndProcessFields(Map<String, Object> resultMap) {
+        // 1.获取接口返回值
+
+        // ===================== 订单基本信息 =====================
+        // 订单类型 (01001机票正常单, 01002机票退单, 01003机票改签单, 1酒店正常单, 2酒店退单等)
+        Object orderType = resultMap.get("orderType");
+        // 房间数
+        Object roomQuantity = resultMap.get("roomQuantity");
+        // 订单类型名称
+        Object orderName = resultMap.get("orderName");
+        // 订单号
+        Object orderNo = resultMap.get("orderNo");
+        // 原订单编号
+        Object oldOrderNo = resultMap.get("oldOrderNo");
+        // 订单状态 (已完成等)
+        Object orderStatus = resultMap.get("orderStatus");
+        // 预订时间
+        Object orderDate = resultMap.get("orderDate");
+        // 业务发生时间
+        Object rebookingtime = resultMap.get("rebookingtime");
+        // 结算生成时间
+        Object createTime = resultMap.get("createTime");
+
+        // ===================== 结算信息 =====================
+        // 结算明细主键
+        Object tmcSettlementid = resultMap.get("tmcSettlementid");
+        // 结算单号
+        Object settlementNo = resultMap.get("settlementNo");
+        // 结算批次号(对应系统账单号)
+        Object accCheckBatchNo = resultMap.get("accCheckBatchNo");
+        // 结算明细ID
+        Object subAccCheckBatchNo = resultMap.get("subAccCheckBatchNo");
+        // 大表ID
+        Object mainTableId = resultMap.get("mainTableId");
+        // 币种 (例如CNY)
+        Object settlementCurrency = resultMap.get("settlementCurrency");
+        // 结算金额
+        Object settlementAmount = resultMap.get("settlementAmount");
+        // 结算单合计金额
+        Object totalAmount = resultMap.get("totalAmount");
+
+        // ===================== 人员信息 =====================
+        // 出行人姓名
+        Object guestName = resultMap.get("guestName");
+        // 出行人名称
+        Object passengerName = resultMap.get("passengerName");
+        // 员工姓名
+        Object employeeName = resultMap.get("employeeName");
+        // 出行人工号
+        Object employeeId = resultMap.get("employeeId");
+        // 预订人姓名
+        Object reserveName = resultMap.get("reserveName");
+        // 预订人员编号
+        Object reserveId = resultMap.get("reserveId");
+        // 人员类型(可能是员工类型)
+        Object personnelType = resultMap.get("personnelType");
+
+        // ===================== 财务信息 =====================
+        // 销售价
+        Object price = resultMap.get("price");
+        // 折扣
+        Object priceRate = resultMap.get("priceRate");
+        // 含税金额
+        Object inTaxAmount = resultMap.get("inTaxAmount");
+        // 不含税金额
+        Object excludingtaxAmount = resultMap.get("excludingtaxAmount");
+        // 不含税交易金额(不含税销售价)
+        Object sellingPriceNoTax = resultMap.get("sellingPriceNoTax");
+        // 订单不含税金额
+        Object orderNoTaxAmount = resultMap.get("orderNoTaxAmount");
+        // 订单税额
+        Object orderTax = resultMap.get("orderTax");
+        // 发票税率
+        Object taxRate = resultMap.get("taxRate");
+
+        // ===================== 费用信息 =====================
+        // 员工自付金额
+        Object personalPaymentAmount = resultMap.get("personalPaymentAmount");
+        // 欠款金额
+        Object amount = resultMap.get("amount");
+        Object priceAmount = resultMap.get("priceAmount");
+        // 垫款服务费
+        Object advancePaymentAmount = resultMap.get("advancePaymentAmount");
+        // 支付类型 (0自付、1垫付)
+        Object payType = resultMap.get("payType");
+        // TMC支付类型
+        Object tmcPaymentType = resultMap.get("tmcPaymentType");
+        // 账单类型 (M月结, S服务费)
+        Object billType = resultMap.get("billType");
+
+        // ===================== 服务费信息 =====================
+        // TMC服务费(服务商服务费)
+        Object spServiceFee = resultMap.get("spServiceFee");
+        // 服务费(销售服务费)
+        Object serviceFee = resultMap.get("serviceFee");
+        // 技术服务费
+        Object technologyServiceFee = resultMap.get("technologyServiceFee");
+        // 退票费
+        Object refund = resultMap.get("refund");
+        // 改签费
+        Object rebookQueryFee = resultMap.get("rebookQueryFee");
+
+        // ===================== 项目信息 =====================
+        // 项目编号
+        Object projectNo = resultMap.get("projectNo");
+        // 项目名称
+        Object projectName = resultMap.get("projectName");
+        // 业务类型编号
+        Object businessTypeNo = resultMap.get("businessTypeNo");
+        // 业务类型名称
+        Object businessTypeName = resultMap.get("businessTypeName");
+        // 费用类型编号
+        Object feeTypeNo = resultMap.get("feeTypeNo");
+        // 费用类型名称
+        Object feeTypeName = resultMap.get("feeTypeName");
+        // 差旅类型 (1因公, 0因私)
+        Object travelType = resultMap.get("travelType");
+        // 搜索类型名称(可能是查询条件类型)
+        Object searchTypeName = resultMap.get("searchTypeName");
+
+        // ===================== 供应商信息 =====================
+        // 供应商编号
+        Object supplierNo = resultMap.get("supplierNo");
+        // 供应商名称
+        Object supplierName = resultMap.get("supplierName");
+        // 供应单号
+        Object purchaseOrderNo = resultMap.get("purchaseOrderNo");
+        // 供应商发票类型 (0/空:普票, 1:专票)
+        Object supplierInvoiceType = resultMap.get("supplierInvoiceType");
+        // 垫款商户编号
+        Object advancePaymentMerchantNo = resultMap.get("advancePaymentMerchantNo");
+        // 垫款商户名称
+        Object advancePaymentMerchantName = resultMap.get("advancePaymentMerchantName");
+
+        // ===================== 法人信息 =====================
+        // 法人公司
+        Object frgs = resultMap.get("frgs");
+        // 法人公司名称
+        Object frgsmc = resultMap.get("frgsmc");
+
+        // ===================== 行程信息 =====================
+        // 国内国际标识 (1国内, 0国际)
+        Object international = resultMap.get("international");
+        // 所在城市/出发城市名称
+        Object cityName = resultMap.get("cityName");
+        // 到达城市
+        Object arrivalCity = resultMap.get("arrivalCity");
+        // 到达城市名称/酒店所在城市
+        Object arrivalCityName = resultMap.get("arrivalCityName");
+        // 入住日期/出发时间
+        Object startTime = resultMap.get("startTime");
+        // 离店日期/到达时间
+        Object endTime = resultMap.get("endTime");
+        // 出票时间
+        Object printTicketTime = resultMap.get("printTicketTime");
+
+        // ===================== 酒店信息 =====================
+        // 酒店名称
+        Object hotelName = resultMap.get("hotelName");
+        // 酒店星级
+        Object star = resultMap.get("star");
+        // 房型中文名称
+        Object roomName = resultMap.get("roomName");
+        // 间夜数
+        Object quantity = resultMap.get("quantity");
+
+        // ===================== 机票附加费 =====================
+        // 机票建设费
+        Object airportFee = resultMap.get("airportFee");
+        // 保险费
+        Object insuranceFee = resultMap.get("insuranceFee");
+
+        // ===================== 其他字段 =====================
+        // 销售价(重复字段,可根据实际情况处理)
+        Object transAmount = resultMap.get("transAmount");
+
+        // 2.机票结算单 --国内机票 创建新的动态对象
+        DynamicObject planeCheckingBill = BusinessDataServiceHelper.newDynamicObject("er_planecheckingbill");
+
+        // 3. 设置对应对象属性
+
+        //订单日期
+        planeCheckingBill.set("orderdate", orderType);
+        //订单性质
+        planeCheckingBill.set("isbusiness", travelType);
+        //结算类型 2 -个人现付
+        planeCheckingBill.set("producttype", "2");
+        //预订人工号
+        planeCheckingBill.set("booknum", "");
+        //预订人姓名
+        planeCheckingBill.set("bookedname", reserveName);
+        //结算发生日期
+        planeCheckingBill.set("happenddate", DateUtil.string2date((String) createTime,null));
+        //业务类型
+        planeCheckingBill.set("operationtype", businessTypeNo);
+        //订单分类
+        planeCheckingBill.set("ordersort", orderType);
+        //订单状态
+        planeCheckingBill.set("orderstatus", "5");
+        //结算金额
+        planeCheckingBill.set("totalamount", settlementAmount);
+        //币种
+        switch (settlementCurrency.toString()){
+            case "CNY":
+                planeCheckingBill.set("currency", "1");
+                break;
+            case "HKD":
+                planeCheckingBill.set("currency", "2");
+                break;
+            case "JPY":
+                planeCheckingBill.set("currency", "3");
+                break;
+            case "USD":
+                planeCheckingBill.set("currency", "4");
+                break;
+            case "EUR":
+                planeCheckingBill.set("currency", "5");
+                break;
+            case "GBP":
+                planeCheckingBill.set("currency", "6");
+                break;
+            case "AUD":
+                planeCheckingBill.set("currency", "7");
+                break;
+            case "TWD":
+                planeCheckingBill.set("currency", "8");
+                break;
+            case "MOP":
+                planeCheckingBill.set("currency", "9");
+                break;
+        }
+        //结算批次号
+        planeCheckingBill.set("batchno", accCheckBatchNo);
+        //结算子批次号
+        planeCheckingBill.set("subbatchno", "");
+        //费用承担公司
+        planeCheckingBill.set("settlemain", "");
+        //费用承担部门
+        planeCheckingBill.set("settledept", "");
+        //申请人公司
+        planeCheckingBill.set("company", "");
+        //申请人部门
+        planeCheckingBill.set("org", "");
+        //项目
+        planeCheckingBill.set("std_project", projectNo);
+        //成本中心
+        planeCheckingBill.set("std_costcenter", "");
+        //外部系统结算单号
+        planeCheckingBill.set("outsettlementnum", "");
+        //火车票车票号
+        planeCheckingBill.set("trainticketnum", "");
+        //出发城市
+        planeCheckingBill.set("departcity", "");
+        //出发车站
+        planeCheckingBill.set("departaddress", "");
+        //到达城市
+        planeCheckingBill.set("arrivecity", "");
+        //到达车站
+        planeCheckingBill.set("arriveaddress", "");
+        //出发时间
+        planeCheckingBill.set("departtime", "");
+        //到达时间
+        planeCheckingBill.set("arrivetime", "");
+        //乘客
+        planeCheckingBill.set("passeger", "");
+        //乘客姓名
+        planeCheckingBill.set("passegername", "");
+        //车次
+        planeCheckingBill.set("vendorname", "");
+        //席位
+        planeCheckingBill.set("trainseat", "");
+        //火车票价
+        planeCheckingBill.set("ticketprice", "");
+        //服务费
+        planeCheckingBill.set("servicefee", "");
+        //退票费
+        planeCheckingBill.set("refundamount", "");
+        //保险费
+        planeCheckingBill.set("assuranceamount", "");
+        //下载地址
+        planeCheckingBill.set("downloadlink", "");
+        //内部下载地址
+        planeCheckingBill.set("kddownloadlink", "");
+        //发票流水号
+        planeCheckingBill.set("serialno", "");
+        //发票识别异常信息
+        planeCheckingBill.set("identityerrormsg", "");
+        //票价开票类型
+        planeCheckingBill.set("pricebillingtype", "");
+
+        //控制信息
+//        ??????。。
+        //可抵扣税额
+        planeCheckingBill.set("totaltax", "");
+        //已开票
+        planeCheckingBill.set("hasinvoice", "");
+        //付款/付款申请单号
+        planeCheckingBill.set("paybillnum", "");
+        //付款状态
+        planeCheckingBill.set("paybillstatus", "");
+        //凭证号
+        planeCheckingBill.set("vouchernum", "");
+        //记账日期
+        planeCheckingBill.set("bookeddatereq", "");
+        //记账日期
+        planeCheckingBill.set("bookeddatebu", "");
+
+        // 4.保存对象
+        SaveServiceHelper.save(new DynamicObject[]{planeCheckingBill});
+    }
+
+    /**
+     * 从接口获取国内机票结算数据
+     *
+     * @return 国内机票结算数据列表
+     */
+    private List<Map<String, Object>> getResult() {
+        //获取开始同步时间
+        String syncTime = getSyncTime();
+        //当前时间
+        Date nowDate = new Date();
+        String nowDateString = DateUtil.date2str(nowDate, DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
+
+        log.info("结算单(国内机票) 同步开始时间:" + syncTime);
+
+        List<Map<String, Object>> dataList = new ArrayList<>();
+        for (int i = 0; i < totalPage; i++) {
+            //创建接口业务数据参数
+            Map<String, Object> data = new HashMap<>();
+            //结算时间始
+            data.put("dateFrom", syncTime);
+            //结算时间止
+            data.put("dateTo", nowDateString);
+            //产品类别 0100 国内机票
+            data.put("searchType", "0100");
+            //当前页
+            data.put("current", i + 1);
+            //每页条数,最多500条
+            data.put("size", size);
+            //企业卡号
+            data.put("enterpriseNo", "JXWL");
+            //账单类型 01-现结
+            data.put("settlementType", "01");
+
+            Map<String, Object> resp = TripSyncUtils.pushApiCallResult("FCSET_OUTAPI_LiteGetSettlementInfo", Boolean.FALSE, data);
+            //报错终止同步,等待下次计划执行
+            if ((Boolean) resp.get("fail")) {
+                throw new KDBizException(resp.get("message").toString());
+            }
+            Map<String, Object> result = (Map<String, Object>) resp.get("result");
+            List<Map<String, Object>> resultDataList = (List<Map<String, Object>>) result.getOrDefault("dataList", Collections.emptyList());
+            dataList.addAll(resultDataList);
+
+            //当前查询数量小于分页数量时结束循环
+            if (resultDataList.size() < size) {
+                break;
+            }
+        }
+        return dataList;
+    }
+
+    /**
+     * @return 获取同步开始时间
+     */
+    private String getSyncTime() {
+        //获取费用核算应用参数
+        Map<String, Object> sysCtrlParameter = ParamUtils.getSysCtrlParameter(ParamUtils.EM);
+        //是否全量同步
+        Boolean isAll = (Boolean) sysCtrlParameter.get("nckd_settlementbillall");
+        if (isAll) {
+            return "1970-01-01 00:00:00";
+        }
+        //增量同步小时  填写整数N,同步N小时前到现在新增或修改的数据,不填默认1小时。
+        int hours = ObjectUtils.isEmpty(sysCtrlParameter.get("nckd_settlementbillhour")) ? 1 : (Integer) sysCtrlParameter.get("nckd_settlementbillhour");
+        //同步N小时前
+        Date date = DateUtil.addHour(new Date(), -hours);
+
+        return DateUtil.date2str(date, DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
+    }
+}

+ 490 - 0
nckd-fi/src/main/java/nckd/fi/er/task/HotelSettlementTask.java

@@ -0,0 +1,490 @@
+package nckd.fi.er.task;
+
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.exception.KDBizException;
+import kd.bos.exception.KDException;
+import kd.bos.krpc.common.logger.Logger;
+import kd.bos.krpc.common.logger.LoggerFactory;
+import kd.bos.schedule.executor.AbstractTask;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import nckd.base.common.utils.DateUtil;
+import nckd.base.common.utils.ParamUtils;
+import nckd.base.common.utils.TripSyncUtils;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.text.ParseException;
+import java.util.*;
+
+/**
+ * Created with IntelliJ IDEA.
+ *
+ * @Author: 赵嘉琪
+ * @Date: 2025/12/19
+ * @Description:结算单(酒店)
+ */
+public class HotelSettlementTask extends AbstractTask {
+    private static Logger log = LoggerFactory.getLogger(HotelSettlementTask.class);
+
+    /**
+     * 总页码,不处理总数,
+     * 每当当前页码数据小于1000 停止接口查询
+     */
+    private final static int totalPage = 1000;
+
+    /**
+     * 每页条数,最多500条   实际1000条
+     */
+    private final static int size = 1000;
+
+    @Override
+    public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
+        log.info("结算单(同步酒店)查询接口 调度计划开始执行");
+        List<Map<String, Object>> resultLists = getResult();
+        if (ObjectUtils.isEmpty(resultLists)) {
+            log.info("结算单(同步酒店)查询接口 暂无数据-----");
+            return;
+        }
+        for (Map<String, Object> resultMap : resultLists) {
+            try {
+                // 从结果映射中提取各字段
+                extractAndProcessFields(resultMap);
+            } catch (Exception e) {
+                log.info("处理火车票结算数据时发生异常,数据内容: " + resultMap, e);
+            }
+        }
+
+    }
+
+    /**
+     * 从单条数据映射中提取字段并处理
+     *
+     * @param resultMap 单条数据映射
+     */
+    private void extractAndProcessFields(Map<String, Object> resultMap) throws ParseException {
+        // 1.获取接口返回值
+
+        // ===================== 订单基本信息 =====================
+        // 订单类型 (01001机票正常单, 01002机票退单, 01003机票改签单, 1酒店正常单, 2酒店退单等)
+        Object orderType = resultMap.get("orderType");
+        // 房间数
+        Object roomQuantity = resultMap.get("roomQuantity");
+        int roomQuantityInt = 0;
+
+        if (roomQuantity != null) {
+            try {
+                // 先解析为double,再转换为int
+                double doubleValue = Double.parseDouble(roomQuantity.toString());
+                roomQuantityInt = (int) doubleValue;
+
+                // 或者使用四舍五入
+                // roomQuantityInt = (int) Math.round(doubleValue);
+            } catch (NumberFormatException e) {
+                System.out.println("无法解析为数字: " + roomQuantity);
+            }
+        }
+        // 订单类型名称
+        Object orderName = resultMap.get("orderName");
+        // 订单号
+        Object orderNo = resultMap.get("orderNo");
+        // 原订单编号
+        Object oldOrderNo = resultMap.get("oldOrderNo");
+        // 订单状态 (已完成等)
+        Object orderStatus = resultMap.get("orderStatus");
+        // 预订时间
+        Object orderDate = resultMap.get("orderDate");
+        // 业务发生时间
+        Object rebookingtime = resultMap.get("rebookingtime");
+        // 结算生成时间
+        Object createTime = resultMap.get("createTime");
+
+        // ===================== 结算信息 =====================
+        // 结算明细主键
+        Object tmcSettlementid = resultMap.get("tmcSettlementid");
+        // 结算单号
+        Object settlementNo = resultMap.get("settlementNo");
+        // 结算批次号(对应系统账单号)
+        Object accCheckBatchNo = resultMap.get("accCheckBatchNo");
+        // 结算明细ID
+        Object subAccCheckBatchNo = resultMap.get("subAccCheckBatchNo");
+        // 大表ID
+        Object mainTableId = resultMap.get("mainTableId");
+        // 币种 (例如CNY)
+        Object settlementCurrency = resultMap.get("settlementCurrency");
+
+        // 结算金额
+        Object settlementAmount = resultMap.get("settlementAmount");
+        // 结算单合计金额
+        Object totalAmount = resultMap.get("totalAmount");
+
+        // ===================== 人员信息 =====================
+        // 出行人姓名
+        Object guestName = resultMap.get("guestName");
+        // 出行人名称
+        Object passengerName = resultMap.get("passengerName");
+        // 员工姓名
+        Object employeeName = resultMap.get("employeeName");
+        // 出行人工号
+        Object employeeId = resultMap.get("employeeId");
+        // 预订人姓名
+        Object reserveName = resultMap.get("reserveName");
+        // 预订人员编号
+        Object reserveId = resultMap.get("reserveId");
+        // 人员类型(可能是员工类型)
+        Object personnelType = resultMap.get("personnelType");
+
+        // ===================== 财务信息 =====================
+        // 销售价
+        Object price = resultMap.get("price");
+        // 折扣
+        Object priceRate = resultMap.get("priceRate");
+        // 含税金额
+        Object inTaxAmount = resultMap.get("inTaxAmount");
+        // 不含税金额
+        Object excludingtaxAmount = resultMap.get("excludingtaxAmount");
+        // 不含税交易金额(不含税销售价)
+        Object sellingPriceNoTax = resultMap.get("sellingPriceNoTax");
+        // 订单不含税金额
+        Object orderNoTaxAmount = resultMap.get("orderNoTaxAmount");
+        // 订单税额
+        Object orderTax = resultMap.get("orderTax");
+        // 发票税率
+        Object taxRate = resultMap.get("taxRate");
+
+        // ===================== 费用信息 =====================
+        // 员工自付金额
+        Object personalPaymentAmount = resultMap.get("personalPaymentAmount");
+        // 欠款金额
+        Object amount = resultMap.get("amount");
+        Object priceAmount = resultMap.get("priceAmount");
+        // 垫款服务费
+        Object advancePaymentAmount = resultMap.get("advancePaymentAmount");
+        // 支付类型 (0自付、1垫付)
+        Object payType = resultMap.get("payType");
+        // TMC支付类型
+        Object tmcPaymentType = resultMap.get("tmcPaymentType");
+        // 账单类型 (M月结, S服务费)
+        Object billType = resultMap.get("billType");
+
+        // ===================== 服务费信息 =====================
+        // TMC服务费(服务商服务费)
+        Object spServiceFee = resultMap.get("spServiceFee");
+        // 服务费(销售服务费)
+        Object serviceFee = resultMap.get("serviceFee");
+        // 技术服务费
+        Object technologyServiceFee = resultMap.get("technologyServiceFee");
+        // 退票费
+        Object refund = resultMap.get("refund");
+        // 改签费
+        Object rebookQueryFee = resultMap.get("rebookQueryFee");
+
+        // ===================== 项目信息 =====================
+        // 项目编号
+        Object projectNo = resultMap.get("projectNo");
+        // 项目名称
+        Object projectName = resultMap.get("projectName");
+        // 业务类型编号
+        Object businessTypeNo = resultMap.get("businessTypeNo");
+        // 业务类型名称
+        Object businessTypeName = resultMap.get("businessTypeName");
+        // 费用类型编号
+        Object feeTypeNo = resultMap.get("feeTypeNo");
+        // 费用类型名称
+        Object feeTypeName = resultMap.get("feeTypeName");
+        // 差旅类型 (1因公, 0因私)
+        Object travelType = resultMap.get("travelType");
+        if ("因公".equals(travelType)){
+            travelType = "1";
+        }else if ("因私".equals(travelType)){
+            travelType = "0";
+        }
+        // 搜索类型名称(可能是查询条件类型)
+        Object searchTypeName = resultMap.get("searchTypeName");
+
+        // ===================== 供应商信息 =====================
+        // 供应商编号
+        Object supplierNo = resultMap.get("supplierNo");
+        // 供应商名称
+        Object supplierName = resultMap.get("supplierName");
+        // 供应单号
+        Object purchaseOrderNo = resultMap.get("purchaseOrderNo");
+        // 供应商发票类型 (0/空:普票, 1:专票)
+        Object supplierInvoiceType = resultMap.get("supplierInvoiceType");
+        // 垫款商户编号
+        Object advancePaymentMerchantNo = resultMap.get("advancePaymentMerchantNo");
+        // 垫款商户名称
+        Object advancePaymentMerchantName = resultMap.get("advancePaymentMerchantName");
+
+        // ===================== 法人信息 =====================
+        // 法人公司名称
+        Object frgsmc = resultMap.get("frgsmc");
+
+        // ===================== 行程信息 =====================
+        // 国内国际标识 (1国内, 0国际)
+        Object international = resultMap.get("international");
+        // 所在城市/出发城市名称
+        Object cityName = resultMap.get("cityName");
+        // 到达城市
+        Object arrivalCity = resultMap.get("arrivalCity");
+        // 到达城市名称/酒店所在城市
+        Object arrivalCityName = resultMap.get("arrivalCityName");
+        // 入住日期/出发时间
+        Object startTime = resultMap.get("startTime");
+        // 离店日期/到达时间
+        Object endTime = resultMap.get("endTime");
+        // 出票时间
+        Object printTicketTime = resultMap.get("printTicketTime");
+
+        // ===================== 酒店信息 =====================
+        // 酒店名称
+        Object hotelName = resultMap.get("hotelName");
+        // 酒店星级
+        Object star = resultMap.get("star");
+        // 房型中文名称
+        Object roomName = resultMap.get("roomName");
+        // 间夜数
+        Object quantity = resultMap.get("quantity");
+
+        // ===================== 机票附加费 =====================
+        // 机票建设费
+        Object airportFee = resultMap.get("airportFee");
+        // 保险费
+        Object insuranceFee = resultMap.get("insuranceFee");
+
+        // ===================== 其他字段 =====================
+        // 销售价(重复字段,可根据实际情况处理)
+        Object transAmount = resultMap.get("transAmount");
+
+        // 2.酒店结算单 创建新的动态对象
+        DynamicObject hotelCheckingBill = BusinessDataServiceHelper.newDynamicObject("er_hotelcheckingbill");
+
+        //3.设置对应对象属性
+//        服务商
+        hotelCheckingBill.set("server", supplierName);
+        //订单日期
+        hotelCheckingBill.set("orderdate", DateUtil.string2date((String) orderDate,null));
+        //结算单号
+        hotelCheckingBill.set("ordernum", settlementNo);
+        //订单类型
+//        hotelCheckingBill.set("ordertype", orderType);
+        hotelCheckingBill.set("ordertype", "O");
+        //申请单号
+        hotelCheckingBill.set("oabillnum", "");
+        //报销单号
+        hotelCheckingBill.set("reimbursenum", "");
+        //业务类型
+        hotelCheckingBill.set("operationtype", businessTypeNo);
+        //订单分类
+        hotelCheckingBill.set("ordersort", orderType);
+        //订单性质
+        hotelCheckingBill.set("isbusiness", travelType);
+        //结算类型
+        hotelCheckingBill.set("producttype", "2");
+        //预订人姓名
+        hotelCheckingBill.set("bookedname", reserveName);
+        //预订人工号
+        hotelCheckingBill.set("sourcebookedid", reserveId);
+        //结算发生日期
+        hotelCheckingBill.set("happenddate", DateUtil.string2date((String) createTime,null));
+        //订单状态
+        hotelCheckingBill.set("orderstatus", "5");
+        //父订单号
+        hotelCheckingBill.set("parentordernum", "");
+
+        //币种
+        switch (settlementCurrency.toString()){
+            case "CNY":
+                hotelCheckingBill.set("currency", "1");
+                break;
+            case "HKD":
+                hotelCheckingBill.set("currency", "2");
+                break;
+            case "JPY":
+                hotelCheckingBill.set("currency", "3");
+                break;
+            case "USD":
+                hotelCheckingBill.set("currency", "4");
+                break;
+            case "EUR":
+                hotelCheckingBill.set("currency", "5");
+                break;
+            case "GBP":
+                hotelCheckingBill.set("currency", "6");
+                break;
+            case "AUD":
+                hotelCheckingBill.set("currency", "7");
+                break;
+            case "TWD":
+                hotelCheckingBill.set("currency", "8");
+                break;
+            case "MOP":
+                hotelCheckingBill.set("currency", "9");
+                break;
+        }
+
+        //结算金额
+        hotelCheckingBill.set("totalamount", settlementAmount);
+        //结算批次号
+        hotelCheckingBill.set("batchno", accCheckBatchNo);
+        //结算子批次号
+        hotelCheckingBill.set("subbatchno", "");
+        //费用承担公司
+        hotelCheckingBill.set("settlemain", "");
+        //费用承担部门
+        hotelCheckingBill.set("settledept", "");
+        //成本中心
+        hotelCheckingBill.set("std_costcenter", "");
+        //申请人公司
+        hotelCheckingBill.set("company", "");
+        //申请人部门
+        hotelCheckingBill.set("org", "");
+        //项目
+        hotelCheckingBill.set("std_project", projectNo);
+        //产品子类型
+        hotelCheckingBill.set("productsontype", "");
+        //外部系统结算单号
+        hotelCheckingBill.set("outsettlementnum", purchaseOrderNo);
+        //入住人工号
+        hotelCheckingBill.set("sourcetravelerid", employeeId);
+        //入住人
+        hotelCheckingBill.set("travelername", guestName);
+        //城市
+        hotelCheckingBill.set("cityname", arrivalCityName);
+        //酒店名称
+        hotelCheckingBill.set("hotelname", hotelName);
+        //入住日期
+        hotelCheckingBill.set("checkindate",DateUtil.string2date((String) startTime,"yyyy-MM-dd"));
+        //离店日期
+        hotelCheckingBill.set("checkoutdate", DateUtil.string2date((String) endTime,"yyyy-MM-dd"));
+        //房型
+        hotelCheckingBill.set("roomstylename", roomName);
+        //订房间数
+        hotelCheckingBill.set("roomcount", roomQuantityInt);
+
+        //服务费
+        hotelCheckingBill.set("servicefee", serviceFee);
+        //退订费
+        hotelCheckingBill.set("unbookfee", refund);
+        //票价开票类型
+        hotelCheckingBill.set("pricebillingtype", "");
+        //已对平
+        hotelCheckingBill.set("isbalance", "");
+        //备注
+        hotelCheckingBill.set("balanceremark", "");
+        //超标理由
+//        hotelCheckingBill.set("orderoverdesc", "");
+        //单据状态
+        hotelCheckingBill.set("billstatus", "C");
+        // 全部订单(er_allorderbill) 查询基础资料
+        //需要开票
+//        hotelCheckingBill.set("orderisinvoice", "");
+        //需要开票
+//        hotelCheckingBill.set("orderisinvoicerep", "");
+        //已确认
+//        hotelCheckingBill.set("orderisconfirm", "");
+        //已报销
+//        hotelCheckingBill.set("orderisrembureq", "");
+        //审批通过
+//        hotelCheckingBill.set("orderisapproverep", "");
+        //已报销
+//        hotelCheckingBill.set("orderisrembu", "");
+        //审批通过
+//        hotelCheckingBill.set("orderisapprove", "");
+        //已确认
+//        hotelCheckingBill.set("isconfirm", "");
+        //可抵扣
+//        hotelCheckingBill.set("isdeductible", "");
+        //可抵扣税额
+//        hotelCheckingBill.set("totaltax", "");
+        //已开票
+//        hotelCheckingBill.set("hasinvoice", "");
+        //付款/付款申请单号
+//        hotelCheckingBill.set("paybillnum", "");
+        //付款状态
+//        hotelCheckingBill.set("paybillstatus", "");
+        //凭证号
+//        hotelCheckingBill.set("vouchernum", "");
+        //记账日期
+//        hotelCheckingBill.set("bookeddatereq", "");
+        //记账日期
+//        hotelCheckingBill.set("bookeddatebu", "");
+
+        //4.保存对象
+        SaveServiceHelper.save(new DynamicObject[]{hotelCheckingBill});
+    }
+
+
+    /**
+     * 从接口获取酒店结算数据
+     *
+     * @return 酒店结算数据列表
+     */
+    private List<Map<String, Object>> getResult() {
+        //获取开始同步时间
+//        String syncTime = getSyncTime();
+        //当前时间
+        Date nowDate = new Date();
+        String nowDateString = DateUtil.date2str(nowDate, DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
+
+//        log.info("结算单(酒店) 同步开始时间:" + syncTime);
+
+        List<Map<String, Object>> dataList = new ArrayList<>();
+        for (int i = 0; i < totalPage; i++) {
+            //创建接口业务数据参数
+            Map<String, Object> data = new HashMap<>();
+            //结算时间始
+//            data.put("dateFrom", syncTime);
+            data.put("dateFrom", "1970-01-01 00:00:00");
+            //结算时间止
+            data.put("dateTo", nowDateString);
+            //产品类别 0300 酒店
+            data.put("searchType", "0300");
+            //当前页
+            data.put("current", i + 1);
+            //每页条数,最多500条
+            data.put("size", size);
+            //企业卡号
+            data.put("enterpriseNo", "JXWL");
+            //账单类型 01-现结
+//            data.put("settlementType", "01");
+
+            Map<String, Object> resp = TripSyncUtils.pushApiCallResult("FCSET_OUTAPI_LiteGetSettlementInfo", Boolean.FALSE, data);
+            //报错终止同步,等待下次计划执行
+            if ((Boolean) resp.get("fail")) {
+                throw new KDBizException(resp.get("message").toString());
+            }
+            Map<String, Object> result = (Map<String, Object>) resp.get("result");
+            List<Map<String, Object>> resultDataList = (List<Map<String, Object>>) result.getOrDefault("settlementInfos", Collections.emptyList());
+            dataList.addAll(resultDataList);
+
+            //当前查询数量小于分页数量时结束循环
+            if (resultDataList.size() < size) {
+                break;
+            }
+        }
+        return dataList;
+    }
+
+    /**
+     * 获取数据同步的开始时间
+     *
+     * @return 同步开始时间字符串(格式:yyyy-MM-dd HH:mm:ss)
+     */
+    private String getSyncTime() {
+        //获取费用核算应用参数
+        Map<String, Object> sysCtrlParameter = ParamUtils.getSysCtrlParameter(ParamUtils.EM);
+        //是否全量同步
+        Boolean isAll = (Boolean) sysCtrlParameter.get("nckd_settlementbillall");
+        if (isAll) {
+            return "1970-01-01 00:00:00";
+        }
+        //增量同步小时  填写整数N,同步N小时前到现在新增或修改的数据,不填默认1小时。
+        int hours = ObjectUtils.isEmpty(sysCtrlParameter.get("nckd_settlementbillhour")) ? 1 : (Integer) sysCtrlParameter.get("nckd_settlementbillhour");
+        //同步N小时前
+        Date date = DateUtil.addHour(new Date(), -hours);
+
+        return DateUtil.date2str(date, DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
+    }
+}

+ 434 - 0
nckd-fi/src/main/java/nckd/fi/er/task/InternationalFlightSettlementTask.java

@@ -0,0 +1,434 @@
+package nckd.fi.er.task;
+
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.exception.KDBizException;
+import kd.bos.exception.KDException;
+import kd.bos.krpc.common.logger.Logger;
+import kd.bos.krpc.common.logger.LoggerFactory;
+import kd.bos.schedule.executor.AbstractTask;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import nckd.base.common.utils.DateUtil;
+import nckd.base.common.utils.ParamUtils;
+import nckd.base.common.utils.TripSyncUtils;
+import org.apache.commons.lang3.ObjectUtils;
+
+import java.util.*;
+
+/**
+ * Created with IntelliJ IDEA.
+ *
+ * @Author: 赵嘉琪
+ * @Date: 2025/12/19
+ * @Description:结算单(国际机票)
+ */
+public class InternationalFlightSettlementTask extends AbstractTask {
+    private static Logger log = LoggerFactory.getLogger(InternationalFlightSettlementTask.class);
+
+    /**
+     * 总页码,不处理总数,
+     * 每当当前页码数据小于1000 停止接口查询
+     */
+    private final static int totalPage = 1000;
+
+    /**
+     * 每页条数,最多500条   实际1000条
+     */
+    private final static int size = 1000;
+
+    @Override
+    public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
+        log.info("结算单(国际机票)查询接口 调度计划开始执行");
+        List<Map<String, Object>> resultLists = getResult();
+        if (ObjectUtils.isEmpty(resultLists)) {
+            log.info("结算单(国际机票)查询接口 暂无数据-----");
+            return;
+        }
+        for (Map<String, Object> resultMap : resultLists) {
+            try {
+                // 从结果映射中提取各字段
+                extractAndProcessFields(resultMap);
+            } catch (Exception e) {
+                log.info("处理火车票结算数据时发生异常,数据内容: " + resultMap, e);
+            }
+        }
+
+    }
+
+    /**
+     * 从单条数据映射中提取字段并处理
+     *
+     * @param resultMap 单条数据映射
+     */
+    private void extractAndProcessFields(Map<String, Object> resultMap) {
+        // 1.获取接口返回值
+
+        // ===================== 订单基本信息 =====================
+        // 订单类型 (01001机票正常单, 01002机票退单, 01003机票改签单, 1酒店正常单, 2酒店退单等)
+        Object orderType = resultMap.get("orderType");
+        // 房间数
+        Object roomQuantity = resultMap.get("roomQuantity");
+        // 订单类型名称
+        Object orderName = resultMap.get("orderName");
+        // 订单号
+        Object orderNo = resultMap.get("orderNo");
+        // 原订单编号
+        Object oldOrderNo = resultMap.get("oldOrderNo");
+        // 订单状态 (已完成等)
+        Object orderStatus = resultMap.get("orderStatus");
+        // 预订时间
+        Object orderDate = resultMap.get("orderDate");
+        // 业务发生时间
+        Object rebookingtime = resultMap.get("rebookingtime");
+        // 结算生成时间
+        Object createTime = resultMap.get("createTime");
+
+        // ===================== 结算信息 =====================
+        // 结算明细主键
+        Object tmcSettlementid = resultMap.get("tmcSettlementid");
+        // 结算单号
+        Object settlementNo = resultMap.get("settlementNo");
+        // 结算批次号(对应系统账单号)
+        Object accCheckBatchNo = resultMap.get("accCheckBatchNo");
+        // 结算明细ID
+        Object subAccCheckBatchNo = resultMap.get("subAccCheckBatchNo");
+        // 大表ID
+        Object mainTableId = resultMap.get("mainTableId");
+        // 币种 (例如CNY)
+        Object settlementCurrency = resultMap.get("settlementCurrency");
+        // 结算金额
+        Object settlementAmount = resultMap.get("settlementAmount");
+        // 结算单合计金额
+        Object totalAmount = resultMap.get("totalAmount");
+
+        // ===================== 人员信息 =====================
+        // 出行人姓名
+        Object guestName = resultMap.get("guestName");
+        // 出行人名称
+        Object passengerName = resultMap.get("passengerName");
+        // 员工姓名
+        Object employeeName = resultMap.get("employeeName");
+        // 出行人工号
+        Object employeeId = resultMap.get("employeeId");
+        // 预订人姓名
+        Object reserveName = resultMap.get("reserveName");
+        // 预订人员编号
+        Object reserveId = resultMap.get("reserveId");
+        // 人员类型(可能是员工类型)
+        Object personnelType = resultMap.get("personnelType");
+
+        // ===================== 财务信息 =====================
+        // 销售价
+        Object price = resultMap.get("price");
+        // 折扣
+        Object priceRate = resultMap.get("priceRate");
+        // 含税金额
+        Object inTaxAmount = resultMap.get("inTaxAmount");
+        // 不含税金额
+        Object excludingtaxAmount = resultMap.get("excludingtaxAmount");
+        // 不含税交易金额(不含税销售价)
+        Object sellingPriceNoTax = resultMap.get("sellingPriceNoTax");
+        // 订单不含税金额
+        Object orderNoTaxAmount = resultMap.get("orderNoTaxAmount");
+        // 订单税额
+        Object orderTax = resultMap.get("orderTax");
+        // 发票税率
+        Object taxRate = resultMap.get("taxRate");
+
+        // ===================== 费用信息 =====================
+        // 员工自付金额
+        Object personalPaymentAmount = resultMap.get("personalPaymentAmount");
+        // 欠款金额
+        Object amount = resultMap.get("amount");
+        Object priceAmount = resultMap.get("priceAmount");
+        // 垫款服务费
+        Object advancePaymentAmount = resultMap.get("advancePaymentAmount");
+        // 支付类型 (0自付、1垫付)
+        Object payType = resultMap.get("payType");
+        // TMC支付类型
+        Object tmcPaymentType = resultMap.get("tmcPaymentType");
+        // 账单类型 (M月结, S服务费)
+        Object billType = resultMap.get("billType");
+
+        // ===================== 服务费信息 =====================
+        // TMC服务费(服务商服务费)
+        Object spServiceFee = resultMap.get("spServiceFee");
+        // 服务费(销售服务费)
+        Object serviceFee = resultMap.get("serviceFee");
+        // 技术服务费
+        Object technologyServiceFee = resultMap.get("technologyServiceFee");
+        // 退票费
+        Object refund = resultMap.get("refund");
+        // 改签费
+        Object rebookQueryFee = resultMap.get("rebookQueryFee");
+
+        // ===================== 项目信息 =====================
+        // 项目编号
+        Object projectNo = resultMap.get("projectNo");
+        // 项目名称
+        Object projectName = resultMap.get("projectName");
+        // 业务类型编号
+        Object businessTypeNo = resultMap.get("businessTypeNo");
+        // 业务类型名称
+        Object businessTypeName = resultMap.get("businessTypeName");
+        // 费用类型编号
+        Object feeTypeNo = resultMap.get("feeTypeNo");
+        // 费用类型名称
+        Object feeTypeName = resultMap.get("feeTypeName");
+        // 差旅类型 (1因公, 0因私)
+        Object travelType = resultMap.get("travelType");
+        // 搜索类型名称(可能是查询条件类型)
+        Object searchTypeName = resultMap.get("searchTypeName");
+
+        // ===================== 供应商信息 =====================
+        // 供应商编号
+        Object supplierNo = resultMap.get("supplierNo");
+        // 供应商名称
+        Object supplierName = resultMap.get("supplierName");
+        // 供应单号
+        Object purchaseOrderNo = resultMap.get("purchaseOrderNo");
+        // 供应商发票类型 (0/空:普票, 1:专票)
+        Object supplierInvoiceType = resultMap.get("supplierInvoiceType");
+        // 垫款商户编号
+        Object advancePaymentMerchantNo = resultMap.get("advancePaymentMerchantNo");
+        // 垫款商户名称
+        Object advancePaymentMerchantName = resultMap.get("advancePaymentMerchantName");
+
+        // ===================== 法人信息 =====================
+        // 法人公司名称
+        Object frgsmc = resultMap.get("frgsmc");
+
+        // ===================== 行程信息 =====================
+        // 国内国际标识 (1国内, 0国际)
+        Object international = resultMap.get("international");
+        // 所在城市/出发城市名称
+        Object cityName = resultMap.get("cityName");
+        // 到达城市
+        Object arrivalCity = resultMap.get("arrivalCity");
+        // 到达城市名称/酒店所在城市
+        Object arrivalCityName = resultMap.get("arrivalCityName");
+        // 入住日期/出发时间
+        Object startTime = resultMap.get("startTime");
+        // 离店日期/到达时间
+        Object endTime = resultMap.get("endTime");
+        // 出票时间
+        Object printTicketTime = resultMap.get("printTicketTime");
+
+        // ===================== 酒店信息 =====================
+        // 酒店名称
+        Object hotelName = resultMap.get("hotelName");
+        // 酒店星级
+        Object star = resultMap.get("star");
+        // 房型中文名称
+        Object roomName = resultMap.get("roomName");
+        // 间夜数
+        Object quantity = resultMap.get("quantity");
+
+        // ===================== 机票附加费 =====================
+        // 机票建设费
+        Object airportFee = resultMap.get("airportFee");
+        // 保险费
+        Object insuranceFee = resultMap.get("insuranceFee");
+
+        // ===================== 其他字段 =====================
+        // 销售价(重复字段,可根据实际情况处理)
+        Object transAmount = resultMap.get("transAmount");
+
+        // 2.机票结算单 --国际机票 创建动态对象
+        DynamicObject planeCheckingBill = BusinessDataServiceHelper.newDynamicObject("er_planecheckingbill");
+
+        //3.设置各字段
+        //订单日期
+        planeCheckingBill.set("orderdate", orderType);
+        //订单性质
+        planeCheckingBill.set("isbusiness", travelType);
+        //结算类型 2 -个人现付
+        planeCheckingBill.set("producttype", "2");
+        //预订人工号
+        planeCheckingBill.set("booknum", "");
+        //预订人姓名
+        planeCheckingBill.set("bookedname", reserveName);
+        //结算发生日期
+        planeCheckingBill.set("happenddate", DateUtil.string2date((String) createTime,null));
+        //业务类型
+        planeCheckingBill.set("operationtype", businessTypeNo);
+        //订单分类
+        planeCheckingBill.set("ordersort", orderType);
+        //订单状态
+        planeCheckingBill.set("orderstatus", "5");
+        //结算金额
+        planeCheckingBill.set("totalamount", settlementAmount);
+        //币种
+        switch (settlementCurrency.toString()){
+            case "CNY":
+                planeCheckingBill.set("currency", "1");
+                break;
+            case "HKD":
+                planeCheckingBill.set("currency", "2");
+                break;
+            case "JPY":
+                planeCheckingBill.set("currency", "3");
+                break;
+            case "USD":
+                planeCheckingBill.set("currency", "4");
+                break;
+            case "EUR":
+                planeCheckingBill.set("currency", "5");
+                break;
+            case "GBP":
+                planeCheckingBill.set("currency", "6");
+                break;
+            case "AUD":
+                planeCheckingBill.set("currency", "7");
+                break;
+            case "TWD":
+                planeCheckingBill.set("currency", "8");
+                break;
+            case "MOP":
+                planeCheckingBill.set("currency", "9");
+                break;
+        }
+        //结算批次号
+        planeCheckingBill.set("batchno", accCheckBatchNo);
+        //结算子批次号
+        planeCheckingBill.set("subbatchno", "");
+        //费用承担公司
+        planeCheckingBill.set("settlemain", "");
+        //费用承担部门
+        planeCheckingBill.set("settledept", "");
+        //申请人公司
+        planeCheckingBill.set("company", "");
+        //申请人部门
+        planeCheckingBill.set("org", "");
+        //项目
+        planeCheckingBill.set("std_project", projectNo);
+        //成本中心
+        planeCheckingBill.set("std_costcenter", "");
+        //外部系统结算单号
+        planeCheckingBill.set("outsettlementnum", "");
+        //火车票车票号
+        planeCheckingBill.set("trainticketnum", "");
+        //出发城市
+        planeCheckingBill.set("departcity", cityName);
+        //出发车站
+        planeCheckingBill.set("departaddress", "");
+        //到达城市
+        planeCheckingBill.set("arrivecity", arrivalCity);
+        //到达车站
+        planeCheckingBill.set("arriveaddress", "");
+        //出发时间
+        planeCheckingBill.set("departtime", "");
+        //到达时间
+        planeCheckingBill.set("arrivetime", "");
+        //乘客
+        planeCheckingBill.set("passeger", "");
+        //乘客姓名
+        planeCheckingBill.set("passegername", "");
+        //火车票价
+        planeCheckingBill.set("ticketprice", "");
+        //服务费
+        planeCheckingBill.set("servicefee", serviceFee);
+        //退票费
+        planeCheckingBill.set("refundamount", refund);
+        //保险费
+        planeCheckingBill.set("assuranceamount", insuranceFee);
+        //下载地址
+        planeCheckingBill.set("downloadlink", "");
+        //内部下载地址
+        planeCheckingBill.set("kddownloadlink", "");
+        //发票流水号
+        planeCheckingBill.set("serialno", "");
+        //发票识别异常信息
+        planeCheckingBill.set("identityerrormsg", "");
+        //票价开票类型
+        planeCheckingBill.set("pricebillingtype", "");
+
+        //可抵扣税额
+        planeCheckingBill.set("totaltax", "");
+        //已开票
+        planeCheckingBill.set("hasinvoice", "");
+        //付款/付款申请单号
+        planeCheckingBill.set("paybillnum", "");
+        //付款状态
+        planeCheckingBill.set("paybillstatus", "");
+        //凭证号
+        planeCheckingBill.set("vouchernum", "");
+        //记账日期
+        planeCheckingBill.set("bookeddatereq", "");
+        //记账日期
+        planeCheckingBill.set("bookeddatebu", "");
+
+        //4.保存对象
+        SaveServiceHelper.save(new DynamicObject[]{planeCheckingBill});
+    }
+
+    /**
+     * 从接口获取国际机票结算数据
+     *
+     * @return 国际机票结算数据列表
+     */
+    private List<Map<String, Object>> getResult() {
+        //获取开始同步时间
+        String syncTime = getSyncTime();
+        //当前时间
+        Date nowDate = new Date();
+        String nowDateString = DateUtil.date2str(nowDate, DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
+
+        log.info("结算单(国际机票) 同步开始时间:" + syncTime);
+
+        List<Map<String, Object>> dataList = new ArrayList<>();
+        for (int i = 0; i < totalPage; i++) {
+            //创建接口业务数据参数
+            Map<String, Object> data = new HashMap<>();
+            //结算时间始
+            data.put("dateFrom", syncTime);
+            //结算时间止
+            data.put("dateTo", nowDateString);
+            //产品类别 0200 国际机票
+            data.put("searchType", "0200");
+            //当前页
+            data.put("current", i + 1);
+            //每页条数,最多500条
+            data.put("size", size);
+            //企业卡号
+            data.put("enterpriseNo", "JXWL");
+            //账单类型 01-现结
+            data.put("settlementType", "01");
+
+            Map<String, Object> resp = TripSyncUtils.pushApiCallResult("FCSET_OUTAPI_LiteGetSettlementInfo", Boolean.FALSE, data);
+            //报错终止同步,等待下次计划执行
+            if ((Boolean) resp.get("fail")) {
+                throw new KDBizException(resp.get("message").toString());
+            }
+            Map<String, Object> result = (Map<String, Object>) resp.get("result");
+            List<Map<String, Object>> resultDataList = (List<Map<String, Object>>) result.getOrDefault("dataList", Collections.emptyList());
+            dataList.addAll(resultDataList);
+
+            //当前查询数量小于分页数量时结束循环
+            if (resultDataList.size() < size) {
+                break;
+            }
+        }
+        return dataList;
+    }
+
+    /**
+     * @return 获取同步开始时间
+     */
+    private String getSyncTime() {
+        //获取费用核算应用参数
+        Map<String, Object> sysCtrlParameter = ParamUtils.getSysCtrlParameter(ParamUtils.EM);
+        //是否全量同步
+        Boolean isAll = (Boolean) sysCtrlParameter.get("nckd_settlementbillall");
+        if (isAll) {
+            return "1970-01-01 00:00:00";
+        }
+        //增量同步小时  填写整数N,同步N小时前到现在新增或修改的数据,不填默认1小时。
+        int hours = ObjectUtils.isEmpty(sysCtrlParameter.get("nckd_settlementbillhour")) ? 1 : (Integer) sysCtrlParameter.get("nckd_settlementbillhour");
+        //同步N小时前
+        Date date = DateUtil.addHour(new Date(), -hours);
+
+        return DateUtil.date2str(date, DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
+    }
+}

+ 481 - 0
nckd-fi/src/main/java/nckd/fi/er/task/TrainTicketSettlementTask.java

@@ -0,0 +1,481 @@
+package nckd.fi.er.task;
+
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.exception.KDBizException;
+import kd.bos.exception.KDException;
+import kd.bos.krpc.common.logger.Logger;
+import kd.bos.krpc.common.logger.LoggerFactory;
+import kd.bos.schedule.executor.AbstractTask;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import nckd.base.common.utils.DateUtil;
+import nckd.base.common.utils.ParamUtils;
+import nckd.base.common.utils.TripSyncUtils;
+import org.apache.commons.lang3.ObjectUtils;
+
+import java.util.*;
+
+/**
+ * 火车票结算单同步任务
+ * 功能:从外部接口获取火车票结算数据,并同步到系统中
+ *
+ * @Author: 赵嘉琪
+ * @Date: 2025/12/18
+ */
+public class TrainTicketSettlementTask extends AbstractTask {
+    private static final Logger log = LoggerFactory.getLogger(TrainTicketSettlementTask.class);
+
+    /**
+     * 最大查询页数,当某页数据小于每页条数时停止查询
+     */
+    private static final int TOTAL_PAGE = 1000;
+
+    /**
+     * 每页查询条数
+     */
+    private static final int PAGE_SIZE = 1000;
+
+    /**
+     * 任务执行入口
+     *
+     * @param requestContext 请求上下文
+     * @param map 任务参数映射
+     * @throws KDException 执行异常
+     */
+    @Override
+    public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
+        log.info("结算单(同步火车票)查询接口 调度计划开始执行");
+
+        List<Map<String, Object>> resultLists = getResult();
+        if (ObjectUtils.isEmpty(resultLists)) {
+            log.info("结算单(同步火车票)查询接口 暂无数据-----");
+            return;
+        }
+
+        processResultData(resultLists);
+    }
+
+    /**
+     * 处理获取到的火车票结算数据
+     *
+     * @param resultLists 火车票结算数据列表
+     */
+    private void processResultData(List<Map<String, Object>> resultLists) {
+        for (Map<String, Object> resultMap : resultLists) {
+            try {
+                // 从结果映射中提取各字段
+                extractAndProcessFields(resultMap);
+            } catch (Exception e) {
+                log.error("处理火车票结算数据时发生异常,数据内容: " + resultMap, e);
+            }
+        }
+    }
+
+    /**
+     * 从单条数据映射中提取字段并处理
+     *
+     * @param resultMap 单条数据映射
+     */
+    private void extractAndProcessFields(Map<String, Object> resultMap) {
+        // 1.获取接口返回值
+
+        // ===================== 订单基本信息 =====================
+        // 订单类型 (01001机票正常单, 01002机票退单, 01003机票改签单, 1酒店正常单, 2酒店退单等)
+        Object orderType = resultMap.get("orderType");
+        // 房间数
+        Object roomQuantity = resultMap.get("roomQuantity");
+        // 订单类型名称
+        Object orderName = resultMap.get("orderName");
+        // 订单号
+        Object orderNo = resultMap.get("orderNo");
+        // 原订单编号
+        Object oldOrderNo = resultMap.get("oldOrderNo");
+        // 订单状态 (已完成等)
+        Object orderStatus = resultMap.get("orderStatus");
+        // 预订时间
+        Object orderDate = resultMap.get("orderDate");
+        // 业务发生时间
+        Object rebookingtime = resultMap.get("rebookingtime");
+        // 结算生成时间
+        Object createTime = resultMap.get("createTime");
+
+        // ===================== 结算信息 =====================
+        // 结算明细主键
+        Object tmcSettlementid = resultMap.get("tmcSettlementid");
+        // 结算单号
+        Object settlementNo = resultMap.get("settlementNo");
+        // 结算批次号(对应系统账单号)
+        Object accCheckBatchNo = resultMap.get("accCheckBatchNo");
+        // 结算明细ID
+        Object subAccCheckBatchNo = resultMap.get("subAccCheckBatchNo");
+        // 大表ID
+        Object mainTableId = resultMap.get("mainTableId");
+        // 币种 (例如CNY)
+        Object settlementCurrency = resultMap.get("settlementCurrency");
+        // 结算金额
+        Object settlementAmount = resultMap.get("settlementAmount");
+        // 结算单合计金额
+        Object totalAmount = resultMap.get("totalAmount");
+
+        // ===================== 人员信息 =====================
+        // 出行人姓名
+        Object guestName = resultMap.get("guestName");
+        // 出行人名称
+        Object passengerName = resultMap.get("passengerName");
+        // 员工姓名
+        Object employeeName = resultMap.get("employeeName");
+        // 出行人工号
+        Object employeeId = resultMap.get("employeeId");
+        // 预订人姓名
+        Object reserveName = resultMap.get("reserveName");
+        // 预订人员编号
+        Object reserveId = resultMap.get("reserveId");
+        // 人员类型(可能是员工类型)
+        Object personnelType = resultMap.get("personnelType");
+
+        // ===================== 财务信息 =====================
+        // 销售价
+        Object price = resultMap.get("price");
+        // 折扣
+        Object priceRate = resultMap.get("priceRate");
+        // 含税金额
+        Object inTaxAmount = resultMap.get("inTaxAmount");
+        // 不含税金额
+        Object excludingtaxAmount = resultMap.get("excludingtaxAmount");
+        // 不含税交易金额(不含税销售价)
+        Object sellingPriceNoTax = resultMap.get("sellingPriceNoTax");
+        // 订单不含税金额
+        Object orderNoTaxAmount = resultMap.get("orderNoTaxAmount");
+        // 订单税额
+        Object orderTax = resultMap.get("orderTax");
+        // 发票税率
+        Object taxRate = resultMap.get("taxRate");
+
+        // ===================== 费用信息 =====================
+        // 员工自付金额
+        Object personalPaymentAmount = resultMap.get("personalPaymentAmount");
+        // 欠款金额
+        Object amount = resultMap.get("amount");
+        Object priceAmount = resultMap.get("priceAmount");
+        // 垫款服务费
+        Object advancePaymentAmount = resultMap.get("advancePaymentAmount");
+        // 支付类型 (0自付、1垫付)
+        Object payType = resultMap.get("payType");
+        // TMC支付类型
+        Object tmcPaymentType = resultMap.get("tmcPaymentType");
+        // 账单类型 (M月结, S服务费)
+        Object billType = resultMap.get("billType");
+
+        // ===================== 服务费信息 =====================
+        // TMC服务费(服务商服务费)
+        Object spServiceFee = resultMap.get("spServiceFee");
+        // 服务费(销售服务费)
+        Object serviceFee = resultMap.get("serviceFee");
+        // 技术服务费
+        Object technologyServiceFee = resultMap.get("technologyServiceFee");
+        // 退票费
+        Object refund = resultMap.get("refund");
+        // 改签费
+        Object rebookQueryFee = resultMap.get("rebookQueryFee");
+
+        // ===================== 项目信息 =====================
+        // 项目编号
+        Object projectNo = resultMap.get("projectNo");
+        // 项目名称
+        Object projectName = resultMap.get("projectName");
+        // 业务类型编号
+        Object businessTypeNo = resultMap.get("businessTypeNo");
+        // 业务类型名称
+        Object businessTypeName = resultMap.get("businessTypeName");
+        // 费用类型编号
+        Object feeTypeNo = resultMap.get("feeTypeNo");
+        // 费用类型名称
+        Object feeTypeName = resultMap.get("feeTypeName");
+        // 差旅类型 (1因公, 0因私)
+        Object travelType = resultMap.get("travelType");
+        // 搜索类型名称(可能是查询条件类型)
+        Object searchTypeName = resultMap.get("searchTypeName");
+
+        // ===================== 供应商信息 =====================
+        // 供应商编号
+        Object supplierNo = resultMap.get("supplierNo");
+        // 供应商名称
+        Object supplierName = resultMap.get("supplierName");
+        // 供应单号
+        Object purchaseOrderNo = resultMap.get("purchaseOrderNo");
+        // 供应商发票类型 (0/空:普票, 1:专票)
+        Object supplierInvoiceType = resultMap.get("supplierInvoiceType");
+        // 垫款商户编号
+        Object advancePaymentMerchantNo = resultMap.get("advancePaymentMerchantNo");
+        // 垫款商户名称
+        Object advancePaymentMerchantName = resultMap.get("advancePaymentMerchantName");
+
+        // ===================== 法人信息 =====================
+        // 法人公司名称
+        Object frgsmc = resultMap.get("frgsmc");
+
+        // ===================== 行程信息 =====================
+        // 国内国际标识 (1国内, 0国际)
+        Object international = resultMap.get("international");
+        // 所在城市/出发城市名称
+        Object cityName = resultMap.get("cityName");
+        // 到达城市
+        Object arrivalCity = resultMap.get("arrivalCity");
+        // 到达城市名称/酒店所在城市
+        Object arrivalCityName = resultMap.get("arrivalCityName");
+        // 入住日期/出发时间
+        Object startTime = resultMap.get("startTime");
+        // 离店日期/到达时间
+        Object endTime = resultMap.get("endTime");
+        // 出票时间
+        Object printTicketTime = resultMap.get("printTicketTime");
+
+        // ===================== 酒店信息 =====================
+        // 酒店名称
+        Object hotelName = resultMap.get("hotelName");
+        // 酒店星级
+        Object star = resultMap.get("star");
+        // 房型中文名称
+        Object roomName = resultMap.get("roomName");
+        // 间夜数
+        Object quantity = resultMap.get("quantity");
+
+        // ===================== 机票附加费 =====================
+        // 机票建设费
+        Object airportFee = resultMap.get("airportFee");
+        // 保险费
+        Object insuranceFee = resultMap.get("insuranceFee");
+
+        // ===================== 其他字段 =====================
+        // 销售价(重复字段,可根据实际情况处理)
+        Object transAmount = resultMap.get("transAmount");
+
+        //2. 判断当前结算单是否已经存在 存在即修改  不存在 创建动态对象 ????
+        DynamicObject trainCheckingBill = BusinessDataServiceHelper.newDynamicObject("er_traincheckingbill");
+
+        //3. 设置各字段
+        //订单日期
+        trainCheckingBill.set("orderdate", orderType);
+        //订单性质
+        trainCheckingBill.set("isbusiness", travelType);
+        //结算类型 2 -个人现付
+        trainCheckingBill.set("producttype", "2");
+        //预订人工号
+        trainCheckingBill.set("booknum", "");
+        //预订人姓名
+        trainCheckingBill.set("bookedname", reserveName);
+        //结算发生日期
+        trainCheckingBill.set("happenddate", DateUtil.string2date((String) createTime,null));
+        //业务类型
+        trainCheckingBill.set("operationtype", businessTypeNo);
+        //订单分类
+        trainCheckingBill.set("ordersort", orderType);
+        //订单状态
+        trainCheckingBill.set("orderstatus", "5");
+        //结算金额
+        trainCheckingBill.set("totalamount", settlementAmount);
+        //币种
+        switch (settlementCurrency.toString()){
+            case "CNY":
+                trainCheckingBill.set("currency", "1");
+                break;
+            case "HKD":
+                trainCheckingBill.set("currency", "2");
+                break;
+            case "JPY":
+                trainCheckingBill.set("currency", "3");
+                break;
+            case "USD":
+                trainCheckingBill.set("currency", "4");
+                break;
+            case "EUR":
+                trainCheckingBill.set("currency", "5");
+                break;
+            case "GBP":
+                trainCheckingBill.set("currency", "6");
+                break;
+            case "AUD":
+                trainCheckingBill.set("currency", "7");
+                break;
+            case "TWD":
+                trainCheckingBill.set("currency", "8");
+                break;
+            case "MOP":
+                trainCheckingBill.set("currency", "9");
+                break;
+        }
+        //结算批次号
+        trainCheckingBill.set("batchno", accCheckBatchNo);
+        //结算子批次号
+        trainCheckingBill.set("subbatchno", "");
+        //费用承担公司
+        trainCheckingBill.set("settlemain", "");
+        //费用承担部门
+        trainCheckingBill.set("settledept", "");
+        //申请人公司
+        trainCheckingBill.set("company", "");
+        //申请人部门
+        trainCheckingBill.set("org", "");
+        //项目
+        trainCheckingBill.set("std_project", projectNo);
+        //成本中心
+        trainCheckingBill.set("std_costcenter", "");
+        //外部系统结算单号
+        trainCheckingBill.set("outsettlementnum", "");
+        //火车票车票号
+        trainCheckingBill.set("trainticketnum", "");
+        //出发城市
+        trainCheckingBill.set("departcity", "");
+        //出发车站
+        trainCheckingBill.set("departaddress", "");
+        //到达城市
+        trainCheckingBill.set("arrivecity", "");
+        //到达车站
+        trainCheckingBill.set("arriveaddress", "");
+        //出发时间
+        trainCheckingBill.set("departtime", "");
+        //到达时间
+        trainCheckingBill.set("arrivetime", "");
+        //乘客
+        trainCheckingBill.set("passeger", "");
+        //乘客姓名
+        trainCheckingBill.set("passegername", "");
+        //车次
+        trainCheckingBill.set("vendorname", "");
+        //席位
+        trainCheckingBill.set("trainseat", "");
+        //火车票价
+        trainCheckingBill.set("ticketprice", "");
+        //服务费
+        trainCheckingBill.set("servicefee", "");
+        //退票费
+        trainCheckingBill.set("refundamount", "");
+        //保险费
+        trainCheckingBill.set("assuranceamount", "");
+        //下载地址
+        trainCheckingBill.set("downloadlink", "");
+        //内部下载地址
+        trainCheckingBill.set("kddownloadlink", "");
+        //发票流水号
+        trainCheckingBill.set("serialno", "");
+        //发票识别异常信息
+        trainCheckingBill.set("identityerrormsg", "");
+        //票价开票类型
+        trainCheckingBill.set("pricebillingtype", "");
+
+        //控制信息
+//        ??????。。
+        //可抵扣税额
+        trainCheckingBill.set("totaltax", "");
+        //已开票
+        trainCheckingBill.set("hasinvoice", "");
+        //付款/付款申请单号
+        trainCheckingBill.set("paybillnum", "");
+        //付款状态
+        trainCheckingBill.set("paybillstatus", "");
+        //凭证号
+        trainCheckingBill.set("vouchernum", "");
+        //记账日期
+        trainCheckingBill.set("bookeddatereq", "");
+        //记账日期
+        trainCheckingBill.set("bookeddatebu", "");
+
+        //4. 保存对象
+        SaveServiceHelper.save(new DynamicObject[]{trainCheckingBill});
+    }
+
+    /**
+     * 从接口获取火车票结算数据
+     *
+     * @return 火车票结算数据列表
+     */
+    private List<Map<String, Object>> getResult() {
+        //获取同步开始时间
+        String syncTime = getSyncTime();
+        //获取当前时间
+        Date nowDate = new Date();
+        //获取当前时间字符串
+        String nowDateString = DateUtil.date2str(nowDate, DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
+
+        log.info("结算单(火车票) 同步开始时间:" + syncTime);
+
+        List<Map<String, Object>> dataList = new ArrayList<>();
+        for (int i = 0; i < TOTAL_PAGE; i++) {
+            // 查询当前页数据
+            List<Map<String, Object>> pageData = queryPageData(syncTime, nowDateString, i + 1);
+            dataList.addAll(pageData);
+
+            // 当前页数据量小于分页大小时,说明已到最后一页
+            if (pageData.size() < PAGE_SIZE) {
+                break;
+            }
+        }
+        return dataList;
+    }
+
+    /**
+     * 分页查询接口数据
+     *
+     * @param syncTime 同步开始时间
+     * @param nowDateString 当前时间字符串
+     * @param currentPage 当前页码
+     * @return 当前页的数据列表
+     */
+    private List<Map<String, Object>> queryPageData(String syncTime, String nowDateString, int currentPage) {
+        // 请求参数
+        Map<String, Object> requestData = new HashMap<>();
+        // 结算时间始
+        requestData.put("dateFrom", syncTime);
+        // 结算时间止
+        requestData.put("dateTo", nowDateString);
+        // 产品类别 0600 火车票
+        requestData.put("searchType", "0600");
+        // 当前页码
+        requestData.put("current", currentPage);
+        // 每页数据量
+        requestData.put("size", PAGE_SIZE);
+        // 企业卡号
+        requestData.put("enterpriseNo", "JXWL");
+        // 账单类型 01-现结
+        requestData.put("settlementType", "01");
+
+        // 调用接口
+        Map<String, Object> resp = TripSyncUtils.pushApiCallResult("FCSET_OUTAPI_LiteGetSettlementInfo", Boolean.FALSE, requestData);
+
+        // 接口调用失败时抛出异常
+        if ((Boolean) resp.get("fail")) {
+            throw new KDBizException(resp.get("message").toString());
+        }
+
+        Map<String, Object> result = (Map<String, Object>) resp.get("result");
+        return (List<Map<String, Object>>) result.getOrDefault("dataList", Collections.emptyList());
+    }
+
+
+
+    /**
+     * 获取数据同步的开始时间
+     *
+     * @return 同步开始时间字符串(格式:yyyy-MM-dd HH:mm:ss)
+     */
+    private String getSyncTime() {
+        // 获取费用核算应用参数
+        Map<String, Object> sysCtrlParameter = ParamUtils.getSysCtrlParameter(ParamUtils.EM);
+
+        // 是否全量同步
+        Boolean isAll = (Boolean) sysCtrlParameter.get("nckd_settlementbillall");
+        if (isAll != null && isAll) {
+            return "1970-01-01 00:00:00";
+        }
+
+        // 增量同步小时数,默认1小时
+        int hours = ObjectUtils.isEmpty(sysCtrlParameter.get("nckd_settlementbillhour"))
+                ? 1
+                : (Integer) sysCtrlParameter.get("nckd_settlementbillhour");
+
+        // 计算同步开始时间(当前时间前推N小时)
+        Date date = DateUtil.addHour(new Date(), -hours);
+        return DateUtil.date2str(date, DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS);
+    }
+}