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

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.HMac;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yc.ship.framework.common.lang.Asserts;
import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.common.util.json.JsonUtils;
import com.yc.ship.framework.common.util.object.BeanUtils;
import com.yc.ship.framework.tenant.core.context.TenantContextHolder;
import com.yc.ship.module.infra.api.config.ConfigApi;
import com.yc.ship.module.infra.api.file.FileApi;
import com.yc.ship.module.trade.controller.admin.invoice.inventory.InvoiceInventorySaveReqVO;
import com.yc.ship.module.trade.dal.dataobject.invoice.InvoiceDO;
import com.yc.ship.module.trade.dal.dataobject.invoice.InvoiceDetailDO;
import com.yc.ship.module.trade.dal.dataobject.invoiceinventory.InvoiceInventoryDO;
import com.yc.ship.module.trade.dal.mysql.invoice.InvoiceMapper;
import com.yc.ship.module.trade.enums.invoice.DigitalInvoiceTypeEnum;
import com.yc.ship.module.trade.enums.invoice.InvoiceStatusEnum;
import com.yc.ship.module.trade.service.invoice.InvoiceDetailService;
import com.yc.ship.module.trade.service.invoice.InvoiceGroupService;
import com.yc.ship.module.trade.service.invoice.InvoiceLogService;
import com.yc.ship.module.trade.service.invoiceinventory.InvoiceInventoryService;
import com.yc.ship.module.trade.service.order.TradeOrderRepositoryService;
import com.yc.ship.module.trade.utils.GzipUtils;
import com.yc.ship.module.trade.utils.TripleDesUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static com.yc.ship.module.trade.enums.ErrorCodeConstants.INVOICING_FAIL;


/**
 * 集团电子发票
 */
@Service
@Slf4j
public class InvoiceGroupServiceImpl implements InvoiceGroupService {

    @Resource
    private ConfigApi configApi;

    @Resource
    private InvoiceLogService invoiceLogService;

    @Resource
    private InvoiceInventoryService invoiceInventoryService;

    @Resource
    @Lazy
    private InvoiceMapper invoiceMapper;

    @Resource
    private InvoiceDetailService invoiceDetailService;

    @Resource
    private TradeOrderRepositoryService tradeOrderRepositoryService;

    @Resource
    private FileApi fileApi;

    @Override
    public CommonResult<InvoiceDO> invoiceIssuance(InvoiceDO invoice, String remark) {
        List<InvoiceDO> invoiceList = new ArrayList<>(Collections.singletonList(invoice));
        return CommonResult.success(this.invoiceIssuance(invoiceList, 0, remark).getCheckedData().get(0));
    }


    /**
     * 开蓝票
     *
     * @param invoiceList
     * @return
     */
    @Override
    public CommonResult<?> batchInvoice(List<InvoiceDO> invoiceList) {
        return this.invoiceIssuance(invoiceList, 0, null);
    }

    /**
     * 查询开票状态
     *
     * @param serialNo（订单请求流水号）
     * @return
     */
//    @Override
    public JSONObject queryInvoiceStatus(String orderNo, String serialNo, String secretKey) {
        String method = "GetOrderInfoAndInvoiceInfo";
        try {
            if (StrUtil.isBlank(secretKey)) {
                secretKey = configApi.getPlatformConfigValueByKey("newinvoice.group.secretkey");
            }
            String taxNum = configApi.getPlatformConfigValueByKey("newinvoice.group.tax");
            JSONObject reqBody = new JSONObject();
            reqBody.set("NSRSBH", taxNum);
            reqBody.set("DDQQLSH", serialNo);
            reqBody.set("DDH", orderNo);
            reqBody.set("TQM", "");
            reqBody.set("HZQRDBH", "");
            reqBody.set("BSWJ", 0);
            reqBody.set("WJLX", "PDF");
            reqBody.set("DDRQQ", "");
            reqBody.set("DDRQZ", "");
            JSONObject resObj = this.doRequest(reqBody, method, secretKey);
            log.error("集团电子发票查询返回1{}:", resObj);
            //成功
            if (Objects.equals("000000", resObj.getStr("returnCode"))) {
                //先判断解压缩标识（0：不压缩1：压缩）
                String originalContent = resObj.getStr("content");
                byte[] decodeContent = Base64.decodeBase64(originalContent);
                //先判断解压缩标识（0：不压缩1：压缩）
                if (Objects.equals("1", resObj.getStr("zipCode"))) {
                    decodeContent = GzipUtils.decompress(originalContent.getBytes(StandardCharsets.UTF_8));
                }
                //加密标识
                if (Objects.equals("1", resObj.getStr("encryptCode"))) {
                    decodeContent = TripleDesUtil.decrypt(secretKey.substring(0, Math.min(secretKey.length(), 24)), decodeContent);
                }
                String content = StrUtil.str(decodeContent, StandardCharsets.UTF_8);
//                log.error("集团电子发票查询返回3:{}", content);
                JSONObject contentObj = JSONUtil.parseObj(content);
//                log.error("集团电子发票查询返回4:{}", contentObj);
                Asserts.isTrue(Objects.equals("000000", contentObj.getStr("ZTDM")), "发票查询失败,{}", contentObj.getStr("ZTXX"));
                JSONArray ddfpzxxList = contentObj.getJSONArray("DDFPZXX");
                return ddfpzxxList.getJSONObject(0);
//                return JSONUtil.parseObj(ddfpzObj.getStr("DDFPXX"));
            }
        } catch (Exception e) {
            log.error("集团电子发票查询失败:", e);
            throw exception0(30_030_10, "集团电子发票查询失败");
        }
        return null;
    }

    @Override
    public CommonResult<InvoiceDO> queryInvoice(InvoiceDO invoice) {
        String secretKey = configApi.getPlatformConfigValueByKey("newinvoice.group.secretkey");
        JSONObject queryRes = this.queryInvoiceStatus(invoice.getTransactionNo(), invoice.getFpqqlsh(), secretKey);
        if (queryRes != null) {
            JSONObject ddfpxx = queryRes.getJSONObject("DDFPXX");
            String ddzt = ddfpxx.getStr("DDZT");
            String pdfzjls = ddfpxx.getStr("PDFZJL");
//            log.error("发票pdfzjls=" + pdfzjls);
            if (StringUtils.isNotEmpty(pdfzjls)) {
                if (TenantContextHolder.getTenantId() == null) {
                    TenantContextHolder.setTenantId(invoice.getTenantId());
                }
                String file = fileApi.createFile(Base64.decodeBase64(pdfzjls),null,null,"application/pdf");
                log.error("发票file=" + file);
                invoice.setCUrl(file);
                String sdewmurl = ddfpxx.getStr("SDEWMURL");
                if (StringUtils.equals("030000", ddzt)) {
                    String kprq = ddfpxx.getStr("KPRQ");
                    String fphm = ddfpxx.getStr("FPHM");
                    //030000-开票成功，031000-订单未开票，031999-订单开票失败，032000-订单开票中，032997-订单不存在，032998-订单已拆分或已合并，032999-订单已删除
                    LocalDateTime localDateTime = this.getLocalDateTime(kprq);
                    invoice.setCKprq(localDateTime);
                    invoice.setCFphm(fphm);
                    invoice.setInvoiceStatus(InvoiceStatusEnum.INVOICE_SUCCESS.getValue());
                    JSONArray DDKZXX = queryRes.getJSONArray("DDKZXX");
                    List<InvoiceInventoryDO> inventoryList = invoiceInventoryService.getInvoiceInventoryListByInvoiceId(invoice.getId());
                    for (int i = 0; i < DDKZXX.size(); i++) {
                        InvoiceInventoryDO inventoryDO = inventoryList.get(i);
                        inventoryDO.setDylzfpmxxh(DDKZXX.getJSONObject(i).getStr("DDQQLSH"));
                        InvoiceInventorySaveReqVO reqVO = BeanUtils.toBean(inventoryDO, InvoiceInventorySaveReqVO.class);
                        invoiceInventoryService.updateInvoiceInventory(reqVO);
                    }
                    invoiceMapper.updateById(invoice);

                    List<InvoiceDetailDO> list = invoiceDetailService.getInvoiceDetails(invoice.getId());
                    List<String> orderNoList = list.stream().map(InvoiceDetailDO::getOrderNo).collect(Collectors.toList());
                    tradeOrderRepositoryService.updateInvoiceStatusByOrderNo(orderNoList, 1);

                }
            }else if (StringUtils.equals("032000", ddzt)) {
                String ddztxx = ddfpxx.getStr("DDZTXX");
                log.error("集团电子发票查询异常：" + ddfpxx);
                invoice.setCResultmsg(ddztxx);
                invoiceMapper.updateById(invoice);
            }else if (StringUtils.equals("031999", ddzt)) {
                String ddztxx = ddfpxx.getStr("DDZTXX");
                invoice.setInvoiceStatus(InvoiceStatusEnum.INVOICE_FAILED.getValue());
                invoice.setCResultmsg(ddztxx);
                invoiceMapper.updateById(invoice);

                List<InvoiceDetailDO> orderList = invoiceDetailService.getInvoiceDetails(invoice.getId());
                List<String> orderNoList = orderList.stream().map(InvoiceDetailDO::getOrderNo).collect(Collectors.toList());
                tradeOrderRepositoryService.updateInvoiceStatusByOrderNo(orderNoList, InvoiceStatusEnum.NOT_INVOICED.getValue());
            }
            return CommonResult.success(invoice);
        }
        return null;
    }

