package com.yc.ship.module.trade.service.ota.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yc.ship.framework.common.exception.ServerException;
import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.common.util.collection.CollectionUtils;
import com.yc.ship.framework.tenant.core.context.TenantContextHolder;
import com.yc.ship.module.ota.api.OtaDistributorApi;
import com.yc.ship.module.ota.api.dto.DistributorProductRespDTO;
import com.yc.ship.module.ota.api.dto.DistributorRespDTO;
import com.yc.ship.module.product.api.ProductApi;
import com.yc.ship.module.product.api.dto.ProductRefundRuleRespDTO;
import com.yc.ship.module.product.api.dto.ProductSaleRuleRespDTO;
import com.yc.ship.module.product.api.dto.ProductSpuRespDTO;
import com.yc.ship.module.trade.api.dto.TradeOrderCreateReqDTO;
import com.yc.ship.module.trade.api.dto.TradeOrderRespDTO;
import com.yc.ship.module.trade.api.dto.TradeRefundCreateReqDTO;
import com.yc.ship.module.trade.api.dto.TradeRefundRespDTO;
import com.yc.ship.module.trade.controller.admin.order.vo.order.PayOrderReqVO;
import com.yc.ship.module.trade.controller.admin.order.vo.order.PayOrderRespVO;
import com.yc.ship.module.trade.convert.order.TradeRefundConvert;
import com.yc.ship.module.trade.convert.ota.OtaConvert;
import com.yc.ship.module.trade.dal.dataobject.order.TradeDetailDO;
import com.yc.ship.module.trade.dal.dataobject.order.TradeOrderDO;
import com.yc.ship.module.trade.dal.dataobject.order.TradeVisitorDO;
import com.yc.ship.module.trade.dal.dataobject.refund.RefundDO;
import com.yc.ship.module.trade.enums.*;
import com.yc.ship.module.trade.framework.common.Md5;
import com.yc.ship.module.trade.framework.common.ota.AesUtil;
import com.yc.ship.module.trade.framework.common.ota.XieChengResolver;
import com.yc.ship.module.trade.service.notifylog.NotifyLogService;
import com.yc.ship.module.trade.service.order.TradeOrderRepositoryService;
import com.yc.ship.module.trade.service.order.TradeOrderRuleValidate;
import com.yc.ship.module.trade.service.order.TradeOrderService;
import com.yc.ship.module.trade.service.ota.OtaService;
import com.yc.ship.module.trade.service.ota.XieChengService;
import com.yc.ship.module.trade.service.pay.TradeOrderPayService;
import com.yc.ship.module.trade.service.refund.TradeRefundRepositoryService;
import com.yc.ship.module.trade.service.refund.TradeRefundService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.module.trade.enums.ErrorCodeConstants.OTA_REQUEST_TIMEOUT;
import static com.yc.ship.module.trade.enums.ErrorCodeConstants.REFUND_AUDITING;
import static com.yc.ship.module.trade.enums.TravelhubDictTypeConstants.PRODUCT_BASE_TYPE_SELF;
import static com.yc.ship.module.trade.service.ota.OtaService.xieCheng;

/**
 * 携程
 *
 * @author le'yang
 */
@Service(xieCheng)
@Slf4j
public class XieChengServiceImpl implements XieChengService, OtaService {

    @Resource
    private OtaDistributorApi otaDistributorApi;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private ProductApi productApi;
    @Resource
    private TradeOrderService tradeOrderService;
    @Resource
    private TradeOrderRepositoryService tradeOrderRepositoryService;
    @Resource
    private TradeOrderPayService tradeOrderPayService;
    @Resource
    private XieChengService xieChengService;
    @Resource
    private TradeRefundService tradeRefundService;
    @Resource
    private NotifyLogService notifyLogService;
    @Resource
    private TradeRefundRepositoryService tradeRefundRepositoryService;