    @Override
    public CommonResult<InvoiceDO> redInvoiceIssuance(InvoiceDO invoice) {
        try {
            String secretKey = configApi.getPlatformConfigValueByKey("newinvoice.group.secretkey");
            String taxNum = configApi.getPlatformConfigValueByKey("newinvoice.group.tax");
//            JSONObject data1 = redConfirmationApply(secretKey, taxNum, invoice);
//            String redOrderNo = data1.getStr("HZFPXXQRDBH");
//            String uuid = data1.getStr("UUID");
//            // 红字确认单状态
//            if (!StringUtils.equals("01", redOrderNo)) {
//                // 购方确认
//                redConfirmationConfirm(secretKey, invoice.getBuyerTaxCode(), uuid, redOrderNo);
//                // 销方确认
//                redConfirmationConfirm(secretKey, taxNum, uuid, redOrderNo);
//                // 订单快捷冲红接口
//                orderToFastRedInvoice(secretKey, taxNum, uuid, redOrderNo, invoice);
//                // 快捷冲红查询
//                JSONObject data2 = getOrderInfoAndInvoiceInfo(secretKey, taxNum, uuid, redOrderNo, invoice);
//                log.info("集团电子发票冲红查询:{}", data2);
//            }
            // 订单快捷冲红接口
            JSONObject data1 = orderToFastRedInvoice(secretKey, taxNum, "", "", invoice);
            ////{"HZFPXXQRDBH":"","UUID":"","ZTDM":"009999","ZTXX":"原蓝票已冲红"}
            ////{"HZFPXX":{"DDFPXX":{"BMBBBH":"36.0","BYZD1":"","BYZD2":"","BYZD3":"","BYZD4":"","BYZD5":"","BZ":"","CHBZ":"0","CHYY":"2","DDH":"IVE2026042415170000110","DDLX":"0","DDLY":"3","DDQQLSH":"1212623796021043200","DDSJ":"2026-05-08 15:00:52","DDZT":"032000","DDZTXX":"订单开票中","DFGTGMBZ":"","DTM":"","ENTID":"1027395519858941985","EWM":"","FHR":"","FJH":"","FPDM":"","FPHM":"","FPLXDM":"002","FWM":"","GMFBM":"","GMFDH":"","GMFDZ":"","GMFDZYX":"906534176@qq.com","GMFGJ":"","GMFLX":"01","GMFMC":"测试旅行社001","GMFSBH":"913301087458306077","GMFSJH":"18628286025","GMFYH":"","GMFZH":"","GMFZJHM":"","GMFZJLX":"","GMFZJLXDM":"","HJJE":"-0.94","HJSE":"-0.06","HZXXBBH":"","JQBH":"","JSHJ":"-1.00","JYM":"","KPFS":"0","KPJH":"","KPLX":"1","KPR":"陈心雨","KPRQ":"","KPRZJHM":"","KPRZJLX":"","KPZD":"","PDFZJL":"","QDBZ":"0","SDEWMURL":"","SDFPHM":"","SFCF":"","SKR":"","SLKJLY":"","TQM":"","TSCHBZ":"","XHFDH":"0717-6900579","XHFDZ":"宜昌市夷陵区三斗坪镇黄陵庙村一组","XHFMC":"宜昌长江国际旅行社有限公司","XHFSBH":"91420500737133035K","XHFYH":"1","XHFZH":"1","YFPDM":"","YFPHM":"26427000000001615911","YFPKPRQ":"","YFPLX":"","YHM":"","YWLX":"","ZFBZ":"0","ZJLLX":""},"DDKZXX":[{"BYZD1":"","BYZD2":"","BYZD3":"","DDH":"IVE2026042415170000110","DDLX":"0","DDQQLSH":"1212623796021043200"}],"DDMXXX":[{"BYZD1":"","BYZD2":"","BYZD3":"","BZ":"","DJ":"","DW":"","FPHXZ":"0","FYMX":"","GGXH":"","HSBZ":"0","JE":"-0.94","KCE":"","LSLBS":"","MTZLDM":"","SE":"-0.06","SL":"0.06","SPBM":"3070301000000000000","SPSL":"","XH":"1","XMMC":"*旅游服务*旅游服务费","YHZCBS":"0","YLFWGBM":"","ZXBM":"","ZZSTSGL":""}],"QDTXX":{"BFCPSGXSLZ":"","CEZSLXDM":"","CKYWSYZCDM":"","GMFJBR":"","GMFJBRLXDH":"","JAZSLXDM":"","JBRSFZJHM":"","JSFS":"","MTPZXX":"","QYDM":"","REMIND_INFO":"","SGFPLXDM":"","SKYHMC":"","SKYHZH":"","TDYS":"","XSEQRBZ":"","YSXWFSD":"","YYBLDJ":"","ZPPZDM":"","ZZID":"1027395519858941985","ZZSJZJTDM":""}},"HZQRDXX":{"HZCXJE":"-0.94","HZCXSE":"-0.06","HZFPHM":"26427000000001616024","HZFPXXQRDBH":"42050326051000502207","HZKPRQ":"2026-05-08 15:00:52","HZQRXXZTDM":"01","LRRQ":"2026-05-08 15:00:52","UUID":"0a0ae9fd177f4042ab32a0c91a88bd6e","YKJHZFPBZ":"Y","YXBZ":"Y"},"ZTDM":"001000","ZTXX":"订单开票中"}
            if(data1.getStr("ZTDM").equals("009999")){
                invoice.setInvoiceStatus(InvoiceStatusEnum.INVOICE_RED_SUCCESS.getValue());
                invoiceMapper.updateById(invoice);
                List<InvoiceDetailDO> orderList = invoiceDetailService.getInvoiceDetails(invoice.getId());
                List<String> orderNoList = orderList.stream().map(InvoiceDetailDO::getOrderNo).collect(Collectors.toList());
                tradeOrderRepositoryService.updateInvoiceStatusByOrderNo(orderNoList, InvoiceStatusEnum.NOT_INVOICED.getValue());
            }else if(data1.getStr("ZTDM").equals("001000")) {
                String redOrderNo = data1.getStr("HZFPXXQRDBH");
                String uuid = data1.getStr("UUID");
                // 4.冲红中 5.冲红失败 6.冲红成功
                invoice.setInvoiceStatus(InvoiceStatusEnum.INVOICE_RED_INVOIING.getValue());
                invoice.setRemark(JSONUtil.toJsonStr(data1));
                invoiceMapper.updateById(invoice);
                // 快捷冲红查询
                JSONObject data2 = queryFastRedInvoiceResult(secretKey, taxNum, uuid, redOrderNo, invoice);
                String ztdm = data2.getStr("ZTDM");
                if (Objects.equals("000000", ztdm)) {
                    invoice.setInvoiceStatus(InvoiceStatusEnum.INVOICE_RED_SUCCESS.getValue());
                    invoiceMapper.updateById(invoice);
                    List<InvoiceDetailDO> orderList = invoiceDetailService.getInvoiceDetails(invoice.getId());
                    List<String> orderNoList = orderList.stream().map(InvoiceDetailDO::getOrderNo).collect(Collectors.toList());
                    tradeOrderRepositoryService.updateInvoiceStatusByOrderNo(orderNoList, InvoiceStatusEnum.NOT_INVOICED.getValue());
                }
            }else{
                log.error("集团电子发票查询失败:{}",data1);
                return CommonResult.error(30_030_10,"集团电子发票查询失败"+data1);
            }
        } catch (Exception e) {
            log.error("集团电子发票查询失败:", e);
            throw exception0(30_030_10, "集团电子发票查询失败");
        }
        return CommonResult.success(invoice);
    }

    @Override
    public CommonResult<InvoiceDO> queryRedInvoice(InvoiceDO invoice) {
        String secretKey = configApi.getPlatformConfigValueByKey("newinvoice.group.secretkey");
        String taxNum = configApi.getPlatformConfigValueByKey("newinvoice.group.tax");
        JSONObject data1 = JSONUtil.parseObj(invoice.getRemark());
        String redOrderNo = data1.getStr("HZFPXXQRDBH");
        String uuid = data1.getStr("UUID");
        // 快捷冲红查询
        JSONObject data2 = queryFastRedInvoiceResult(secretKey, taxNum, uuid, redOrderNo, invoice);
        String ztdm = data2.getStr("ZTDM");
        if (Objects.equals("000000", ztdm)) {
            invoice.setInvoiceStatus(InvoiceStatusEnum.INVOICE_RED_SUCCESS.getValue());
            invoiceMapper.updateById(invoice);
            List<InvoiceDetailDO> orderList = invoiceDetailService.getInvoiceDetails(invoice.getId());
            List<String> orderNoList = orderList.stream().map(InvoiceDetailDO::getOrderNo).collect(Collectors.toList());
            tradeOrderRepositoryService.updateInvoiceStatusByOrderNo(orderNoList, InvoiceStatusEnum.NOT_INVOICED.getValue());
        }
        return CommonResult.success(invoice);
    }

    /**
     * 红字确认单申请
     *
     * @param invoice
     * @return
     */
    public JSONObject redConfirmationApply(String secretKey, String taxNum, InvoiceDO invoice) {
        String method = "RedConfirmationApply";
        try {
            if (StringUtils.isBlank(secretKey)) {
                secretKey = configApi.getPlatformConfigValueByKey("newinvoice.group.secretkey");
            }
            JSONObject reqBody = new JSONObject();
            reqBody.set("LRFSF", 0);
            reqBody.set("XSFNSRSBH", taxNum);
            reqBody.set("XSFMC", invoice.getSalesName());
            reqBody.set("GMFNSRSBH", invoice.getBuyerTaxCode());
            reqBody.set("GMFMC", invoice.getBuyerName());
            reqBody.set("SFZZFPBZ", "N");
            reqBody.set("LZKPRQ", DateUtil.format(invoice.getCKprq(), "yyyy-MM-dd HH:mm:ss"));
            reqBody.set("LZHJJE", BigDecimal.ZERO.subtract(invoice.getPrice()));
            reqBody.set("LZHJSE", BigDecimal.ZERO.subtract(invoice.getCHjse()));
            //发票种类代码01-专用发票 02-普通发票
            if (invoice.getInvoiceType() == null) {
                reqBody.set("LZFPPZDM", "002");
            } else {
                reqBody.set("LZFPPZDM", DigitalInvoiceTypeEnum.valueOf(invoice.getInvoiceType()).getCode());
            }
            reqBody.set("LZFPQDHM", invoice.getCFphm());

            reqBody.set("HZCXJE", BigDecimal.ZERO.subtract(invoice.getPrice()));
            reqBody.set("HZCXSE", BigDecimal.ZERO.subtract(invoice.getCHjse()));
            reqBody.set("CHYYDM", "01");
            reqBody.set("DDH", invoice.getTransactionNo());
            List<InvoiceInventoryDO> inventoryList = invoiceInventoryService.getInvoiceInventoryListByInvoiceId(invoice.getId());
            JSONArray details = new JSONArray();
            JSONObject detail;
            for (InvoiceInventoryDO inventoryDO : inventoryList) {
                detail = new JSONObject();
                detail.set("LZMXXH", inventoryDO.getSort());
                detail.set("XH", inventoryDO.getSort());
                detail.set("SPFWJC", inventoryDO.getName());
                detail.set("SPHFWSSFLHBBM", inventoryDO.getCode());
                detail.set("XMMC", inventoryDO.getName());
                detail.set("JE", BigDecimal.ZERO.subtract(inventoryDO.getAmount()));
                detail.set("SLV", inventoryDO.getTaxRate());
                detail.set("SE", BigDecimal.ZERO.subtract(inventoryDO.getTax()));
                details.add(detail);
            }
            reqBody.set("HZQRDMXLIST", details);
            JSONObject resObj = this.doRequest(reqBody, method, secretKey);
            //成功
            if (Objects.equals("000000", resObj.getStr("returnCode"))) {
                //先判断解压缩标识（0：不压缩1：压缩）
                String originalContent = resObj.getStr("content");
                byte[] decodeContent = Base64.decodeBase64(originalContent);
                //先判断解压缩标识（0：不压缩1：压缩）
                if (Objects.equals("1", resObj.getStr("zipCode"))) {
                    decodeContent = GzipUtils.decompress(originalContent.getBytes(StandardCharsets.UTF_8));
                }
                //加密标识
                if (Objects.equals("1", resObj.getStr("encryptCode"))) {
                    decodeContent = TripleDesUtil.decrypt(secretKey.substring(0, Math.min(secretKey.length(), 24)), decodeContent);
                }
                String content = StrUtil.str(decodeContent, StandardCharsets.UTF_8);
                JSONObject contentObj = JSONUtil.parseObj(content);
                Asserts.isTrue(Objects.equals("000000", contentObj.getStr("ZTDM")), "发票查询失败,{}", contentObj.getStr("ZTXX"));
                return contentObj.getJSONObject("DATA");
                // "DATA": {
                //    "HZFPXXQRDBH": "红字确认单编号",
                //    "UUID": "红字确认单UUID",
                //    "HZQRXXZTDM ": "01：无需确认
                //02：销方录入待购方确认
                //03：购方录入待销方确认
                //04：购销双方已确认
                //05：作废（销方录入购方否认）
                //06：作废（购方录入销方否认）
                //07：作废（超72小时未确认）
                //08：（发起方撤销）",
                //    "QRJKPBZ":"“确认即开票标识”为‘Y’时，系统自动开具红字发票，无需再发起红字发票开具业务，可使用红字确认单编号，通过《订单及发票查询接口》获取对应红字发票。
                //“确认即开票标识”为‘N’或空时，需要通过发票开具接口，根据红字确认单编号发起红字发票开具业务。"
                //  }
            }
        } catch (Exception e) {
            log.error("集团电子发票查询失败:", e);
            throw exception0(30_030_10, "集团电子发票查询失败");
        }
        return null;

    }

    /**
     * 红字确认单确认
     *
     * @param uuid
     * @param secretKey
     * @param taxNum
     * @param redOrderNo
     * @return
     */
    public JSONObject redConfirmationConfirm(String secretKey, String taxNum, String uuid, String redOrderNo) {
        String method = "RedConfirmationConfirm";
        try {
            if (StringUtils.isBlank(secretKey)) {
                secretKey = configApi.getPlatformConfigValueByKey("newinvoice.group.secretkey");
            }
            JSONObject reqBody = new JSONObject();
            reqBody.set("NSRSBH", taxNum);
            reqBody.set("HZQRDBH", redOrderNo);
            reqBody.set("QRLX", "Y");
            reqBody.set("UUID", uuid);
            JSONObject resObj = this.doRequest(reqBody, method, secretKey);
            //成功
            if (Objects.equals("000000", resObj.getStr("returnCode"))) {
                //先判断解压缩标识（0：不压缩1：压缩）
                String originalContent = resObj.getStr("content");
                byte[] decodeContent = Base64.decodeBase64(originalContent);
                //先判断解压缩标识（0：不压缩1：压缩）
                if (Objects.equals("1", resObj.getStr("zipCode"))) {
                    decodeContent = GzipUtils.decompress(originalContent.getBytes(StandardCharsets.UTF_8));
                }
                //加密标识
                if (Objects.equals("1", resObj.getStr("encryptCode"))) {
                    decodeContent = TripleDesUtil.decrypt(secretKey.substring(0, Math.min(secretKey.length(), 24)), decodeContent);
                }
                String content = StrUtil.str(decodeContent, StandardCharsets.UTF_8);
                JSONObject contentObj = JSONUtil.parseObj(content);
                Asserts.isTrue(Objects.equals("000000", contentObj.getStr("ZTDM")), "发票查询失败,{}", contentObj.getStr("ZTXX"));
                return contentObj.getJSONObject("DATA");
            }
        } catch (Exception e) {
            log.error("集团电子发票查询失败:", e);
            throw exception0(30_030_10, "集团电子发票查询失败");
        }
        return null;
    }

    /**
     * 订单快捷冲红接口
     *
     * @param secretKey
     * @param taxNum
     * @param uuid
     * @param redOrderNo
     * @param invoice
     * @return
     */
    public JSONObject orderToFastRedInvoice(String secretKey, String taxNum, String uuid, String redOrderNo, InvoiceDO invoice) {
        String method = "OrderToFastRedInvoice";
        try {
            if (StringUtils.isBlank(secretKey)) {
                secretKey = configApi.getPlatformConfigValueByKey("newinvoice.group.secretkey");
            }
            JSONObject reqBody = new JSONObject();
            reqBody.set("NSRSBH", taxNum);
            reqBody.set("DDH", invoice.getTransactionNo());
            reqBody.set("CHYYDM", "01");
            reqBody.set("LZFPQDHM", invoice.getCFphm());
            // 0:使用原发票代码号码或原数电发票号码冲红,1:使用红字确认单编号冲红
            if (StringUtils.isNotBlank(uuid)) {
                reqBody.set("UUID", uuid);
                reqBody.set("HZFPXXQRDBH", redOrderNo);
                reqBody.set("LZFPQDHM", "");
                reqBody.set("CHFS", "1");
            } else {
                reqBody.set("LZFPQDHM", invoice.getCFphm());
                reqBody.set("CHFS", "0");
            }

            reqBody.set("LZFPDM", "");
            reqBody.set("LZFPHM", "");

            JSONObject resObj = this.doRequest(reqBody, method, secretKey);
            //成功
            if (Objects.equals("000000", resObj.getStr("returnCode"))) {
                //先判断解压缩标识（0：不压缩1：压缩）
                String originalContent = resObj.getStr("content");
                byte[] decodeContent = Base64.decodeBase64(originalContent);
                //先判断解压缩标识（0：不压缩1：压缩）
                if (Objects.equals("1", resObj.getStr("zipCode"))) {
                    decodeContent = GzipUtils.decompress(originalContent.getBytes(StandardCharsets.UTF_8));
                }
                //加密标识
                if (Objects.equals("1", resObj.getStr("encryptCode"))) {
                    decodeContent = TripleDesUtil.decrypt(secretKey.substring(0, Math.min(secretKey.length(), 24)), decodeContent);
                }
                String content = StrUtil.str(decodeContent, StandardCharsets.UTF_8);
                JSONObject contentObj = JSONUtil.parseObj(content);
                //{"HZFPXXQRDBH":"","UUID":"","ZTDM":"009999","ZTXX":"原蓝票已冲红"}
                if(contentObj.getStr("ZTDM").equals("009999")){
                    return contentObj;
                }
                Asserts.isTrue(Objects.equals("000000", contentObj.getStr("ZTDM")), "发票查询失败,{}", contentObj.getStr("ZTXX"));
                return contentObj;
            }
        } catch (Exception e) {
            log.error("集团电子发票查询失败:", e);
            throw exception0(30_030_10, "集团电子发票查询失败");
        }
        return null;
    }