    /**
     * 携程，请求入口类
     */
    @Override
    public String doRequest(Long tenantId, String path, String data, HttpServletRequest request) {

        DistributorRespDTO distributor = null;
        try {
            TenantContextHolder.setTenantId(tenantId);
            TenantContextHolder.setIgnore(false);
            // JSON报文 转换
            JSONObject root = JSONUtil.parseObj(data);
            JSONObject header = root.getJSONObject("header");
            String bodyStrEncrypted = root.getStr("body");
            String ota_accountId = header.getStr("accountId");

            distributor = otaDistributorApi.getDistributorByOtaAccount(ota_accountId, "").getCheckedData();
            if (distributor == null) {
                return xieChengReturn("0003", "账户异常", distributor, null);
            }

            String key = "[ota-in]" + distributor.getId();
            RLock lock = redissonClient.getLock(key);
            try {
                if (lock.tryLock(30, 60, TimeUnit.SECONDS)) {
                    try {
                        // 签名认证
                        String secret = distributor.getSecret();
                        JSONObject secretJson = JSONUtil.parseObj(secret);
                        distributor.setAesSecret(secretJson.getStr("aesSecret"));
                        distributor.setAesVector(secretJson.getStr("aesVector"));
                        distributor.setMd5Secret(secretJson.getStr("md5Secret"));

                        if (!XieChengResolver.checkSign(header, bodyStrEncrypted, distributor.getMd5Secret())) {
                            return xieChengReturn("0002", "签名错误", distributor, null);
                        }

                        String method = header.getStr("serviceName");

                        String bodyStrDecrypted = AesUtil.decrypt(bodyStrEncrypted, distributor.getAesSecret(), distributor.getAesVector());
                        JSONObject body = JSONUtil.parseObj(bodyStrDecrypted);

                        if ("VerifyOrder".equalsIgnoreCase(method)) {
                            return this.verifyOrder(distributor, body);
                        } else if ("CreateOrder".equalsIgnoreCase(method)) {
                            return this.createOrder(distributor, body);
                        } else if ("CancelOrder".equalsIgnoreCase(method)) {
                            return this.cancelOrder(distributor, body, request);
                        } else if ("QueryOrder".equalsIgnoreCase(method)) {
                            return this.queryOrder(distributor, body, request);
                        }

                    } finally {
                        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                            lock.unlock();
                        }
                    }
                } else {
                    log.debug("未获取到锁");
                    throw exception(OTA_REQUEST_TIMEOUT);
                }
            } catch (Exception ex) {
                log.error("携程异常：", ex);
                throw ex;
            }

        } catch (ServerException e) {
            log.info("携程：请求参数-解析失败.");
            return xieChengReturn("0002", e.getMessage(), distributor, null);
        } catch (Exception e) {
            log.error("携程：", e);
            return xieChengReturn("0003", "签名错误", distributor, null);
        }
        return "";
    }

    /**
     * 校验订单
     */
    String verifyOrder(DistributorRespDTO distributor, JSONObject body) {
        try {
            JSONArray items = null;
            if (body.containsKey("items")) {
                items = body.getJSONArray("items");
            } else {
                return xieChengReturn("1006", "报文不正确,items必填!", distributor, null);
            }

            // 判断报文
            if (items == null || items.size() <= 0) {
                return xieChengReturn("1006", "报文不正确,items必填!", distributor, null);
            }

            // 判断多商品情况
            if (items.size() > 1) {
                return xieChengReturn("1006", "报文不正确,目前不支持一单多商品模式!", distributor, null);
            }

            // 获取商品信息
            JSONObject item = (JSONObject) items.get(0);
            JSONObject res_body = new JSONObject();
            res_body.set("inventory", "0");
            CommonResult<DistributorProductRespDTO> productResult = otaDistributorApi.getDistributorProductById(item.getLong("PLU"));
            if (productResult.isError()) {
                return xieChengReturn("1001", "产品不存在或已下架！", distributor, res_body);
            }
            DistributorProductRespDTO distributorProduct = productResult.getCheckedData();

            if (null == distributorProduct || distributorProduct.getIsUse() != 1) {
                return xieChengReturn("1001", "产品已经下架！", distributor, res_body);
            }
            // 售票规则验证购票方式(1:实名购票，3：无需实名)
            ProductSpuRespDTO productSpuRespDTO = productApi.getProduct(distributorProduct.getProductId()).getCheckedData();
            ProductSaleRuleRespDTO productSaleRule = productSpuRespDTO.getProductSaleRule();
            //判断是否有出行人
            JSONArray passengers = item.getJSONArray("passengers");
            if (productSaleRule != null && productSaleRule.getIsLimitType() == 1 && (passengers == null || passengers.size() == 0)) {
                return xieChengReturn("1005", "缺失出行人！", distributor, null);
            }
            //订单总数量
            int count = item.getInt("quantity");
            if (productSaleRule != null && productSaleRule.getIsLimitType() == 1 && passengers.size() != count) {
                return xieChengReturn("1005", "缺失出行人！", distributor, null);
            }

            for (Object o : passengers) {
                JSONObject passenger = (JSONObject) o;
                // 姓名
                String name = passenger.getStr("name");
                if (productSaleRule != null && productSaleRule.getIsLimitType() == 1 && StringUtils.isBlank(name)) {
                    return xieChengReturn("1005", "缺失出行人姓名！", distributor, null);
                }
                String cardNo = passenger.getStr("cardNo");
                if (productSaleRule != null && productSaleRule.getIsLimitType() == 1 && StringUtils.isBlank(cardNo)) {
                    return xieChengReturn("1005", "缺失证件！", distributor, null);
                }
            }

            //开始校验&订单是否存在&该渠道是否还有票&价格是否正确
            // 商品编号PLU
            Long productId = item.getLong("PLU");
            // 游玩开始日期 作为游玩日期
            String useDate = item.getStr("useStartDate");


            JSONArray itemss = new JSONArray();
            JSONObject it = new JSONObject();
            it.set("PLU", productId);
            JSONArray inventorys = new JSONArray();
            it.set("inventorys", inventorys);
            JSONObject dateInventory = new JSONObject();
            dateInventory.set("useDate", useDate);
            inventorys.add(dateInventory);
            itemss.add(it);

            TradeOrderCreateReqDTO order = this.parseOrder(body, distributor);
            //验证销售规则
            TradeOrderRuleValidate.checkSaleRule(order.getItemlList().get(0), productSpuRespDTO);
            return xieChengReturn("0000", "验证成功！", distributor, res_body);
        } catch (ServerException e) {
            log.error("分销{},{},{},{}", "携程", "verifyOrder", "", e.getMessage());
            return xieChengReturn(e.getCode().toString(), e.getMessage(), distributor, null);
        } catch (Exception e) {
            log.error("分销{},{},{},{}", "携程", "verifyOrder", "", e.getMessage());
            return xieChengReturn("0003", e.getMessage(), distributor, null);
        }
    }


    /**
     * 创建订单
     */
    String createOrder(DistributorRespDTO distributor, JSONObject body) {
        RLock lock = null;
        try {
            //封装下单
            TradeOrderCreateReqDTO order = this.parseOrder(body, distributor);

            String key = order.getExternalOrderNo() + distributor.getId();
            lock = redissonClient.getLock(key);
            if (lock.tryLock(10, 60, TimeUnit.SECONDS)) {
                //订单创建
                return xieChengService.savePayOrder(order.getExternalOrderNo(), order, true, distributor);

            } else {
                return xieChengReturn("1009", "重复提交", distributor, null);
            }
        } catch (ServerException e) {
            log.error("分销{},{},{},{}", "携程", "createOrder", body.getStr("otaOrderId"), e.getMessage());
            return xieChengReturn(e.getCode().toString(), e.getMessage(), distributor, null);
        } catch (Exception e) {
            log.error("分销{},{},{},{}", "携程", "createOrder", body.getStr("otaOrderId"), e.getMessage());
            return xieChengReturn("1100", "服务器端异常", distributor, null);
        } finally {
            if (null != lock && lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }


    /**
     * 带事务的创建订单
     */
    @Override
    public String savePayOrder(String otaOrderNo, TradeOrderCreateReqDTO order, boolean isPay, DistributorRespDTO distributor) {
        String orderNo;
        String msg;
        Long orderId;
        //重复验证
        TradeOrderDO tradeOrder = tradeOrderRepositoryService.getOrderByOtaAndExternalOrderNo(otaOrderNo, order.getOrderProperty().getSourceId());
        if (tradeOrder == null) {
            //创建订单
            CommonResult<TradeOrderRespDTO> result = tradeOrderService.createOrder(order);
            if (result.isError()) {
                return xieChengReturn("1103", result.getMsg(), distributor, null);
            }
            TradeOrderRespDTO tradeOrderRespDTO = result.getCheckedData();
            //支付订单
            if (isPay) {
                PayOrderReqVO payOrderReqVO = new PayOrderReqVO();
                payOrderReqVO.setAccountId(distributor.getId().toString());
                //ota
                payOrderReqVO.setAccountType(PayAccountTypeEnum.OTA.getType());

                payOrderReqVO.setOrderId(tradeOrderRespDTO.getOrderId());
                payOrderReqVO.setPayAmount(order.getPayAmount());
                //预付款>授信
                Object[] payTypes = distributor.getPayType().split(",");
                if (CollectionUtils.containsAny("1", payTypes)) {
                    payOrderReqVO.setPayType(PayTypeEnum.ADVANCE_PAYMENT.getType());
                } else if (CollectionUtils.containsAny("2", payTypes)) {
                    payOrderReqVO.setPayType(PayTypeEnum.CREDIT_GRANTING.getType());
                }
                //统一支付、扣款、修改订单状态
                CommonResult<PayOrderRespVO> payResult = tradeOrderPayService.payOrder(payOrderReqVO);
                if (payResult.isError()) {
                    return xieChengReturn("1104", payResult.getMsg(), distributor, null);
                }
            }
            msg = "创建订单成功！";
            orderNo = tradeOrderRespDTO.getOrderNo();
            orderId = tradeOrderRespDTO.getOrderId();
            // 如果订单未支付
        } else if (ObjectUtil.equals(tradeOrder.getOrderStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) {
            msg = "订单状态为待付款(未扣余额)";
            return xieChengReturn("1101", msg, distributor, null);
            // 如果订单已过期
        } else if (ObjectUtil.equals(tradeOrder.getOrderStatus(), TradeOrderStatusEnum.EXPIRED.getStatus())) {
            msg = "订单状态为已过期";
            return xieChengReturn("1102", msg, distributor, null);
        } else {
            msg = "订单已存在！";
            orderNo = tradeOrder.getOrderNo();
            orderId = tradeOrder.getId();
        }
        JSONObject resBody = new JSONObject();
//        res_body.put("inventory", String.valueOf(inventory));//剩余票数
        resBody.set("otaOrderId", otaOrderNo);
        resBody.set("supplierOrderId", orderNo);
        // 1.新订已确认（当confirmType =1/2时可同步返回确认结果）
        // 2.新订待确认（当confirmType =2时需异步返回确认结果的）
        resBody.set("supplierConfirmType", "1");
        // 凭证发送方 1.携程发送凭证 2.供应商发送凭证
        resBody.set("voucherSender", "1");
        // 凭证集合节点 当supplierConfirmType=1时可返回值；当supplierConfirmType=2时不返回值；
        JSONArray vouchers = new JSONArray();
        //出行人凭证关系节点
        JSONArray passengerVouchers = new JSONArray();
        List<TradeDetailDO> detailDOList = tradeOrderRepositoryService.queryDetailByOrderId(orderId);
        for (TradeDetailDO tradeDetail : detailDOList) {
            JSONObject voucher = new JSONObject();
            voucher.set("itemId", order.getItemId());
            // 凭证形式
            voucher.set("voucherType", 3);
            voucher.set("voucherCode", tradeDetail.getVoucherCode());
            voucher.set("voucherData", tradeDetail.getVoucherCode());
            String passengerId = "";
            List<TradeVisitorDO> visitorList = tradeOrderRepositoryService.queryVisitorByDetailId(tradeDetail.getId());
            if (CollUtil.isNotEmpty(visitorList)) {
                passengerId = visitorList.get(0).getOtaDetailId();
            }
            // 出行人编号非空时
            if (StringUtils.isNotBlank(passengerId)) {
                // 票号
                voucher.set("voucherId", tradeDetail.getVoucherCode());
                JSONObject passengerVoucher = new JSONObject();
                // 出行人编号
                passengerVoucher.set("passengerId", passengerId);
                // 凭证编号
                passengerVoucher.set("voucherId", tradeDetail.getVoucherCode());
                // 添加
                passengerVouchers.add(passengerVoucher);
            }
            vouchers.add(voucher);
        }
        resBody.set("vouchers", vouchers);
        // 出行人凭证关系节点非空
        if (CollectionUtil.isNotEmpty(passengerVouchers)) {
            JSONArray itemsJsonArray = new JSONArray();
            JSONObject itemJsonObject = new JSONObject();
            itemJsonObject.set("itemId", order.getItemId());
            // 是否出行人与凭证有关联关系 相关：isCredentialVouchers=1 不相关：isCredentialVouchers=0
            itemJsonObject.set("isCredentialVouchers", 1);
            // 出行人凭证关系节点
            itemJsonObject.set("passengerVouchers", passengerVouchers);
            // 添加
            itemsJsonArray.add(itemJsonObject);
            resBody.set("items", itemsJsonArray);
        }
        return xieChengReturn("0000", msg, distributor, resBody);
    }

    /**
     * 封装下单
     */
    private TradeOrderCreateReqDTO parseOrder(JSONObject body, DistributorRespDTO distributor) throws Exception {
        // log.debug("携程开始下单：" + body.toString());
        Long distributorId = distributor.getId();
        List<TradeOrderCreateReqDTO.OrderItem> itemlList = new ArrayList<>();
        List<TradeOrderCreateReqDTO.OrderDetail> detailList = new ArrayList<>();
        //获取订单基础信息，未保存扩展信息
        // OTA订单号
        String otaOrderId = body.getStr("otaOrderId");
        //String sequenceId = body.getString("sequenceId");

        // 联系人信息
        JSONArray contacts;
        if (body.containsKey("contacts")) {
            contacts = body.getJSONArray("contacts");
        } else {
            throw new ServerException(1006, "报文不正确,contacts必填！");
        }
        // 联系人不能为空
        if (contacts == null || contacts.isEmpty()) {
            throw new ServerException(1006, "报文不正确,contacts必填！");
        }

        // 只获取第一个联系人
        JSONObject contact = contacts.getJSONObject(0);
        //联系人（取件人）姓名，需要支持中/英文
        String contactName = contact.getStr("name");
        //联系人（取件人）手机号
        String contactMobile = contact.getStr("mobile");
        //联系人（取件人）邮箱地址，不需要
        String contactEmail = contact.getStr("email");

        // 商品信息
        JSONArray items;
        if (body.containsKey("items")) {
            items = body.getJSONArray("items");
        } else {
            // throw new RRException("报文不正确,items必填！");
            throw new ServerException(1006, "报文不正确,items必填！");
        }
        // 判断报文
        if (items == null || items.size() <= 0) {
            // throw new RRException("报文不正确,items必填！");
            throw new ServerException(1006, "报文不正确,items必填！");
        }
        // 判断多商品情况
        if (items.size() > 1) {
            // throw new RRException("报文不正确,目前不支持一单多商品模式！");
            throw new ServerException(1006, "报文不正确,目前不支持一单多商品模式！");
        }

        // 商品信息 只获取第一个商品
        JSONObject item = (JSONObject) items.get(0);
        //产品Id
        Long distributorProductId = item.getLong("PLU");
        // 卖价单位：元
        BigDecimal price = item.getBigDecimal("price");
        //订单总数量
        int count = item.getInt("quantity");
        Date travelDate = item.getDate("useStartDate");

        TradeOrderCreateReqDTO order = new TradeOrderCreateReqDTO();
        // 订单项编号
        order.setItemId(item.getStr("itemId"));
        order.setExternalOrderNo(otaOrderId);
        order.setTravelDate(travelDate);

        CommonResult<DistributorProductRespDTO> productResult = otaDistributorApi.getDistributorProductById(distributorProductId);
        if (productResult.isError()) {
            throw new ServerException(1001, "产品不存在或已下架！");
        }
        DistributorProductRespDTO distributorProduct = productResult.getCheckedData();

        ProductSpuRespDTO productSpuRespDTO = productApi.getProduct(distributorProduct.getProductId()).getCheckedData();

        TradeOrderCreateReqDTO.OrderProperty orderProperty = OtaConvert.INSTANCE.convert(distributorId.toString(), distributor.getName());
        order.setOrderProperty(orderProperty);
        order.setRoutePlanId(distributorProduct.getRoutePlanId());
        if (distributorProduct.getIsUse() != 1) {
            throw new ServerException(1001, "产品已经下架！");
        }
        // 单位:元
        BigDecimal ticketPrice = distributorProduct.getSalePrice();

        if (ticketPrice != null) {
            BigDecimal orderAmt = ticketPrice.multiply(new BigDecimal(count));
            order.setAmount(orderAmt);
            order.setPayAmount(orderAmt);
        }
        TradeOrderCreateReqDTO.OrderItem orderItem = new TradeOrderCreateReqDTO.OrderItem();
        orderItem.setProductId(distributorProduct.getProductId().toString());
        orderItem.setProductType(PRODUCT_BASE_TYPE_SELF);
        orderItem.setUseDate(travelDate);

        List<DistributorProductRespDTO.DistributorProjectDTO> distributorProjectDTOS = otaDistributorApi.getProductByDistributor(distributor.getId(), distributorProduct.getProductId(), distributorProduct.getId()).getCheckedData();
        TradeOrderCreateReqDTO.OrderDetail orderDetail = OtaConvert.INSTANCE.convert(distributorProduct, count, distributorProjectDTOS, ticketPrice);

        List<TradeOrderCreateReqDTO.Visitor> visitors = new ArrayList<>();
        JSONArray passengers;
        // 售票规则验证购票方式(1:实名购票，3：无需实名)
        ProductSaleRuleRespDTO productSaleRule = productSpuRespDTO.getProductSaleRule();
        if (productSaleRule != null && productSaleRule.getIsLimitType() == 1 && item.containsKey("passengers") && item.getJSONArray("passengers").size() > 0) {
            passengers = item.getJSONArray("passengers");
            for (Object p : passengers) {
                JSONObject passenger = (JSONObject) p;
                TradeOrderCreateReqDTO.Visitor visitor = new TradeOrderCreateReqDTO.Visitor();
                // 出行人手机号
                String dMobile = passenger.getStr("mobile");
                //出行人证件号，可空，实名制产品必传
                visitor.setCredentialNo(passenger.getStr("cardNo"));
                // 出行人证件类型，默认身份证，具体定义参见附录4.2

                visitor.setCredentialType(this.changeCertificateType(passenger.getStr("cardType")));
                // 出行人姓名，需要支持中/英文
                visitor.setName(passenger.getStr("name"));
                visitor.setOtaDetailId(passenger.getStr("passengerId"));
                if (StringUtils.isEmpty(visitor.getCredentialNo())) {
                    // log.info("携程：创建订单：游客身份证为空不能下单.");
                    // throw new RRException("游客身份证为空不能下单！");
                    throw new ServerException(1006, "游客身份证为空不能下单！");
                }
                visitors.add(visitor);
            }
        } else if (productSaleRule != null && productSaleRule.getIsLimitType() == 0) {
            // throw new RRException("本商品为实名制商品，出行人必填！");
            // 非实名制购票
            if (item.containsKey("passengers") && !item.getJSONArray("passengers").isEmpty() && count == item.getJSONArray("passengers").size()) {
                passengers = item.getJSONArray("passengers");
                for (Object p : passengers) {
                    JSONObject passenger = (JSONObject) p;
                    TradeOrderCreateReqDTO.Visitor visitor = new TradeOrderCreateReqDTO.Visitor();
                    // 出行人手机号
                    String dMobile = passenger.getStr("mobile");
                    //出行人证件号，可空，实名制产品必传
                    visitor.setCredentialNo(passenger.getStr("cardNo"));
                    // 出行人证件类型，默认身份证，具体定义参见附录4.2
                    visitor.setCredentialType(this.changeCertificateType(passenger.getStr("cardType")));
                    // 出行人姓名，需要支持中/英文
                    visitor.setName(passenger.getStr("name"));
                    visitor.setOtaDetailId(passenger.getStr("passengerId"));
                    visitors.add(visitor);
                }
            } else {
                visitors = OtaConvert.INSTANCE.convertOtaVisitorList(count);
            }
        }
        // 缺少出行人返回信息
        if (productSaleRule != null && productSaleRule.getIsLimitType() == 1 && orderDetail.getCount() != visitors.size()) {
            // throw new RRException("本商品为实名制商品，出行人必填！");
            throw new ServerException(1006, "本商品为实名制商品，出行人必填！");
        }
        //联系人
        TradeOrderCreateReqDTO.OrderUser orderUser = new TradeOrderCreateReqDTO.OrderUser();
        orderUser.setCredentialType(0);
        orderUser.setMobile(contactMobile);
        orderUser.setContactName(contactName);
        orderUser.setCredentialNo("");
        order.setOrderUser(orderUser);

        orderDetail.setVisitorList(visitors);
        detailList.add(orderDetail);
        orderItem.setDetailList(detailList);
        itemlList.add(orderItem);
        order.setItemlList(itemlList);
        return order;
    }


    /**
     * 退单
     *
     * @param body
     * @return
     */
    String cancelOrder(DistributorRespDTO distributor, JSONObject body, HttpServletRequest request) {
        JSONObject res_body = new JSONObject();
        // 1.取消已确认 2.取消待确认（当confirmType =2时需异步返回确认结果的）
        res_body.put("supplierConfirmType", 1);
        RLock lock = null;
        try {
            //2、获取参数
            // 获取参数
            // 基础参数
            String otaOrderId = body.getStr("otaOrderId");
            String orderNo = body.getStr("supplierOrderId");
            String sequenceId = body.getStr("sequenceId");

            // 商品信息
            JSONArray items;
            if (body.containsKey("items")) {
                items = body.getJSONArray("items");
            } else {

                return xieChengReturn("1006", "报文不正确,items必填!", distributor, res_body);
            }
            // 判断报文
            if (items == null || items.size() <= 0) {
                return xieChengReturn("1006", "报文不正确,items必填!", distributor, res_body);
            }
            // 判断多商品情况
            if (items.size() > 1) {
                return xieChengReturn("1006", "报文不正确,目前不支持一单多商品模式!", distributor, res_body);
            }

            // 商品信息 只获取第一个商品
            JSONObject item = (JSONObject) items.get(0);

            // 产品Id
            String ticketTypeId = item.getStr("PLU");
            // 取消数量
            int cancelCount = item.getInt("quantity");
            // 获取订单信息
            TradeOrderDO order = tradeOrderRepositoryService.getOrderByNo(orderNo);
            // 获取订单退票数
            Map<String, Object> ticketMap = tradeOrderRepositoryService.queryDetailCountByOrderId(order.getId());
            List<TradeDetailDO> detailDOList = tradeOrderRepositoryService.queryDetailByOrderId(order.getId());
            // 订单退票数
            int refundCount = MapUtil.getInt(ticketMap, "refundCount");
            // 订单已退票数量 == 总数量
            if (refundCount == detailDOList.size()) {
                JSONArray itemsArray = new JSONArray();
                JSONObject itemObject = new JSONObject();
                // 订单项编号
                itemObject.put("itemId", item.getStr("itemId"));
                itemsArray.add(itemObject);
                res_body.put("items", itemsArray);
                return xieChengReturn("0000", "该订单已全部退款", distributor, res_body);
            }
            int checkCount = MapUtil.getInt(ticketMap, "checkCount");
            int partCount = MapUtil.getInt(ticketMap, "partCount", 0);
            int outTimeCount = MapUtil.getInt(ticketMap, "outTimeCount");
            int useCount = checkCount + partCount + outTimeCount;
            // 订单门票使用数量 == 总数量
            if (useCount == detailDOList.size()) {
                return xieChengReturn("2002", "该订单已消费", distributor, res_body);
            }
            Long effectyCount = tradeOrderRepositoryService.queryEffectyCount(order.getId());
            if (effectyCount == 0) {
                return xieChengReturn("2001", "该订单无可退门票", distributor, res_body);
            }
            if (order == null || !order.getExternalOrderNo().equals(otaOrderId)) {
                return xieChengReturn("2001", "订单不存在", distributor, res_body);
            }
            if (cancelCount < 1 || cancelCount > detailDOList.size()) {
                return xieChengReturn("2004", "取消数量不正确", distributor, res_body);
            }
            if (effectyCount < cancelCount) {
                return xieChengReturn("2005", "申请张数与可退票张数数量不等", distributor, res_body);
            }
            List<Long> tradeDetailList = new ArrayList<>();
            // 0、全退,1、按份数部分退,2、按出行人部分退
            Integer cancelType = item.getInt("cancelType");
            // 订单项节点
            JSONArray itemsJsonArray = new JSONArray();
            Integer isForceRefund = 0;
            String forceRefund = body.getStr("isForceRefund");
            if (StringUtils.isNotEmpty(forceRefund)) {
                isForceRefund = Integer.valueOf(forceRefund);
            }
            TradeRefundCreateReqDTO refundCreateReqDTO = TradeRefundConvert.INSTANCE.convertOtaRefund(order.getId(), distributor.getId(), isForceRefund, sequenceId);
            refundCreateReqDTO.setRefundAmount(order.getPayAmount());
            if (cancelType == 2) {
                //判断是否有出行人
                JSONArray passengers = item.getJSONArray("passengers");
                if (passengers == null || passengers.size() == 0) {
                    return xieChengReturn("1005", "缺失出行人！", distributor, null);
                }
                if (passengers.size() != cancelCount) {
                    return xieChengReturn("2004", "取消数量不正确！", distributor, null);
                }
                // 凭证节点
                JSONArray vouchers = new JSONArray();
                // 获取可退门票
                int refund_count = 0;

                List<TradeRefundCreateReqDTO.RefundItem> refundItemList = new ArrayList<>();
                //根据出行人编号查询门票
                BigDecimal refundAmt = BigDecimal.ZERO;
                for (Object p : passengers) {
                    JSONObject passenger = (JSONObject) p;
                    String passengerId = passenger.getStr("passengerId");
                    if (StringUtils.isBlank(passengerId)) {
                        return xieChengReturn("1005", "缺失出行人编号！", distributor, null);
                    }
                    TradeDetailDO tradeDetail = tradeOrderRepositoryService.queryByOrderIdAndPassengerId(order.getId(), passengerId);
                    if (tradeDetail != null) {
                        tradeDetailList.add(tradeDetail.getId());
                    } else {
                        return xieChengReturn("1005", "未查询到出行人、编号：" + passengerId + "！", distributor, null);
                    }
                    JSONObject voucher = new JSONObject();
                    // 凭证编号
                    voucher.put("voucherId", tradeDetail.getVoucherCode());
                    vouchers.add(voucher);
                    //验证门票是否可退：初始状态，1待使用，2已取票，3已核销，4退款中,5已退票，6逾期核销,7已过期
                    if (tradeDetail.getVoucherStatus() > 0 && tradeDetail.getVoucherStatus() < 3) {
                        TradeRefundCreateReqDTO.RefundItem refundItem = TradeRefundConvert.INSTANCE.convertRefundItem(tradeDetail.getActualPrice(), order.getId(), tradeDetail.getId(), tradeDetail.getVoucherCode());
                        refundItemList.add(refundItem);
                        refundAmt = refundAmt.add(tradeDetail.getActualPrice());
                    } else if (tradeDetail.getVoucherStatus() == 5) {
                        refund_count += 1;
                    }
                }

                if (CollectionUtil.isNotEmpty(vouchers)) {
                    JSONObject itemJsonObject = new JSONObject();
                    // 订单项编号
                    itemJsonObject.put("itemId", item.getStr("itemId"));
                    itemJsonObject.put("vouchers", vouchers);
                    itemsJsonArray.add(itemJsonObject);
                }

                if (refundItemList.size() == 0 && cancelCount == refund_count) {
                    JSONArray itemsArray = new JSONArray();
                    if (CollectionUtil.isNotEmpty(itemsJsonArray)) {
                        res_body.put("items", itemsJsonArray);
                    } else {
                        JSONObject itemObject = new JSONObject();
                        // 订单项编号
                        itemObject.put("itemId", item.getStr("itemId"));
                        itemsArray.add(itemObject);
                        res_body.put("items", itemsArray);
                    }
                    return xieChengReturn("0000", "订单已退票成功", distributor, res_body);
                } else if (refundItemList.size() != cancelCount) {
                    return xieChengReturn("2002", "申请张数与可退票张数数量不等", distributor, res_body);
                }
                refundCreateReqDTO.setRefundAmount(refundAmt);
                refundCreateReqDTO.setItemlList(refundItemList);
            }

            lock = redissonClient.getLock(orderNo + distributor.getId());
            if (lock.tryLock(20, 60, TimeUnit.SECONDS)) {
                // 操作成功
                String resultCode = "0000";
                String resultMessage = "操作成功";
                RefundDO refund = tradeRefundRepositoryService.getRefundByOatNoAndOrder(sequenceId, order.getId());
                if (refund == null) {
                    CommonResult<TradeRefundRespDTO> refundResult = tradeRefundService.refund(refundCreateReqDTO);
                    if (refundResult.isSuccess()) {
                        res_body.put("supplierConfirmType", 1);
                    } else if (refundResult.getCode().equals(REFUND_AUDITING.getCode())) {
                        // 1.取消已确认 2.取消待确认（当confirmType =2时需异步返回确认结果的）
                        res_body.put("supplierConfirmType", 2);
                    } else {
                        throw new ServerException(2001, refundResult.getMsg());
                    }
                } else if (Objects.equals(refund.getRefundStatus(), RefundStatusEnum.AUDITING.getStatus())) {
                    res_body.put("supplierConfirmType", 2);
                } else if (Objects.equals(refund.getRefundStatus(), RefundStatusEnum.PASS.getStatus())) {
                    res_body.put("supplierConfirmType", 1);
                } else {
                    res_body.put("supplierConfirmType", 1);
                    resultCode = "2100";
                    resultMessage = RefundStatusEnum.getRefundNameByStatus(refund.getRefundStatus());
                }


                JSONArray itemsArray = new JSONArray();
                if (CollectionUtil.isNotEmpty(itemsJsonArray)) {
                    res_body.put("items", itemsJsonArray);
                } else {
                    JSONObject itemObject = new JSONObject();
                    // 订单项编号
                    itemObject.put("itemId", item.getStr("itemId"));
                    itemsArray.add(itemObject);
                    res_body.put("items", itemsArray);
                }
                return xieChengReturn(resultCode, resultMessage, distributor, res_body);
            } else {
                return xieChengReturn("2001", "重复提交", distributor, res_body);
            }
        } catch (ServerException ex) {
            return xieChengReturn("2001", ex.getMessage(), distributor, res_body);
        } catch (Exception ex) {
            log.error("分销{},{},{},{}", "携程退票申请异常", "cancelOrder", body.getStr("otaOrderId"), ex.getMessage());
            return xieChengReturn("2001", "分销退票申请异常", distributor, res_body);
        } finally {
            if (null != lock && lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 检查门票是否可退
     *
     * @return
     */
    private String checkRefund(TradeDetailDO detailDO) {
        Long productId = detailDO.getProductId();
        ProductSpuRespDTO productSpu = productApi.getProduct(productId).getCheckedData();
        ProductRefundRuleRespDTO refundRule = productSpu.getProductRefundRule();
        if (refundRule.getRefundRule() != 0) {

            if (refundRule != null) {
                //过期后是否可退
//                if (refundRule.getIsOverdueRefund() == 0) {
//                    if (ticket.getTicketEndDate().compareTo(new Date()) < 0) {
//                        //已过期不可退
//                        return "已过期不可退";
//                    }
//                }
//                //取票后是否可退
//                if (refundRule.getIsRejectRefund() == 0 && ticket.getTakeStatus() == 1) {
//                    //已取票不可退
//                    return "已取票不可退";
//                }
//                //是否可部分退票
//                if (refundRule.getIsPartRefund() == 0 && ticket.getTicketStatus() == 3) {
//                    //已检票不可退
//                    return "已检票不可退";
//                }
            }
            //查询子票
        }
        return "";
    }

    /**
     * 订单查询
     *
     * @param body
     * @return
     */
    String queryOrder(DistributorRespDTO distributor, JSONObject body, HttpServletRequest request) {
        //OTA订单号
        String otaOrderNo = body.getStr("otaOrderId");
        //供应商订单号
        String orderNo = body.getStr("supplierOrderId");
        TradeOrderDO order = tradeOrderRepositoryService.getOrderByNo(orderNo);
        if (order == null || !order.getExternalOrderNo().equals(otaOrderNo)) {
            return xieChengReturn("4001", "订单号错误", distributor, null);
        }

        Map ticketCount = tradeOrderRepositoryService.queryDetailCountByOrderId(order.getId());
        //解析数据
        int status = 0;
        Integer useCount = MapUtil.getInt(ticketCount, "checkCount", 0) + MapUtil.getInt(ticketCount, "partCount", 0) + MapUtil.getInt(ticketCount, "outTimeCount", 0);
        Integer cancelCount = MapUtil.getInt(ticketCount, "refundCount", 0);
        // 新订单
        if (order.getOrderStatus() == 0) {
            status = 1;
            //已出票
        } else if (ObjectUtil.equals(order.getOrderStatus(), TradeOrderStatusEnum.UNUSED.getStatus())) {
            status = 2;
            // 部分取消
            if (cancelCount > 0) {
                status = 4;
                // 部分使用
            } else if (useCount > 0) {
                status = 7;
            }
            // 部分取消
        } else if (ObjectUtil.equals(order.getOrderStatus(), TradeOrderStatusEnum.PARTIAL_REFUND.getStatus())) {
            status = 4;
            // 全部取消
        } else if (ObjectUtil.equals(order.getOrderStatus(), TradeOrderStatusEnum.ALL_REFUND.getStatus())) {
            status = 5;
            // 已验证、已返码
        } else if (ObjectUtil.equals(order.getOrderStatus(), TradeOrderStatusEnum.PART_CHECK.getStatus())) {
            status = 7;
        } else if (ObjectUtil.equals(order.getOrderStatus(), TradeOrderStatusEnum.ALL_CHECK.getStatus())) {
            status = 8;
        } else if (ObjectUtil.equals(order.getOrderStatus(), TradeOrderStatusEnum.EXPIRED.getStatus())) {
            status = 10;
        }
        String sequenceId = body.getStr("sequenceId");
        RefundDO refund = tradeRefundRepositoryService.getRefundByOatNoAndOrder(sequenceId, order.getId());

        boolean auditStatusIngFlag = refund != null && ObjectUtil.equals(refund.getRefundStatus(), RefundStatusEnum.AUDITING.getStatus());
        // 订单状态:待审核
        if (auditStatusIngFlag) {
            // 3取消待确认
            status = 3;
        }
        List<TradeDetailDO> detailDOList = tradeOrderRepositoryService.queryDetailByOrderId(order.getId());
        TradeDetailDO detailDO = null;
        // 出行人节点
        JSONArray passengers = new JSONArray();
        // 凭证节点
        JSONArray vouchers = new JSONArray();

        //返回数据
        // body
        JSONObject res_body = new JSONObject();
        res_body.put("otaOrderId", otaOrderNo);
        res_body.put("supplierOrderId", orderNo);

        JSONArray itemsResp = new JSONArray();
        JSONObject itemResp = new JSONObject();
        itemResp.put("itemId", order.getItemId());

        itemResp.put("orderStatus", status);
        itemResp.put("quantity", detailDOList.size());
        itemResp.put("useQuantity", useCount);
        itemResp.put("cancelQuantity", cancelCount);

        if (CollUtil.isNotEmpty(detailDOList)) {
            detailDO = detailDOList.get(0);
            for (TradeDetailDO tradeDetailDO : detailDOList) {
                String passengerId = "";
                List<TradeVisitorDO> visitors = tradeOrderRepositoryService.queryVisitorByDetailId(tradeDetailDO.getId());
                if (visitors != null && visitors.size() > 0) {
                    passengerId = visitors.get(0).getOtaDetailId();
                }
                // 出行人编号非空
                if (StringUtils.isNotBlank(passengerId)) {
                    JSONObject passenger = new JSONObject();
                    // 出行人编号
                    passenger.put("passengerId", passengerId);
                    JSONObject voucher = new JSONObject();
                    // 凭证编号
                    voucher.put("voucherId", tradeDetailDO.getVoucherCode());

                    // 0、待使用；1、已使用；2、已取消
                    if (tradeDetailDO.getVoucherStatus().equals(VoucherStatusEnum.UNUSED.getStatus()) || tradeDetailDO.getVoucherStatus().equals(VoucherStatusEnum.TOOK.getStatus())) {
                        passenger.put("passengerStatus", 0);
                        voucher.put("voucherStatus", 0);
                    } else if (tradeDetailDO.getVoucherStatus().equals(VoucherStatusEnum.VERIFIED.getStatus()) || tradeDetailDO.getVoucherStatus().equals(VoucherStatusEnum.OVERDUE_VERIFIED.getStatus())) {
                        passenger.put("passengerStatus", 1);
                        voucher.put("voucherStatus", 1);
                    } else if (tradeDetailDO.getVoucherStatus().equals(VoucherStatusEnum.REFUNDING.getStatus())
                            || ObjectUtil.equals(tradeDetailDO.getVoucherStatus(), VoucherStatusEnum.PART_REFUND.getStatus())
                            || tradeDetailDO.getVoucherStatus().equals(VoucherStatusEnum.REFUND.getStatus())) {
                        passenger.put("passengerStatus", 2);
                        voucher.put("voucherStatus", 2);
                    }
                    passengers.add(passenger);
                    vouchers.add(voucher);
                }
            }
            if (CollectionUtil.isNotEmpty(passengers)) {
                itemResp.put("passengers", passengers);
                itemResp.put("vouchers", vouchers);
            }
        }
        String useStartDate = "";
        String useEndDate = "";
        if (detailDO != null) {
            if (detailDO.getValidityStartDate() != null) {
                useStartDate = LocalDateTimeUtil.format(detailDO.getValidityStartDate(), DatePattern.NORM_DATE_FORMATTER);
            }
            if (detailDO.getValidityEndDate() != null) {
                useEndDate = LocalDateTimeUtil.format(detailDO.getValidityEndDate(), DatePattern.NORM_DATE_FORMATTER);
            }
        }
        itemResp.put("useStartDate", useStartDate);
        itemResp.put("useEndDate", useEndDate);

        itemsResp.add(itemResp);
        res_body.put("items", itemsResp);
        return xieChengReturn("0000", "查询成功", distributor, res_body);
    }

    /**
     * 订单消费通知
     */
    @Override
    public boolean consumeNotice(DistributorRespDTO distributor, Map<String, Object> map) {
        String orderNo = MapUtil.getStr(map, "orderNo");
        Long orderId = MapUtil.getLong(map, "orderId");


        Map<String, Object> ticketMap = tradeOrderRepositoryService.queryDetailCountByOrderId(orderId);
        int checkCount = MapUtil.getInt(ticketMap, "checkCount");
        int partCount = MapUtil.getInt(ticketMap, "partCount", 0);
        int outTimeCount = MapUtil.getInt(ticketMap, "outTimeCount");
        int useCount = checkCount + partCount + outTimeCount;
        String sendUrl = "";
        String param = "";
        try {
            List<TradeDetailDO> detailDOList = tradeOrderRepositoryService.queryDetailByOrderId(orderId);
            int totalTicket = detailDOList.size();
            //数据处理
            //已入园
            //返回数据
            JSONObject res_body = new JSONObject();
            res_body.put("otaOrderId", MapUtil.getStr(map, "external_order_no"));
            res_body.put("supplierOrderId", MapUtil.getStr(map, "orderNo"));
            res_body.put("sequenceId", new SimpleDateFormat("yyyyMMdd").format(new Date()) + UUID.randomUUID().toString().replace("-", ""));
            JSONArray items = new JSONArray();
            JSONObject item = new JSONObject();
            item.put("itemId", MapUtil.getStr(map, "item_id"));
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            String useStartDate = DateUtil.format(MapUtil.getDate(map, "ticketStartDate"), DatePattern.NORM_DATE_PATTERN);
            String useEndDate = DateUtil.format(MapUtil.getDate(map, "ticketEndDate"), DatePattern.NORM_DATE_PATTERN);
            item.put("useStartDate", useStartDate);
            item.put("useEndDate", useEndDate);
            item.put("quantity", totalTicket);
            item.put("useQuantity", useCount);

            // 已核销的份数所对应的出行人
            JSONArray passengers = new JSONArray();
            // 已核销的份数所对应的凭证
            JSONArray vouchers = new JSONArray();
            for (TradeDetailDO detailDO : detailDOList) {
                //0初始状态，1待使用，2已取票，3已核销，4退款中,5已退票，6逾期核销,7已过期
                if (detailDO.getVoucherStatus() == 3 || detailDO.getVoucherStatus() == 6) {
                    List<TradeVisitorDO> visitors = tradeOrderRepositoryService.queryVisitorByDetailId(detailDO.getId());
                    if (visitors != null && visitors.size() > 0) {
                        String passengerId = visitors.get(0).getOtaDetailId();
                        if (StringUtils.isNotBlank(passengerId)) {
                            JSONObject passenger = new JSONObject();
                            // 出行人编号
                            passenger.put("passengerId", passengerId);
                            passengers.add(passenger);

                            JSONObject voucher = new JSONObject();
                            // 凭证编号
                            voucher.put("voucherId", detailDO.getVoucherCode());
                            vouchers.add(voucher);
                        }
                    }
                }
            }
            if (CollectionUtil.isNotEmpty(passengers)) {
                item.put("passengers", passengers);
                item.put("vouchers", vouchers);
            }

            item.put("remark", "");
            items.add(item);
            res_body.put("items", items);
            res_body.put("itemId", MapUtil.getStr(map, "item_id"));
            //String json = res_body.toJSONString();
            // 发送请求
            Map<String, String> headMap = new HashMap<String, String>(0);
            headMap.put("Content-Type", "application/json;charset=utf-8");
            // 发送请求
            String serviceName = "OrderConsumedNotice";
            String secret = distributor.getSecret();
            JSONObject secretJson = JSONUtil.parseObj(secret);
            String aesSecret = secretJson.getStr("aesSecret");
            String aesVector = secretJson.getStr("aesVector");
            String md5Secret = secretJson.getStr("md5Secret");
            //String param = XieChengJsonV3equest.create(distributor.getZhName(), , md5Secret, , aesVector, res_body);
            JSONObject root = new JSONObject();
            JSONObject header = new JSONObject();
            //header
            header.put("accountId", distributor.getAppid());
            header.put("serviceName", serviceName);
            SimpleDateFormat format2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String requestTime = format2.format(new Date());
            header.put("requestTime", requestTime);
            String version = "1.0";
            header.put("version", version);
            String strBody = res_body.toString();
            // log.info("---通知携程---入参-- strBody:" + strBody);
            // 加密body
            if (res_body != null && res_body.size() > 0) {
                // 加密body报文
                strBody = AesUtil.encrypt(strBody, aesSecret, aesVector);
                root.put("body", strBody);
            }
            // 签名 使用加密后的报文签名
            //String sign = XieChengJsonV3Resolver.sign(header, strBody, userKey);
            String waitSignString = distributor.getAppid() + serviceName + requestTime + strBody + version + md5Secret;
            String usSign = Md5.getMD5(waitSignString.getBytes("UTF-8"));
            header.put("sign", usSign);

            root.put("header", header);
            sendUrl = distributor.getServerUrl();
            param = root.toString();
            log.info("---通知第三方---start-- orderNo:" + orderNo + " [ param ]：" + param);
            String sendResult = HttpUtil.createPost(sendUrl).contentType("application/json")
                    .headerMap(headMap, false)
                    .body(param)
                    .timeout(15000)
                    .execute().body();
            log.info("---通知第三方---end-- orderNo:" + orderNo + " [ sendResult ]：" + sendResult);
            // JSON报文 转换
            JSONObject resultJson = JSONUtil.parseObj(sendResult);
            JSONObject headerJson = resultJson.getJSONObject("header");
            if (header != null && "0000".equals(headerJson.getStr("resultCode"))) {
                //记录消费通知
                notifyLogService.saveNotifyLog(map, sendUrl, param, sendResult, 1);
                return true;
            } else {
                //如果失败需要加入至定时任务
                log.error("分销{},{},{},{}", "携程消费通知失败", "consumeNotice", orderNo, headerJson.getStr("resultMessage"));
                notifyLogService.saveNotifyLog(map, sendUrl, param, sendResult, 0);
                return false;
            }
        } catch (Exception ex) {
            //记录消费通知
            notifyLogService.saveNotifyLog(map, sendUrl, param, ex.getMessage(), 0);
            log.error("分销{},{},{},{}", "携程消费通知失败", "consumeNotice", orderNo, ex.getMessage());
        }
        return false;
    }

    /**
     * @param map 参数
     * @return boolean
     * @description 退票结果异步通知携程
     * @author 杨涛
     * @date 2025/11/17 15:40
     */
    @Override
    public boolean refundNotice(DistributorRespDTO distributor, Map<String, Object> map) {
        String sendUrl = "";
        String param = "";
        String orderNo = MapUtil.getStr(map, "order_no");
        String refundNo = MapUtil.getStr(map, "refund_id");
        map.put("pid", orderNo);
        map.put("ticket_no", refundNo);
        try {
            // 返回数据
            JSONObject resBody = new JSONObject();
            // 携程处理批次流水号
            resBody.put("sequenceId", refundNo);
            // 携程订单号
            resBody.put("otaOrderId", MapUtil.getStr(map, "external_order_no"));
            // 供应商订单号
            resBody.put("supplierOrderId", orderNo);

            // 审核状态：0待审核，1审核通过，2审核驳回
            String auditStatus = MapUtil.getStr(map, "audit_status");
            boolean auditStatusFlag = StrUtil.equals(auditStatus, "1");
            boolean auditSatausRejectFlag = StrUtil.equals(auditStatus, "0");
            if (auditStatusFlag) {
                // 确认结果返回码 0000表示成功 0005 系统处理异常拒绝
                resBody.put("confirmResultCode", "0000");
                // 确认信息
                resBody.put("confirmResultMessage", "确认成功");
            } else if (auditSatausRejectFlag) {
                // 确认结果返回码 0000表示成功 0005 系统处理异常拒绝
                resBody.put("confirmResultCode", "0005");
                // 确认信息
                resBody.put("confirmResultMessage", MapUtil.getStr(map, "remark"));
            }

            JSONArray items = new JSONArray();
            JSONObject item = new JSONObject();
            item.put("itemId", MapUtil.getStr(map, "item_id"));
            items.add(item);
            resBody.put("items", items);

            String secret = distributor.getSecret();
            JSONObject secretJson = JSONUtil.parseObj(secret);
            String aesSecret = secretJson.getStr("aesSecret");
            String aesVector = secretJson.getStr("aesVector");
            String md5Secret = secretJson.getStr("md5Secret");
            // String param = XieChengJsonV3equest.create(distributor.getZhName(), , md5Secret, , aesVector, res_body);
            JSONObject root = new JSONObject();
            String strBody = resBody.toString();
            // 加密body
            if (resBody != null && resBody.size() > 0) {
                // 加密body报文
                strBody = AesUtil.encrypt(strBody, aesSecret, aesVector);
                root.put("body", strBody);
            }
            JSONObject header = new JSONObject();
            header.put("accountId", distributor.getAppid());
            // 发送请求
            String serviceName = "CancelOrderConfirm";
            header.put("serviceName", serviceName);
            SimpleDateFormat format2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String requestTime = format2.format(new Date());
            header.put("requestTime", requestTime);
            String version = "1.0";
            header.put("version", version);
            // 签名 使用加密后的报文签名
            // String sign = XieChengJsonV3Resolver.sign(header, strBody, userKey);
            String waitSignString = distributor.getAppid() + serviceName + requestTime + strBody + version + md5Secret;
            String usSign = Md5.getMD5(waitSignString.getBytes("UTF-8"));
            header.put("sign", usSign);
            root.put("header", header);
            sendUrl = distributor.getServerUrl();
            param = root.toString();
            // 发送请求
            Map<String, String> headMap = new HashMap<String, String>(16);
            headMap.put("Content-Type", "application/json;charset=utf-8");
            log.info("---退票结果异步通知携程---start-- orderNo:" + orderNo + " [ param ]：" + param);
            String sendResult = HttpUtil.createPost(sendUrl).contentType("application/json")
                    .headerMap(headMap, false)
                    .body(param)
                    .timeout(15000)
                    .execute().body();
            log.info("---退票结果异步通知携程---end-- orderNo:" + orderNo + " [ sendResult ]：" + sendResult);
            // JSON报文 转换
            JSONObject resultJson = JSONUtil.parseObj(sendResult);
            JSONObject headerJson = resultJson.getJSONObject("header");
            // 处理结果返回码
            boolean resultCodeFlag = "0000".equals(headerJson.getStr("resultCode"));
            if (resultCodeFlag) {
                // 退票结果异步通知携程
                notifyLogService.saveNotifyLog(map, sendUrl, param, sendResult, 1);
                return true;
            } else {
                // 退票结果异步通知携程
                notifyLogService.saveNotifyLog(map, sendUrl, param, sendResult, 0);
                return false;
            }
        } catch (Exception ex) {
            // 退票结果异步通知携程
            notifyLogService.saveNotifyLog(map, sendUrl, param, ex.getMessage(), 0);
            log.error("分销{},{},{},{}", "退票结果异步通知携程", "CancelOrderConfirm", orderNo, ex.getMessage());
        }
        return false;
    }


    /**
     * 从xml中截取body部分（解决使用asXML导致标签闭合的问题
     *
     * @param requestBody
     * @return
     * @author zhoulonggui
     * @date 2017年6月1日
     */
    String getXmlBodyString(String requestBody) {
        if (StringUtils.isNotEmpty(requestBody)) {
            String str = requestBody.substring(requestBody.indexOf("<body>"), requestBody.indexOf("</body>") + 7);
            return str;
        }
        return "";
    }


    /**
     * 创建携程响应实体类
     *
     * @param resultCode
     * @param resultMessage
     * @param body
     * @return
     */
    String xieChengReturn(String resultCode, String resultMessage, DistributorRespDTO distributor, JSONObject body) {
        {
            JSONObject respJson = new JSONObject();
            JSONObject header = new JSONObject();
            try {
                header.put("resultCode", resultCode);
                header.put("resultMessage", resultMessage);

                respJson.put("header", header);
                if (body != null && distributor != null) {
                    // 获取账户和密码
                    String encryptedBodyStr = AesUtil.encrypt(body.toString(), distributor.getAesSecret(), distributor.getAesVector());
                    // aes加密body
                    respJson.put("body", encryptedBodyStr);
                }
            } catch (Exception e) {
                header.put("resultCode", "1100");
                header.put("resultMessage", "服务器内部异常");
                respJson.put("header", header);
            }

            return respJson.toString();
        }
    }

    private Integer changeCertificateType(String type) {
        Integer certificateType = null;
        switch (type) {
            case "1":
                certificateType = CredentialTypeEnum.ID_CARD.getType();
                break;
            case "2":
                certificateType = CredentialTypeEnum.PASSPORT.getType();
                break;
            case "7":
                certificateType = CredentialTypeEnum.HUI_XIANG_CARD.getType();
                ;
                break;
            case "8":
                certificateType = CredentialTypeEnum.TAI_BAO_CARD.getType();
                ;
                break;
            case "10":
                certificateType = CredentialTypeEnum.GANG_AO_PASS_CARD.getType();
                ;
                break;
            case "20":
                certificateType = CredentialTypeEnum.FORERVER_LIVE_CARD.getType();
                ;
                break;
            case "22":
                certificateType = CredentialTypeEnum.TW_PASS_CARD.getType();
                ;
                break;
            case "32":
                certificateType = CredentialTypeEnum.GAT_PASS_CARD.getType();
                ;
                break;
            default:
                certificateType = CredentialTypeEnum.OTHER.getType();
                ;
                break;
        }

        return certificateType;
    }
}