    /**
     * 快捷冲红查询
     *
     * @param secretKey
     * @param taxNum
     * @param uuid
     * @param redOrderNo
     * @param invoice
     * @return
     */
    public JSONObject queryFastRedInvoiceResult(String secretKey, String taxNum, String uuid, String redOrderNo, InvoiceDO invoice) {
        String method = "QueryFastRedInvoiceResult";
        try {
            if (StringUtils.isBlank(secretKey)) {
                secretKey = configApi.getPlatformConfigValueByKey("newinvoice.group.secretkey");
            }
            JSONObject reqBody = new JSONObject();
            reqBody.set("NSRSBH", taxNum);
            reqBody.set("UUID", uuid);
            reqBody.set("HZFPXXQRDBH", redOrderNo);
            JSONObject resObj = this.doRequest(reqBody, method, secretKey);
            //成功
            if (Objects.equals("000000", resObj.getStr("returnCode"))) {
                //先判断解压缩标识（0：不压缩1：压缩）
                String originalContent = resObj.getStr("content");
                byte[] decodeContent = Base64.decodeBase64(originalContent);
                //先判断解压缩标识（0：不压缩1：压缩）
                if (Objects.equals("1", resObj.getStr("zipCode"))) {
                    decodeContent = GzipUtils.decompress(originalContent.getBytes(StandardCharsets.UTF_8));
                }
                //加密标识
                if (Objects.equals("1", resObj.getStr("encryptCode"))) {
                    decodeContent = TripleDesUtil.decrypt(secretKey.substring(0, Math.min(secretKey.length(), 24)), decodeContent);
                }
                String content = StrUtil.str(decodeContent, StandardCharsets.UTF_8);
                JSONObject contentObj = JSONUtil.parseObj(content);
                String ztdm = contentObj.getStr("ZTDM");
                Asserts.isTrue(Objects.equals("000000", ztdm) || Objects.equals("001000", ztdm), "发票冲红查询,{}", contentObj.getStr("ZTXX"));
//                return contentObj.getJSONObject("HZFPXX");
                return contentObj;
            }
        } catch (Exception e) {
            log.error("集团电子发票查询失败:", e);
            throw exception0(30_030_10, "集团电子发票查询失败");
        }
        return null;
    }

    /**
     * @param invoiceList
     * @param type        开票类型（0蓝字发票 1红字发票）
     * @return
     */
    public CommonResult<List<InvoiceDO>> invoiceIssuance(List<InvoiceDO> invoiceList, int type, String remark) {
        String method = "GenerateQdInvoice";
        String secretKey = configApi.getPlatformConfigValueByKey("newinvoice.group.secretkey");
        String msg;
        try {
            JSONObject reqBody = this.buildRequestParam(invoiceList, type, "", remark);
//            JSONObject reqBody = this.buildRequestParamNew(invoiceList, type, "", remark);//折扣行
            String batchNo = reqBody.getJSONObject("DDPCXX").getStr("DDQQPCH");
            log.error("发票开具请求参数reqBody={}，secretKey={}", reqBody,secretKey);
            JSONObject resObj = this.doRequest(reqBody, method, secretKey);
            msg = resObj.getStr("returnMessage");
            //成功
            if (Objects.equals("000000", resObj.getStr("returnCode"))) {
                //先判断解压缩标识（0：不压缩1：压缩）
                String originalContent = resObj.getStr("content");
                byte[] decodeContent = Base64.decodeBase64(originalContent);
                //先判断解压缩标识（0：不压缩1：压缩）
                if (Objects.equals("1", resObj.getStr("zipCode"))) {
                    decodeContent = GzipUtils.decompress(originalContent.getBytes(StandardCharsets.UTF_8));
                }
                //加密标识
                if (Objects.equals("1", resObj.getStr("encryptCode"))) {
                    decodeContent = TripleDesUtil.decrypt(secretKey.substring(0, Math.min(secretKey.length(), 24)), decodeContent);
                }
                String content = StrUtil.str(decodeContent, StandardCharsets.UTF_8);
                log.error("content=" + content);
                JSONObject contentObj = JSONUtil.parseObj(content);
                Asserts.isTrue(Objects.equals("010000", contentObj.getStr("ZTDM")), "开票失败1,{}", contentObj.getStr("ZTXX"));
                invoiceList.forEach(invoiceDO -> {
                    invoiceLogService.saveInvoiceLog(invoiceDO.getId(), "Kp_Fpkj", method, batchNo, reqBody.toString(), resObj.toString());
                    invoiceDO.setInvoiceStatus(InvoiceStatusEnum.INVOICE_INVOIING.getValue());
                    try {
                        JSONObject queryRes = this.queryInvoiceStatus(invoiceDO.getTransactionNo(), invoiceDO.getFpqqlsh(), secretKey);
                        if (queryRes != null) {
                            JSONObject ddfpxx = queryRes.getJSONObject("DDFPXX");
                            String ddzt = ddfpxx.getStr("DDZT");
                            String sdewmurl = ddfpxx.getStr("SDEWMURL");
                            if (StringUtils.equals("030000", ddzt)) {
                                String kprq = ddfpxx.getStr("KPRQ");
                                String fphm = ddfpxx.getStr("FPHM");
                                //030000-开票成功，031000-订单未开票，031999-订单开票失败，032000-订单开票中，032997-订单不存在，032998-订单已拆分或已合并，032999-订单已删除
                                LocalDateTime localDateTime = this.getLocalDateTime(kprq);
                                invoiceDO.setCKprq(localDateTime);
                                invoiceDO.setCFphm(fphm);
                                invoiceDO.setUpdater(sdewmurl);
                                invoiceDO.setInvoiceStatus(InvoiceStatusEnum.INVOICE_SUCCESS.getValue());
                                JSONArray DDKZXX = queryRes.getJSONArray("DDKZXX");
                                List<InvoiceInventoryDO> inventoryList = invoiceInventoryService.getInvoiceInventoryListByInvoiceId(invoiceDO.getId());
                                for (int i = 0; i < DDKZXX.size(); i++) {
                                    InvoiceInventoryDO inventoryDO = inventoryList.get(i);
                                    inventoryDO.setDylzfpmxxh(DDKZXX.getJSONObject(i).getStr("DDQQLSH"));
                                    InvoiceInventorySaveReqVO reqVO = BeanUtils.toBean(inventoryDO, InvoiceInventorySaveReqVO.class);
                                    invoiceInventoryService.updateInvoiceInventory(reqVO);
                                }
                            }
                        }
                    } catch (Exception e) {
                        log.error("集团电子发票查询失败:", e);
                    }
//                    invoiceMapper.updateById(invoiceDO);
                });
                invoiceMapper.updateBatch(invoiceList);
                return CommonResult.success(invoiceList);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return CommonResult.error(INVOICING_FAIL.getCode(), msg);
    }

    /**
     * 组装参数
     *
     * @param invoiceList
     * @param type        开票类型（0蓝字发票 1红字发票）
     * @return
     */
    private JSONObject buildRequestParam(List<InvoiceDO> invoiceList, Integer type, String sysSource, String remark) {
        String taxNum = configApi.getPlatformConfigValueByKey("newinvoice.group.tax");
        String salesName = configApi.getPlatformConfigValueByKey("newinvoice.sales.name");
        String batchNo = IdUtil.fastSimpleUUID();

        JSONObject requestBody = new JSONObject();
        JSONArray reqDDZ = new JSONArray();
        JSONObject reqDDPC = new JSONObject();
        //订单请求批次号
        reqDDPC.set("DDQQPCH", batchNo);
        //纳税人识别号
        reqDDPC.set("NSRSBH", taxNum);
        //发票种类代码01-专用发票 02-普通发票
        if (invoiceList.get(0).getInvoiceType() == null) {
            reqDDPC.set("FPLXDM", "002");
        } else {
            reqDDPC.set("FPLXDM", DigitalInvoiceTypeEnum.valueOf(invoiceList.get(0).getInvoiceType()).getCode());
        }
        requestBody.set("DDPCXX", reqDDPC);
        invoiceList.forEach(invoice -> {
            JSONObject jsonObject = new JSONObject();
            JSONObject reqObj = new JSONObject();
            //订单请求流水号
            reqObj.set("DDQQLSH", invoice.getFpqqlsh());
            //开票类型（0蓝字发票 1红字发票）
            reqObj.set("KPLX", type);
            //销货方纳税人识别号
            reqObj.set("XHFSBH", taxNum);
            //销货方名称
            reqObj.set("XHFMC", salesName);
            //销货方地址
            reqObj.set("XHFDZ", "");
            //销货方电话
            reqObj.set("XHFDH", "");
            //销货方银行名称
            reqObj.set("XHFYH", configApi.getPlatformConfigValueByKey("newinvoice.sales.bank"));
            //销货方银行账号
            reqObj.set("XHFZH", configApi.getPlatformConfigValueByKey("newinvoice.sales.bankaccount"));

            reqObj.set("DDH", invoice.getTransactionNo());

            //开票员，以电子税局绑定人员为准
            reqObj.set("KPR", invoice.getBuyerClerk());

            //购买方编码
            reqObj.set("GMFYH", "");
            //购买方纳税人识别号
            reqObj.set("GMFSBH", invoice.getBuyerTaxCode());
            //购买方名称（当GMFBM为空并且开票方式为自动开票时必填。如果FPLXDM为002，且GMFLX为03(个人)时，GMFMC必须以（个人）字样结尾”(”为全角）
            reqObj.set("GMFMC", invoice.getBuyerName());
            //购买方地址
            reqObj.set("GMFDZ", invoice.getBuyerAddress());
            //购买方电话
            reqObj.set("GMFDH", invoice.getBuyerPhone());
            //购买方银行名称
            reqObj.set("GMFYH", invoice.getBuyerBank());
            //购买方电话
            reqObj.set("GMFZH", invoice.getBuyerAccount());
            //购买方类型(01企业，02机关事业单位，03个人，04其他,如不填写,默认为04)
            if (invoice.getTitleType() != null) {
                if (invoice.getTitleType() == 0) {
                    //购买方名称（当GMFBM为空并且开票方式为自动开票时必填。如果FPLXDM为002，且GMFLX为03(个人)时，GMFMC必须以（个人）字样结尾”(”为全角）
                    reqObj.set("GMFMC", invoice.getBuyerName() + "（个人）");
                    reqObj.set("GMFLX", "03");
                } else if (invoice.getTitleType() == 1) {
                    reqObj.set("GMFLX", "01");
                }
            } else {
                reqObj.set("GMFLX", "04");
            }
//            reqObj.set("GMFLX", invoice.getTitleType());
            //购货方手机
            reqObj.set("GMFSJH", invoice.getBuyerTel());
            //购方邮箱,如果填写,发票类别为电子发票时会自动发送邮件
            reqObj.set("GMFDZYX", invoice.getBuyerEmail());

            JSONArray detailArray = new JSONArray();
            List<InvoiceInventoryDO> inventoryList = invoiceInventoryService.getInvoiceInventoryListByInvoiceId(invoice.getId());
            JSONObject detailObj;
            BigDecimal taxExcludedAmount = BigDecimal.ZERO;
            BigDecimal se = BigDecimal.ZERO;
            BigDecimal taxIncludedAmount = BigDecimal.ZERO;
            if (inventoryList.isEmpty()) {
                int index = 1;
                detailObj = new JSONObject();
                detailObj.set("XH", index);
                String GoodsCode = configApi.getPlatformConfigValueByKey("newinvoice.goods.code");
                String spbm = StrUtil.padAfter(GoodsCode, 19, "0");
                //商品编码
                detailObj.set("SPBM", spbm);
                String spmc = configApi.getPlatformConfigValueByKey("newinvoice.goods.simpleCode");
                //项目名称
                detailObj.set("XMMC", spmc);
                //税率
                BigDecimal taxRate = new BigDecimal(configApi.getPlatformConfigValueByKey("newinvoice.taxRate"));
                detailObj.set("SL", taxRate);
                //含税金额
                taxIncludedAmount = invoice.getPrice();
                if (type == 1) {
                    taxIncludedAmount = BigDecimal.ZERO.subtract(invoice.getPrice());
                }
//                String dylzfpmxxh = String.valueOf(IdWorker.getId()).substring(0,8);
//                detailObj.set("DYLZFPMXXH", dylzfpmxxh);
                //不含税金额
                taxExcludedAmount = taxIncludedAmount.divide(new BigDecimal(1).add(taxRate), 2, RoundingMode.HALF_UP);
                //金额
                detailObj.set("JE", taxIncludedAmount.setScale(2, RoundingMode.HALF_UP));
                //税额
                se = taxIncludedAmount.subtract(taxExcludedAmount);
                detailObj.set("SE", se.setScale(2, RoundingMode.HALF_UP));
                //扣除额
                detailObj.set("KCE", "");
                //行性质。0-正常行 1-折扣行 2-被折扣行
                detailObj.set("FPHXZ", "0");
                //含税标志
                detailObj.set("HSBZ", "1");
                //空：非零税率，1：免税，2：不征税 3:普通零税率
                detailObj.set("LSLBS", "");
                //0：不使用，1：使用,SPID为空时必填
                detailObj.set("YHZCBS", 0);
                detailArray.add(detailObj);

                InvoiceInventorySaveReqVO saveReqVO = new InvoiceInventorySaveReqVO();
                saveReqVO.setInvoiceId(invoice.getId());
                saveReqVO.setSort(index);
                saveReqVO.setAmount(taxIncludedAmount);
                saveReqVO.setTax(se);
                saveReqVO.setCode(spbm);
                saveReqVO.setName(spmc);
                saveReqVO.setTaxRate(taxRate);
                saveReqVO.setFphxz(0);
                saveReqVO.setHsbz(1);
                saveReqVO.setYhzcbs(0);
//                saveReqVO.setDylzfpmxxh(dylzfpmxxh);
                InvoiceInventoryDO invoiceInventoryDO = invoiceInventoryService.createInvoiceInventory(saveReqVO);
                inventoryList = new ArrayList<>(3);
                inventoryList.add(invoiceInventoryDO);
            } else {
                for (InvoiceInventoryDO invoiceInventoryDO : inventoryList) {
                    detailObj = new JSONObject();
                    detailObj.set("XH", invoiceInventoryDO.getSort());
                    //商品编码
                    detailObj.set("SPBM", invoiceInventoryDO.getCode());
                    //项目名称
                    detailObj.set("XMMC", invoiceInventoryDO.getName());
                    //税率
                    detailObj.set("SL", invoiceInventoryDO.getTaxRate());
                    //含税金额
                    BigDecimal thisTaxIncludedAmount = invoiceInventoryDO.getAmount();
                    if (type == 1) {
                        detailObj.set("DYLZFPMXXH", invoiceInventoryDO.getDylzfpmxxh());
                        thisTaxIncludedAmount = BigDecimal.ZERO.subtract(invoiceInventoryDO.getAmount());
                    }
                    //金额
                    detailObj.set("JE", thisTaxIncludedAmount.setScale(2, RoundingMode.HALF_UP));
                    //不含税金额
                    BigDecimal thisTaxExcludedAmount = thisTaxIncludedAmount.divide(new BigDecimal(1).add(invoiceInventoryDO.getTaxRate()), 2, RoundingMode.HALF_UP);
                    //税额
                    BigDecimal thisSe = thisTaxIncludedAmount.subtract(thisTaxExcludedAmount);
                    detailObj.set("SE", thisSe.setScale(2, RoundingMode.HALF_UP));
                    //扣除额
                    detailObj.set("KCE", invoiceInventoryDO.getDeductionAmount() == null ? "" : invoiceInventoryDO.getDeductionAmount());
                    //行性质。0-正常行 1-折扣行 2-被折扣行
                    detailObj.set("FPHXZ", invoiceInventoryDO.getFphxz());
                    //含税标志
                    detailObj.set("HSBZ", invoiceInventoryDO.getHsbz());
                    //空：非零税率，1：免税，2：不征税 3:普通零税率
                    detailObj.set("LSLBS", invoiceInventoryDO.getLslbs() == null ? "" : invoiceInventoryDO.getLslbs());
                    //0：不使用，1：使用,SPID为空时必填
                    detailObj.set("YHZCBS", invoiceInventoryDO.getYhzcbs());
                    detailArray.add(detailObj);

                    taxExcludedAmount = taxExcludedAmount.add(thisTaxExcludedAmount);
                    se = se.add(thisSe);
                    taxIncludedAmount = taxIncludedAmount.add(thisTaxIncludedAmount);
                }
            }
            //合计金额
            reqObj.set("HJJE", taxExcludedAmount.setScale(2, RoundingMode.HALF_UP));
            //合计税额
            reqObj.set("HJSE", se.setScale(2, RoundingMode.HALF_UP));
            if (StringUtils.isNotBlank(remark)) {
                //备注
                reqObj.set("BZ", remark);
            }
            //价税合计
            reqObj.set("JSHJ", taxIncludedAmount.setScale(2, RoundingMode.HALF_UP));
            //系统来源
            reqObj.set("SX_XTLY", StrUtil.isNotBlank(sysSource) ? sysSource : "SX_LYEQ");
//            reqObj.set("DDMXXX", detailArray);
            jsonObject.set("DDTXX", reqObj);
            jsonObject.set("DDMXXX", detailArray);
//            reqDDZ.add(reqObj);
            reqDDZ.add(jsonObject);
            invoice.setCHjse(se);
            invoice.setCBhsje(taxExcludedAmount);
        });
        requestBody.set("DDZXX", reqDDZ);
        return requestBody;
    }



    private JSONObject buildRequestParamNew(List<InvoiceDO> invoiceList, Integer type, String sysSource, String remark) {
        String taxNum = configApi.getPlatformConfigValueByKey("newinvoice.group.tax");
        String salesName = configApi.getPlatformConfigValueByKey("newinvoice.sales.name");
        String batchNo = IdUtil.fastSimpleUUID();

        JSONObject requestBody = new JSONObject();
        JSONArray reqDDZ = new JSONArray();
        JSONObject reqDDPC = new JSONObject();
        //订单请求批次号
        reqDDPC.set("DDQQPCH", batchNo);
        //纳税人识别号
        reqDDPC.set("NSRSBH", taxNum);
        //发票种类代码01-专用发票 02-普通发票
        if (invoiceList.get(0).getInvoiceType() == null) {
            reqDDPC.set("FPLXDM", "002");
        } else {
            reqDDPC.set("FPLXDM", DigitalInvoiceTypeEnum.valueOf(invoiceList.get(0).getInvoiceType()).getCode());
        }
        requestBody.set("DDPCXX", reqDDPC);
        invoiceList.forEach(invoice -> {
            JSONObject jsonObject = new JSONObject();
            JSONObject reqObj = new JSONObject();
            //订单请求流水号
            reqObj.set("DDQQLSH", invoice.getFpqqlsh());
            //开票类型（0蓝字发票 1红字发票）
            reqObj.set("KPLX", type);
            //销货方纳税人识别号
            reqObj.set("XHFSBH", taxNum);
            //销货方名称
            reqObj.set("XHFMC", salesName);
            //销货方地址
            reqObj.set("XHFDZ", "");
            //销货方电话
            reqObj.set("XHFDH", "");
            //销货方银行名称
            reqObj.set("XHFYH", configApi.getPlatformConfigValueByKey("newinvoice.sales.bank"));
            //销货方银行账号
            reqObj.set("XHFZH", configApi.getPlatformConfigValueByKey("newinvoice.sales.bankaccount"));

            reqObj.set("DDH", invoice.getTransactionNo());

            //开票员，以电子税局绑定人员为准
            reqObj.set("KPR", invoice.getBuyerClerk());

            //购买方编码
            reqObj.set("GMFYH", "");
            //购买方纳税人识别号
            reqObj.set("GMFSBH", invoice.getBuyerTaxCode());
            //购买方名称（当GMFBM为空并且开票方式为自动开票时必填。如果FPLXDM为002，且GMFLX为03(个人)时，GMFMC必须以（个人）字样结尾”(”为全角）
            reqObj.set("GMFMC", invoice.getBuyerName());
            //购买方地址
            reqObj.set("GMFDZ", invoice.getBuyerAddress());
            //购买方电话
            reqObj.set("GMFDH", invoice.getBuyerPhone());
            //购买方银行名称
            reqObj.set("GMFYH", invoice.getBuyerBank());
            //购买方电话
            reqObj.set("GMFZH", invoice.getBuyerAccount());
            //购买方类型(01企业，02机关事业单位，03个人，04其他,如不填写,默认为04)
            if (invoice.getTitleType() != null) {
                if (invoice.getTitleType() == 0) {
                    //购买方名称（当GMFBM为空并且开票方式为自动开票时必填。如果FPLXDM为002，且GMFLX为03(个人)时，GMFMC必须以（个人）字样结尾”(”为全角）
                    reqObj.set("GMFMC", invoice.getBuyerName() + "（个人）");
                    reqObj.set("GMFLX", "03");
                } else if (invoice.getTitleType() == 1) {
                    reqObj.set("GMFLX", "01");
                }
            } else {
                reqObj.set("GMFLX", "04");
            }
//            reqObj.set("GMFLX", invoice.getTitleType());
            //购货方手机
            reqObj.set("GMFSJH", invoice.getBuyerTel());
            //购方邮箱,如果填写,发票类别为电子发票时会自动发送邮件
            reqObj.set("GMFDZYX", invoice.getBuyerEmail());

            JSONArray detailArray = new JSONArray();
            List<InvoiceInventoryDO> inventoryList = invoiceInventoryService.getInvoiceInventoryListByInvoiceId(invoice.getId());
            JSONObject detailObj;
            // 税价合计总金额
            List<BigDecimal> zsjhjList = new ArrayList<>();
            // 总税额
            List<BigDecimal> zseList = new ArrayList<>();
            // 总不含税金额
            List<BigDecimal> zbhsjeList = new ArrayList<>();

            if (inventoryList.isEmpty()) {
                int index = 1;
                detailObj = new JSONObject();
                detailObj.set("XH", index);
                String GoodsCode = configApi.getPlatformConfigValueByKey("newinvoice.goods.code");
                String spbm = StrUtil.padAfter(GoodsCode, 19, "0");
                //商品编码
                detailObj.set("SPBM", spbm);
                String spmc = configApi.getPlatformConfigValueByKey("newinvoice.goods.simpleCode");
                //项目名称
                detailObj.set("XMMC", spmc);
                //税率
                BigDecimal taxRate = new BigDecimal(configApi.getPlatformConfigValueByKey("newinvoice.taxRate"));
                detailObj.set("SL", taxRate);
                //含税金额
                BigDecimal hsje = invoice.getPrice().add(invoice.getZkprice()).setScale(2, RoundingMode.HALF_UP);
                if (type == 1) {
                    hsje = BigDecimal.ZERO.subtract(invoice.getPrice()).setScale(2, RoundingMode.HALF_UP);
                }
                zsjhjList.add(hsje);
                //不含税金额
                BigDecimal bhsje = hsje.subtract(hsje.multiply(taxRate)).setScale(2, RoundingMode.HALF_UP);
                zbhsjeList.add(bhsje);
                detailObj.set("JE", hsje);
                //税额
                BigDecimal se = hsje.subtract(bhsje).setScale(2, RoundingMode.HALF_UP);
                zseList.add(se);
                detailObj.set("SE", se);
                //扣除额
                detailObj.set("KCE", "");
                //行性质。0-正常行 1-折扣行 2-被折扣行
                detailObj.set("FPHXZ", "0");
                //含税标志
                detailObj.set("HSBZ", "1");
                //空：非零税率，1：免税，2：不征税 3:普通零税率
                detailObj.set("LSLBS", "");
                //0：不使用，1：使用,SPID为空时必填
                detailObj.set("YHZCBS", 0);
                detailArray.add(detailObj);


                if(invoice.getZkprice() != null && invoice.getZkprice().compareTo(BigDecimal.ZERO) > 0) {
                    JSONObject detailObj2 = new JSONObject();
                    detailObj2.set("XH", index+1);
                    //商品编码
                    detailObj2.set("SPBM", spbm);
                    //项目名称
                    detailObj2.set("XMMC", spmc);
                    //税率
                    detailObj2.set("SL", taxRate);
                    //含税金额
                    BigDecimal hsje1 = BigDecimal.ZERO.subtract(invoice.getZkprice()).setScale(2, RoundingMode.HALF_UP);
                    zsjhjList.add(hsje1);
                    //不含税金额
                    BigDecimal bhsje1 = hsje1.subtract(hsje1.multiply(taxRate)).setScale(2, RoundingMode.HALF_UP);
                    zbhsjeList.add(bhsje1);
                    //金额
                    detailObj2.set("JE", hsje1);
                    //税额
                    BigDecimal se1 = hsje1.subtract(bhsje1).setScale(2, RoundingMode.HALF_UP);
                    zseList.add(se1);
                    detailObj2.set("SE", se1);
                    //扣除额
                    detailObj2.set("KCE", "");
                    //行性质。0-正常行 1-折扣行 2-被折扣行
                    detailObj2.set("FPHXZ", "1");
                    //含税标志
                    detailObj2.set("HSBZ", "1");
                    //空：非零税率，1：免税，2：不征税 3:普通零税率
                    detailObj2.set("LSLBS", "");
                    //0：不使用，1：使用,SPID为空时必填
                    detailObj2.set("YHZCBS", 0);
                    detailArray.add(detailObj2);
                }

                InvoiceInventorySaveReqVO saveReqVO = new InvoiceInventorySaveReqVO();
                saveReqVO.setInvoiceId(invoice.getId());
                saveReqVO.setSort(index);
                // 总含税金额
                BigDecimal totalHsje = zsjhjList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
                saveReqVO.setAmount(totalHsje);
                // 总税额
                BigDecimal totalSe = zseList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
                saveReqVO.setTax(totalSe);
                saveReqVO.setCode(spbm);
                saveReqVO.setName(spmc);
                saveReqVO.setTaxRate(taxRate);
                saveReqVO.setFphxz(0);
                saveReqVO.setHsbz(1);
                saveReqVO.setYhzcbs(0);
                InvoiceInventoryDO invoiceInventoryDO = invoiceInventoryService.createInvoiceInventory(saveReqVO);
                inventoryList = new ArrayList<>(3);
                inventoryList.add(invoiceInventoryDO);
            } else {
                for (InvoiceInventoryDO invoiceInventoryDO : inventoryList) {
                    detailObj = new JSONObject();
                    detailObj.set("XH", invoiceInventoryDO.getSort());
                    //商品编码
                    detailObj.set("SPBM", invoiceInventoryDO.getCode());
                    //项目名称
                    detailObj.set("XMMC", invoiceInventoryDO.getName());
                    //税率
                    detailObj.set("SL", invoiceInventoryDO.getTaxRate());
                    //含税金额
                    BigDecimal thisTaxIncludedAmount = invoiceInventoryDO.getAmount();
                    if (type == 1) {
                        detailObj.set("DYLZFPMXXH", invoiceInventoryDO.getDylzfpmxxh());
                        thisTaxIncludedAmount = BigDecimal.ZERO.subtract(invoiceInventoryDO.getAmount());
                    }
                    //金额
                    detailObj.set("JE", thisTaxIncludedAmount.setScale(2, RoundingMode.HALF_UP));
                    //不含税金额
                    BigDecimal thisTaxExcludedAmount = thisTaxIncludedAmount.divide(new BigDecimal(1).add(invoiceInventoryDO.getTaxRate()), 2, RoundingMode.HALF_UP);
                    //税额
                    BigDecimal thisSe = thisTaxIncludedAmount.subtract(thisTaxExcludedAmount);
                    detailObj.set("SE", thisSe.setScale(2, RoundingMode.HALF_UP));
                    //扣除额
                    detailObj.set("KCE", invoiceInventoryDO.getDeductionAmount() == null ? "" : invoiceInventoryDO.getDeductionAmount());
                    //行性质。0-正常行 1-折扣行 2-被折扣行
                    detailObj.set("FPHXZ", invoiceInventoryDO.getFphxz());
                    //含税标志
                    detailObj.set("HSBZ", invoiceInventoryDO.getHsbz());
                    //空：非零税率，1：免税，2：不征税 3:普通零税率
                    detailObj.set("LSLBS", invoiceInventoryDO.getLslbs() == null ? "" : invoiceInventoryDO.getLslbs());
                    //0：不使用，1：使用,SPID为空时必填
                    detailObj.set("YHZCBS", invoiceInventoryDO.getYhzcbs());
                    detailArray.add(detailObj);
                }
            }
            // 总不含税金额
            BigDecimal totalBhsje = zbhsjeList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            reqObj.set("HJJE", totalBhsje);
            //合计税额
            BigDecimal totalSe = zseList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            reqObj.set("HJSE", totalSe);
            if (StringUtils.isNotBlank(remark)) {
                //备注
                reqObj.set("BZ", remark);
            }
            //价税合计
            BigDecimal totalSjhj = zsjhjList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            reqObj.set("JSHJ", totalSjhj);
            //系统来源
            reqObj.set("SX_XTLY", StrUtil.isNotBlank(sysSource) ? sysSource : "SX_LYEQ");
//            reqObj.set("DDMXXX", detailArray);
            jsonObject.set("DDTXX", reqObj);
            jsonObject.set("DDMXXX", detailArray);
//            reqDDZ.add(reqObj);
            reqDDZ.add(jsonObject);
            log.error("请求参数：{}", reqDDZ);

            invoice.setCHjse(totalSe);
            invoice.setCBhsje(totalBhsje);
        });
        requestBody.set("DDZXX", reqDDZ);
        return requestBody;
    }

    private JSONObject doRequest(JSONObject reqBody, String method, String secretKey) {
        String url = configApi.getPlatformConfigValueByKey("newinvoice.group.url");
        String secretId = configApi.getPlatformConfigValueByKey("newinvoice.group.secretId");

        // 加密数据
        String paramStr = JsonUtils.toJsonString(reqBody);
        // 加密数据
        String key = secretKey.substring(0, Math.min(secretKey.length(), 24));
        byte[] encryptedData = TripleDesUtil.encrypt(key, paramStr.getBytes(StandardCharsets.UTF_8));
        String contentData = Base64.encodeBase64URLSafeString(encryptedData);
        String reqUrl = url + method;
        JSONObject params = new JSONObject();
        params.set("secretId", secretId);
        //数据流水号,要求唯一不可以重复
//        params.set("dataExchangeId", IdUtil.fastSimpleUUID());
        String dataExchangeId = IdUtil.fastSimpleUUID();
        params.set("dataExchangeId", dataExchangeId);
        //加密标识（0：不加密(使用base64加密） 1-3DES加密）
        params.set("encryptCode", "1");
        //压缩标识（0：不压缩 1：压缩）
        params.set("zipCode", "0");
        //请求内容
        params.set("content", contentData);
        String signature = this.sign(params, reqUrl, Method.POST.name(), secretKey);
        //签名值
        params.set("signature", signature);
        params.set("version", "v6");
        params.set("method", method);

        log.error("集团电子发票请求参数1：{}", paramStr);
        log.error("集团电子发票请求参数2：{}", url + method + "--" + JsonUtils.toJsonString(params));

        String resultStr = HttpUtil.createPost(reqUrl).contentType(ContentType.JSON.getValue())
                .body(JsonUtils.toJsonString(params))
                .timeout(15000)
                .execute().body();
        log.error("{}集团电子电子发票返回：{}",method, resultStr);
        return JSONUtil.parseObj(resultStr);
    }


    /**
     * 加签
     *
     * @param data
     * @param url
     * @param method
     * @return
     */
    private String sign(JSONObject data, String url, String method, String secretKey) {
        Map<String, Object> paramMap = JSONUtil.toBean(data, Map.class);
        // 使用 TreeMap 对参数按 key 自然排序
        Map<String, Object> sortedParams = new TreeMap<>(paramMap);
        // 调用 Hutool 方法生成参数字符串（自动编码）
        String paramStr = HttpUtil.toParams(sortedParams);
        url = url.replace("http://", "").replace("https://", "");
//        String m = url.substring(url.lastIndexOf("/") + 1);
//        url = "10.1.10.132:10000/sims-api/invoice/api/v6/" + m;
        log.error("签名原文url：{}", url);
        //原文
        String riginalStr = StrUtil.builder().append(method).append(url).append("?").append(paramStr).toString();
        return this.hmacSHA1(riginalStr, secretKey);
    }

    public String hmacSHA1(String data, String key) {
        HMac hmac = SecureUtil.hmacSha1(key.getBytes());
        // 计算签名
        byte[] rawHmac = hmac.digest(data.getBytes());
        // 将签名结果转换为 Base64 字符串
        return Base64.encodeBase64URLSafeString(rawHmac);
//        return Base64.encode(rawHmac);
    }

    private LocalDateTime getLocalDateTime(String kprq) {
        DateTime dateTime = DateUtil.parse(kprq);
        return LocalDateTimeUtil.of(dateTime);
    }

    public static void main(String[] args) {
//        byte[] decodeContent = Base64.decodeBase64("P2TV1mSGL4UDsZ1B5+4xPfUWcO0vY7JeUhqaPNnwNDTH8EmI7UgRQQjhnN+px+WmJWVUSxliuwKiLN0ECQSD0hV+Hzkqas8QpWRrjp0eFa0=");
        byte[] decodeContent = Base64.decodeBase64("P2TV1mSGL4UDsZ1B5+4xPfUWcO0vY7JeUhqaPNnwNDTH8EmI7UgRQQjhnN+px+WmJWVUSxliuwKiLN0ECQSD0hV+Hzkqas8QpWRrjp0eFa0=");
//        byte[] decodeContent = Base64.decodeBase64("P2TV1mSGL4XbjAhoHo2vpx6yB15eLOp4VKiOtofxA37a/Hb40nU0g/Cau0alQzhMdu4rw6wRaI//g5zruCHu+xNBtz+Z7iRX8bXTjzFFBSSajFw/UuVie7zYaTqyVXAE2jUyIiy3U4Z6ZhgTAaDhaPiB5DRtqcb0dDuLiD6dloNXVMYn/roT87ZpA5RY3y3+IT9HnozRtWun6QTXcd40kvt/sCX4EPbIuOW7uzx8NBfpF1waqyvvAsBxjmRFpFm8PJZk/lfFK6my92IaiNO2xBjLcc2Y7LR2beZwsQvqdzsJPjGweihJwgonb56ZxKSMv6rUCo7IyDux23CL/ZHFdVyNpsyiK3T9d/BbV0g99OZSj43U6xBhgiMTI/Cp6Gt9g3DpOcHi6JvcpLbe5Yg5OHNcNI1X02tW4E5los4oHzwu0dz3vtEHEeuz+x+SeeBhtgoDE6oy5ncqUIMKrbWSoltYemE8+YTsLjeDoXmX0Bz/J9Fd5dpptXhEWAs2pXD6bKKd7q+7MUZLocZrPkLxB+C0s6kfigG8QiWF8AP4XHHbJ7vJ5rZmThvl96ym/ZoK9NeqUoWjs+JcBLeZUPEdqtBLDzoeeqM+3ZrEsMMyYNja8ZQ3jbSRN/TXqlKFo7PicuZhpsfaLXL1W/Z7/UYcz4s+xNFTSBNSukiXvDLKV0KwWu6FWLfXIl5jFS7jjlDD/iD6lZQVQVy1+/JgXYt95H7kBfo+rp61cnsb/BIgMOsHznQjXtZXOekjQxAA3evwSUIavOtKZ7z7NI8pQbyiT92uYP78cPXxQiWF8AP4XHG8d1Tapl02oydnCfdpwDjFuSh5nc/ssiB2TFrnyLszHWMuG3KB41vJSmXBbXHmuQZybjJGfeADZ3FnYZOo7fThp1WeGzXY6pPK2KG+b9DxTLaZ/aDCWJ71VCnlCrUbMUeXdRpdr6+ZefbFXbz4UbfRlpC8plFGhPhIvrPNnq1iuAiZrDqTGCxVd/PpjVLI5+Y4z6KMniwaO542GxEwgIDeST8Xg1XYP2Sfg32U1ctI0lPaG96+gAnIqMsDkyK/FTdhSBwEHzCGF//8P4EiyZ6DoNqsBztM0Y3zmsqVFJofcHKCAWoiIvoDMP/4GfC1fLFCSrV7Zx45xYkAYQqEWLr3Y3MQjZpWVVXfI5loyhVSzAIZAo6I09So3poYRWaLqZnK4vwxgnoCioACzHgd+snhcQadC0JJr/SHVh0iQg8yognywvxEE+Iwc0xYY829Tj3zu85ODzOtyc4jqx6KXGgQp+y+FT+8fdNCno4BGfPZ+oMJfxU6s7ymbQBzt6aNDQ7P5qBi+wDWodOY7DKOaZQmhMMlTgueI6G2LNLRGu+U7687Fxiiap94wNRkX/9OoLZhss8miVTGViP0BcTegm4f2ETt3wuSnd7XoEtemxIbC7fM86+//iJNmOi3cbtXHI54R7+wcUbiZi43g6F5l9AczNnv2ZPUY5RnSqZwOy/UVb/rUMd1Q9Jf1hKVHeYYwCIdbO6peUr9nzsGCYDSvDaSwceSjphED5s5B3pCUYBq/9M+IT+IV/QhiTf/yEXB7SLd+m61T8QHTH+CddBHfuzTUXczizau2nYj6Z35SsSYOfCau0alQzhMdu4rw6wRaI//g5zruCHu+wGZqCEwHmSzJU6QNrTseDQi2gO1EJzQ2ueddPKl0tx6A2GFfVgozVVn3pYGJ4Kdp3Nwj/rKxrRGpdd6VO1W9/6ncl7zgKxRXCl2mQGHakXzAFqK6c7TfpUj6Z35SsSYOfCau0alQzhMdu4rw6wRaI//g5zruCHu+xNBtz+Z7iRXDMOgmIyTNBq1CVLIxovJ05Yqen+Imc5QqVJV9k0E5vHrwjodRHhMq+JLK/V3M40Mr0JR9zd4S7l4Y/XZb3BKydxJOMS97xUy3URqRnBiHp6Fn0EeU/zbteDHjRnUxjwx/cT2//vZNyF9ehfVXUAjlIZR4XXmVG2PWWixRNn8jzuNIzCr0FdUcufNURsYrHKO4b1yeDYOX9m9pI7zSKyWVW8/FxRicPYsy5uotQzw50ZW+X4a1rkL6d78HdM+cTzKaTjc44L1EtoUAvbG3XXBxXWVi1rDfv91lcmjOF76MILP4/GQhZ1hnZBUIXB8VyqX56zAOnZvkw0efmiBtPSH4xQ6Stw3pGzirFF+N9V0vb1JoX1ybZJA4S/jnMIGhvN9T3jZPYCodoY1pUoLyo00lSOqCOH8btbqtipLSJBpJPZb7VBuxRcBXq3cMNjc8g3o9NeqUoWjs+L61MA5+Y7mZRsutR2XMWQ1qOFoerdG8BZG4F14UGowW29iMN0RgaUD+wxNDHnJ//BCD8ZN9hveILV7UT+QH7EnrCyiWscnaVYHLzPnbsS+o/6u8UCunPvmQY9NlmaK408jqgjh/G7W6uzCGTN6Px9MSN/wLe7fDGXIT3k2gzOt58ACO2gJp8A2XOieURKkgV9m4v1chc7aGQLHCJEA48+sd8MrbEdzGg4npq6rXNUu5xzjTheF/jCIM/8mR3brszounjqjZLp3C1TCuquTSeuVcvKZyag+XpBxp3rrU41SDdEA6455SurhXQS8kTi9Imb4ioGuiiHVCK8ujlBVokkYMnMYnN1NJ83PgAfZMW1bb3EguUIAX7kIyv7U/MPsbCVNr9XP0eR1ZYW/12EmfvSOzdQgVs+Dzpxkcn0kutu8KZJmV/oA7zd4WEYE6wGtEEko9JXbq+v9f3MfRVusflWFIZytQl40/d+kI47lpnIJsufPhMZ8RMJa8tpOnZ1ZkQwNKZ5Kf36Z2T/exia1mSPPAgtZQOOHJ3Iz2emFCw73Y/BGby3tkDAl9RZw7S9jsl4KCScxaU/xklN/zcFPoda/9oL93VyDo7Nd5XyLOXtNGL9AAwXg9wFqG4Cnxn8K/ISZLW6rFMh7A6CgD0BxiezBfJ00Od4JoQ+Aw4Eq5Ww4AbRWYIF/hrVRjo1uQZC23/+eXpj3VON7hQoVwhBhdP79");
        String secretKey = "RX0GTlFnVk2r8ZgJlA2CXtpwRjChEbxo91mz";
        decodeContent = TripleDesUtil.decrypt(secretKey.substring(0, Math.min(secretKey.length(), 24)), decodeContent);
        String content = StrUtil.str(decodeContent, StandardCharsets.UTF_8);
        System.out.println(content);
        //{"HZFPXX":{"DDFPXX":{"BMBBBH":"36.0","BYZD1":"","BYZD2":"","BYZD3":"","BYZD4":"","BYZD5":"","BZ":"","CHBZ":"0","CHYY":"2","DDH":"IVE2026042415170000110","DDLX":"0","DDLY":"3","DDQQLSH":"1212623796021043200","DDSJ":"2026-05-08 15:00:52","DDZT":"032000","DDZTXX":"订单开票中","DFGTGMBZ":"","DTM":"","ENTID":"1027395519858941985","EWM":"","FHR":"","FJH":"","FPDM":"","FPHM":"","FPLXDM":"002","FWM":"","GMFBM":"","GMFDH":"","GMFDZ":"","GMFDZYX":"906534176@qq.com","GMFGJ":"","GMFLX":"01","GMFMC":"测试旅行社001","GMFSBH":"913301087458306077","GMFSJH":"18628286025","GMFYH":"","GMFZH":"","GMFZJHM":"","GMFZJLX":"","GMFZJLXDM":"","HJJE":"-0.94","HJSE":"-0.06","HZXXBBH":"","JQBH":"","JSHJ":"-1.00","JYM":"","KPFS":"0","KPJH":"","KPLX":"1","KPR":"陈心雨","KPRQ":"","KPRZJHM":"","KPRZJLX":"","KPZD":"","PDFZJL":"","QDBZ":"0","SDEWMURL":"","SDFPHM":"","SFCF":"","SKR":"","SLKJLY":"","TQM":"","TSCHBZ":"","XHFDH":"0717-6900579","XHFDZ":"宜昌市夷陵区三斗坪镇黄陵庙村一组","XHFMC":"宜昌长江国际旅行社有限公司","XHFSBH":"91420500737133035K","XHFYH":"1","XHFZH":"1","YFPDM":"","YFPHM":"26427000000001615911","YFPKPRQ":"","YFPLX":"","YHM":"","YWLX":"","ZFBZ":"0","ZJLLX":""},"DDKZXX":[{"BYZD1":"","BYZD2":"","BYZD3":"","DDH":"IVE2026042415170000110","DDLX":"0","DDQQLSH":"1212623796021043200"}],"DDMXXX":[{"BYZD1":"","BYZD2":"","BYZD3":"","BZ":"","DJ":"","DW":"","FPHXZ":"0","FYMX":"","GGXH":"","HSBZ":"0","JE":"-0.94","KCE":"","LSLBS":"","MTZLDM":"","SE":"-0.06","SL":"0.06","SPBM":"3070301000000000000","SPSL":"","XH":"1","XMMC":"*旅游服务*旅游服务费","YHZCBS":"0","YLFWGBM":"","ZXBM":"","ZZSTSGL":""}],"QDTXX":{"BFCPSGXSLZ":"","CEZSLXDM":"","CKYWSYZCDM":"","GMFJBR":"","GMFJBRLXDH":"","JAZSLXDM":"","JBRSFZJHM":"","JSFS":"","MTPZXX":"","QYDM":"","REMIND_INFO":"","SGFPLXDM":"","SKYHMC":"","SKYHZH":"","TDYS":"","XSEQRBZ":"","YSXWFSD":"","YYBLDJ":"","ZPPZDM":"","ZZID":"1027395519858941985","ZZSJZJTDM":""}},"HZQRDXX":{"HZCXJE":"-0.94","HZCXSE":"-0.06","HZFPHM":"26427000000001616024","HZFPXXQRDBH":"42050326051000502207","HZKPRQ":"2026-05-08 15:00:52","HZQRXXZTDM":"01","LRRQ":"2026-05-08 15:00:52","UUID":"0a0ae9fd177f4042ab32a0c91a88bd6e","YKJHZFPBZ":"Y","YXBZ":"Y"},"ZTDM":"001000","ZTXX":"订单开票中"}

    }
}
