package cn.superdesk.uniorder.service.thirdpart.szhtxx.paperInvoice.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderTypeDimEnum;
import cn.superdesk.uniorder.common.enums.invoice.customer.InvoiceApplyBecomeInvalidEnum;
import cn.superdesk.uniorder.common.enums.thirdpart.szhtxx.electronicInvoice.SzhtxxElectronicInvoiceFptxxInvoiceTypeEnum;
import cn.superdesk.uniorder.common.lamda.AnLamdaUtils;
import cn.superdesk.uniorder.common.security.dto.LoginSysUser;
import cn.superdesk.uniorder.dao.entity.invoice.customer.InvoiceApply;
import cn.superdesk.uniorder.dao.entity.sys.notify.SysNotify;
import cn.superdesk.uniorder.dao.entity.thirdpart.szhtxx.electronicInvoice.SzhtxxElectronicInvoiceFptxxExtendInfo;
import cn.superdesk.uniorder.dto._constant.ResourceConstant;
import cn.superdesk.uniorder.dto.param.thirdpart.szhtxx.common.becomeInvalid.SzhtxxInvoiceFptxxOpBecomeInvalidForm;
import cn.superdesk.uniorder.dto.param.thirdpart.szhtxx.common.redBitchLlq.SzhtxxInvoiceFptxxOpRedLowerWorkLlqForm;
import cn.superdesk.uniorder.dto.param.thirdpart.szhtxx.common.singleBilling.SzhtxxInvoiceFptxxOpSingleBillingForm;
import cn.superdesk.uniorder.dto.param.thirdpart.szhtxx.common.taxDeviceInfo.SzhtxxPaperInvoiceOpTaxDeviceInfoForm;
import cn.superdesk.uniorder.dto.param.thirdpart.szhtxx.common.taxInfo.SzhtxxPaperInvoiceOpTaxInfoForm;
import cn.superdesk.uniorder.dto.vo.thirdpart.szhtxx.electronicInvoice.SzhtxxElectronicInvoiceFptxxListItemVo;
import cn.superdesk.uniorder.event.invoiceApplyCustomerTrigger.InvoiceApplyCustomerTriggerEventPublisher;
import cn.superdesk.uniorder.event.invoiceApplyCustomerTrigger.TailUpdateAccountingScoreCustomerFieldInvoiceStatusEvent;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.electronicInvoice.dto.request.SingleBillingRequestBodyKpContent;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.electronicInvoice.dto.request.SingleBillingRequestBodyKpContentFptxxVo;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.electronicInvoice.dto.request.SingleBillingRequestBodyKpContentXmxxItemVo;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID121TaxInfo.SID121TaxInfoRequestBody;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID1SingleBilling.SID1SingleBillingRequestBody;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID20BitchLlq.ID0200.GoodsMxType;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID20BitchLlq.ID0200.RedInvReqBillMxType;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID20BitchLlq.ID0200.RedInvReqBillType;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID20BitchLlq.ID0200.SID20BitchLlqRequestID0200FpxtTypeFactory;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID20BitchLlq.ID0201.SID20BitchLlqRequestID0201FpxtTypeFactory;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID20BitchLlq.SID20BitchLlqRequestBody;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID25TaxDeviceInfo.SID25TaxDeviceInfoRequestBody;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID4ToInvalid.SID4ToInvalidRequestBody;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID4ToInvalid.SID4ToInvalidRequestBodyStructVo;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID5SelectBillInfo.SID5SelectBillInfoRequestBody;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID5SelectBillInfo.SID5SelectBillInfoRequestBodyStructVo;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID121TaxInfo.SID121TaxInfoResponseBody;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID121TaxInfo.SID121TaxInfoResponseBodyEncmsgVo;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID1SingleBilling.SID1SingleBillingResponseBody;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID1SingleBilling.SID1SingleBillingResponseBodyEncmsgVo;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID20BitchLlq.FpxtComOutputStruct;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID20BitchLlq.SID20BitchLlqResponseBody;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID20BitchLlq.SID20BitchLlqResponseBodyEncmsgVo;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID25TaxDeviceInfo.SID25TaxDeviceInfoResponseBody;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID25TaxDeviceInfo.SID25TaxDeviceInfoResponseBodyEncmsgVo;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID4ToInvalid.SID4ToInvalidResponseBody;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID4ToInvalid.SID4ToInvalidResponseBodyEncmsgVo;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID5SelectBillInfo.SID5SelectBillInfoResponseBody;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID5SelectBillInfo.SID5SelectBillInfoResponseBodyEncmsgVo;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID5SelectBillInfo.SID5SelectBillInfoResponseBodyEncmsgVoFpItemBean;
import cn.superdesk.uniorder.service.invoice.customer.InvoiceApplyCustomerService;
import cn.superdesk.uniorder.service.invoice.customer.InvoiceApplyXGoodsService;
import cn.superdesk.uniorder.service.invoice.customer.state.InvoiceApplyCustomerFieldBackAccountStatusService;
import cn.superdesk.uniorder.service.invoice.customer.state.InvoiceApplyCustomerFieldMakeInvoiceStatusOpOngoingSzhtxxElectronicInvoiceService;
import cn.superdesk.uniorder.service.invoice.customer.state.InvoiceApplyCustomerFieldMakeInvoiceStatusOpOngoingSzhtxxPaperInvoiceService;
import cn.superdesk.uniorder.service.thirdpart.szhtxx.electronicInvoice.SzhtxxElectronicInvoiceFptxxExtendInfoService;
import cn.superdesk.uniorder.service.thirdpart.szhtxx.electronicInvoice.SzhtxxElectronicInvoiceFptxxResultService;
import cn.superdesk.uniorder.service.thirdpart.szhtxx.electronicInvoice.SzhtxxElectronicInvoiceFptxxService;
import cn.superdesk.uniorder.service.thirdpart.szhtxx.electronicInvoice.SzhtxxElectronicInvoiceFptxxXmxxService;
import cn.superdesk.uniorder.service.thirdpart.szhtxx.paperInvoice.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

/**
 * @Description: Java类作用描述
 * @Author: linjinyu
 * @CreateDate: 2022/4/26 9:50 上午
 * @UpdateUser: linjinyu
 * @UpdateDate: 2022/4/26 9:50 上午
 * @UpdateRemark: 修改内容
 * @Version: 1.0
 */
@Slf4j
@Service
public class SzhtxxPaperInvoiceFptxxServiceImpl implements SzhtxxPaperInvoiceFptxxService {


    @Resource
    private Snowflake snowflake;

    @Autowired
    private SzhtxxElectronicInvoiceFptxxService           szhtxxElectronicInvoiceFptxxService;
    @Autowired
    private SzhtxxElectronicInvoiceFptxxExtendInfoService szhtxxElectronicInvoiceFptxxExtendInfoService;
    @Autowired
    private SzhtxxElectronicInvoiceFptxxResultService     szhtxxElectronicInvoiceFptxxResultService;
    @Autowired
    private SzhtxxElectronicInvoiceFptxxXmxxService       szhtxxElectronicInvoiceFptxxXmxxService;

    @Autowired
    private SzhtxxPaperInvoiceRedTaxInfoService                    szhtxxPaperInvoiceRedTaxInfoService;
    @Autowired
    private SzhtxxPaperInvoiceFptxxSID1SingleBillingProcessService szhtxxPaperInvoiceFptxxSID1SingleBillingProcessService;
    @Autowired
    private SzhtxxPaperInvoiceFptxxSID20BitchLlqService            szhtxxPaperInvoiceFptxxSID20BitchLlqService;

    @Autowired
    private SzhtxxPaperInvoiceFptxxLogService szhtxxPaperInvoiceFptxxLogService;

    @Autowired
    public  InvoiceApplyCustomerService invoiceApplyCustomerService;
    @Autowired
    private InvoiceApplyXGoodsService   invoiceApplyXGoodsService;

    @Autowired
    private InvoiceApplyCustomerFieldBackAccountStatusService                                 invoiceApplyCustomerFieldBackAccountStatusService;
    @Autowired
    private InvoiceApplyCustomerFieldMakeInvoiceStatusOpOngoingSzhtxxElectronicInvoiceService invoiceApplyCustomerFieldMakeInvoiceStatusOpOngoingSzhtxxElectronicInvoiceService;
    @Autowired
    private InvoiceApplyCustomerFieldMakeInvoiceStatusOpOngoingSzhtxxPaperInvoiceService      invoiceApplyCustomerFieldMakeInvoiceStatusOpOngoingSzhtxxPaperInvoiceService;

    @Autowired
    private InvoiceApplyCustomerTriggerEventPublisher invoiceApplyCustomerTriggerEventPublisher;

    @Autowired
    private ResourceConstant resourceConstant;


    /**************************************** 金税盘页面-发起-op红冲发票(纸质专用发票)(深圳航信纸质票) start ****************************************/

    /**
     * op发起红冲
     *
     * @param form
     * @param fptxxListItemVo
     * @param invoiceApplyCustomerEntity
     * @param loginSysUser
     * @return
     */
    @Deprecated
    public SID1SingleBillingRequestBody opRedWriteRequest(
            SzhtxxInvoiceFptxxOpSingleBillingForm form,
            SzhtxxElectronicInvoiceFptxxListItemVo fptxxListItemVo,
            InvoiceApply invoiceApplyCustomerEntity,
            LoginSysUser loginSysUser) {


        SID1SingleBillingRequestBody sid1SingleBillingRequestBody = invoiceApplyCustomerFieldMakeInvoiceStatusOpOngoingSzhtxxPaperInvoiceService.opOngoingInvoiceTypeEq2InvoiceModeEqSzhtxxPaperInvoiceRedWriteRequest(
                form,
                fptxxListItemVo,
                invoiceApplyCustomerEntity,
                loginSysUser
        );

        return sid1SingleBillingRequestBody;
    }

    /**
     * op确认红冲 -- 目前逻辑在这 -- // -- 对映 -- SysNotify opRedWrite(SzhtxxInvoiceFptxxOpSingleBillingForm form, SzhtxxElectronicInvoiceFptxxListItemVo fptxxListItemVo, InvoiceApply invoiceApplyEntity, LoginSysUser loginSysUser);
     *
     * @param form
     * @param fptxxListItemVo
     * @param invoiceApplyEntity
     * @param loginSysUser
     * @return
     */
    public SysNotify opRedWriteResponse(
            SzhtxxInvoiceFptxxOpSingleBillingForm form,
            SzhtxxElectronicInvoiceFptxxListItemVo fptxxListItemVo,
            InvoiceApply invoiceApplyEntity,
            LoginSysUser loginSysUser) {

        SID1SingleBillingResponseBody sid1SingleBillingResponseBody = SID1SingleBillingResponseBody
                .builder()
                .batchId(form.getBatchId())
//                      .fpqqlsh(form.getFpqqlsh()) // 这里是错的 fpqqlsh是发票红冲时用  invoiceApplySn是发起开票时用
                .fpqqlsh(form.getInvoiceApplySn())
                .ENCMSG(form.getENCMSG())
                .build();

        sid1SingleBillingResponseBody.unPacking();

        log.info("\n表单\n{}\n密文\n{}\n解密\n{}\n总体\n{}",
                JSONUtil.toJsonPrettyStr(form),
                sid1SingleBillingResponseBody.getENCMSG(),
                JSONUtil.toJsonStr(sid1SingleBillingResponseBody.getEncmsgVo()),
                JSONUtil.toJsonPrettyStr(sid1SingleBillingResponseBody)
        );

        SID1SingleBillingResponseBodyEncmsgVo response = sid1SingleBillingResponseBody.getEncmsgVo();

        if (ObjectUtil.isNotNull(response) && "4011".equals(response.getReturnCode())) {

            // 记录
            szhtxxPaperInvoiceFptxxSID1SingleBillingProcessService.recordSID1SingleBillingResponse(form, sid1SingleBillingResponseBody, loginSysUser);

            return SysNotify.builder()
                    .title(response.getReturnCode())
                    .content(response.getReturnMsg())
                    .build();
        } else {
            return SysNotify.builder()
                    .title(response.getReturnCode())
                    .content(response.getReturnMsg())
                    .build();
        }
    }


    /**************************************** 金税盘页面-发起-op红冲发票(纸质专用发票)(深圳航信纸质票) start ****************************************/


    /**************************************** 金税盘页面-发起-op作废发票(纸质专用发票)(深圳航信纸质票) start ****************************************/

    @Override
    public SID4ToInvalidRequestBody opBecomeInvalidRequest(
            SzhtxxInvoiceFptxxOpBecomeInvalidForm form,
            SzhtxxElectronicInvoiceFptxxListItemVo fptxxListItemVo,
            InvoiceApply entity,
            LoginSysUser loginSysUser) {

        String   nowStr      = DateUtil.now();
        DateTime nowDate     = DateUtil.date();
        String   batchId     = snowflake.nextIdStr();
        String   fpqqlshBlue = form.getFpqqlsh();

        SID4ToInvalidRequestBody sid4ToInvalidRequestBody = SID4ToInvalidRequestBody
                .builder()

                .SID("4")
//                .SIDParam() ---- packing() 装填
                .batchId(batchId)
                .fpqqlsh(fpqqlshBlue)

                .structVo(SID4ToInvalidRequestBodyStructVo
                        .builder()
                        .infoKind(SzhtxxElectronicInvoiceFptxxInvoiceTypeEnum.专票.getKey())
                        .infoNumber(fptxxListItemVo.getFphm())
                        .infoTypeCode(fptxxListItemVo.getFpdm())
                        .issuer(loginSysUser.getFullName()) // ---- 作废人，(使用百旺组件版时传递)
                        .build()
                )
                .build();

        szhtxxPaperInvoiceFptxxLogService.tmpLog("recordRequestForm", "SID4ToInvalid", fpqqlshBlue, batchId, JSONUtil.toJsonPrettyStr(form), nowStr);
        szhtxxPaperInvoiceFptxxLogService.tmpLog("recordRequestBody", "SID4ToInvalid", fpqqlshBlue, batchId, JSONUtil.toJsonPrettyStr(sid4ToInvalidRequestBody.packing()), nowStr);
        szhtxxPaperInvoiceFptxxLogService.tmpLog("recordRequestUser", "SID4ToInvalid", fpqqlshBlue, batchId, JSONUtil.toJsonPrettyStr(loginSysUser), nowStr);

        return sid4ToInvalidRequestBody;

    }

    /**
     * op作废发票(纸质专用发票)(深圳航信纸质票)
     *
     * @param form
     * @param fptxxListItemVo
     * @param invoiceApplyEntity
     * @param loginSysUser
     * @return
     */
    @Override
    public SysNotify opBecomeInvalidResponse(
            SzhtxxInvoiceFptxxOpBecomeInvalidForm form,
            SzhtxxElectronicInvoiceFptxxListItemVo fptxxListItemVo,
            InvoiceApply invoiceApplyEntity,
            LoginSysUser loginSysUser) {

        String   nowStr      = DateUtil.now();
        DateTime nowDate     = DateUtil.date();
        String   batchId     = form.getBatchId();
        String   fpqqlshBlue = form.getFpqqlsh();

        SID4ToInvalidResponseBody sid4ToInvalidResponseBody = SID4ToInvalidResponseBody
                .builder()
                .batchId(form.getBatchId())
//                      .fpqqlsh(form.getFpqqlsh()) // 这里是错的 fpqqlsh是发票红冲时用  invoiceApplySn是发起开票时用
                .fpqqlsh(form.getInvoiceApplySn())
                .ENCMSG(form.getENCMSG())
                .build();

        szhtxxPaperInvoiceFptxxLogService.tmpLog("recordResponseForm", "SID4ToInvalid", fpqqlshBlue, batchId, JSONUtil.toJsonPrettyStr(form), nowStr);
        szhtxxPaperInvoiceFptxxLogService.tmpLog("recordResponseBody", "SID4ToInvalid", fpqqlshBlue, batchId, JSONUtil.toJsonPrettyStr(sid4ToInvalidResponseBody.unPacking()), nowStr);
        szhtxxPaperInvoiceFptxxLogService.tmpLog("recordResponseUser", "SID4ToInvalid", fpqqlshBlue, batchId, JSONUtil.toJsonPrettyStr(loginSysUser), nowStr);

        sid4ToInvalidResponseBody.unPacking();

        log.info("\n表单\n{}\n密文\n{}\n解密\n{}\n总体\n{}",
                JSONUtil.toJsonPrettyStr(form),
                sid4ToInvalidResponseBody.getENCMSG(),
                JSONUtil.toJsonStr(sid4ToInvalidResponseBody.getEncmsgVo()),
                JSONUtil.toJsonPrettyStr(sid4ToInvalidResponseBody)
        );

        SID4ToInvalidResponseBodyEncmsgVo response = sid4ToInvalidResponseBody.getEncmsgVo();

        // 正常情况
        if (ObjectUtil.isNotNull(response)
                && "6011".equals(response.getReturnCode())) {

            // TODO ...

//（1）若提交深圳航信纸质发票作废，返回作废成功：

//·将该发票的回款状态变更为“发票作废”；----
//·将该发票的作废标志变更为“已作废”；----
//·将该发票的回款状态变更为“发票作废”；----
//·将作废原因内容覆盖填充到该发票的备注中，非发票备注；---- ? 什么鬼
//·该发票的作废人和作废时间记录为当前操作人姓名和时间；----
//·该发票的更新人和更新时间记录为当前操作人姓名和时间；----
//·将该发票所关联的开票申请的申请状态变更为“已作废”；----
//·同时解除该开票申请与该发票的开票申请数据的关系；----
//·作废原因记录到该开票申请的开票备注中；----
//·将该开票申请的所有订单流水数据释放回该对账单中，流水的申请状态变更为“未申请”，流水的开票状态变更为“待开票”；
//·该对账单的申请状态“未申请/部分申请/全部申请”，重新校验更新；----
//·该对账单的更新人和更新时间更新为当前的操作人姓名及时间；---- 级联
//·该开票申请的更新人和更新时间更新为当前的操作人姓名及时间；----
//·记录作废操作日志；
//·弹窗关闭，1.5s提示“该发票已作废”，列表数据更新；
//（2）若提交深圳航信纸质发票作废，返回作废失败：1.5s提示“第三方返回msg”错误内容；
//（3）若提交深圳航信电纸质发票作废，30s内（此时间技术可自定）超时第三方仍未返回结果，视为作废失败：----
//·1.5s提示“发票作废异常，请返回重新作废”，自动跳转到“金税盘发票”列表页面，列表数据更新；
//·该发票数据保持原状不变；

//            String fpqqlshBlue = form.getFpqqlsh();
//            DateTime now = DateUtil.date();

            SzhtxxElectronicInvoiceFptxxExtendInfo extendInfoBlue = szhtxxElectronicInvoiceFptxxExtendInfoService.findByFpqqlsh(fpqqlshBlue);

            szhtxxElectronicInvoiceFptxxExtendInfoService.saveOrUpdateByFpqqlsh(
                    SzhtxxElectronicInvoiceFptxxExtendInfo
                            .builder()
                            .fpqqlsh(extendInfoBlue.getFpqqlsh())

                            //·将该发票的作废标志变更为“已作废”；
                            .flagVoidSign(InvoiceApplyBecomeInvalidEnum.已作废.getKey())

                            .becomeInvalidReason(form.getBecomeInvalidReason())
                            //·该发票的作废人和作废时间记录为当前操作人姓名和时间；
                            .becomeInvalidTime(nowDate)
                            .becomeInvalidUserId(loginSysUser.getSysUserId())
                            .becomeInvalidUserName(loginSysUser.getFullName())

                            //·将作废原因内容覆盖填充到该发票的备注中，非发票备注；? 什么鬼,原来是这个
                            .remark2(form.getBecomeInvalidReason())

                            //·该发票的更新人和更新时间记录为当前操作人姓名和时间；
                            .updateUserId(loginSysUser.getSysUserId())
                            .updateUserName(loginSysUser.getFullName())
                            .updateTime(nowDate)

                            .build()
            );


            //·作废原因记录到该开票申请的开票备注中；
            //·该开票申请的更新人和更新时间更新为当前的操作人姓名及时间；
            //·将该发票所关联的开票申请的申请状态变更为“已作废”；
            //·将该发票的回款状态变更为“发票作废”；
            int retOpBecomeInvalid = invoiceApplyCustomerFieldBackAccountStatusService
                    .opBecomeInvalidByStateMachine(
                            fpqqlshBlue,
                            form.getBecomeInvalidReason(),
                            loginSysUser
                    );

            log.info("retOpBecomeInvalid = {}", retOpBecomeInvalid);

            if (retOpBecomeInvalid == 1) {

                // 得出受影响的对账单 ids
                List<Long> affectedAccountingOrderIds = invoiceApplyXGoodsService
                        .getAffectedAccountingOrderIdsByInvoiceApplyId(
                                invoiceApplyEntity.getId()
                        );

                // 清理 invoiceApply X goods 对账单相关信息没有在 invoiceApply, 要用 invoiceApplyId 去查 invoiceOrder
                //·同时解除该开票申请与该发票的开票申请数据的关系；

                // 标志 20220509 start ---- 逻辑修改为
                // 包含流水的三个状态复位
                // 1. InvoiceApplyStatus
                // 2. InvoiceMakeStatus
                // 3. BackAccountStatus
                int retSecond = invoiceApplyXGoodsService
                        .dumpXByInvoiceApplyId(
                                invoiceApplyEntity.getId()
                        );

                /**
                 * 通过 对账单 ids(得出受影响的对账单 ids)
                 * 再去 较验 对账单 发票状态
                 */
                //·该对账单的申请状态“未申请/部分申请/全部申请”，重新校验更新；----
                //·该对账单的更新人和更新时间更新为当前的操作人姓名及时间；---- 级联
                invoiceApplyCustomerTriggerEventPublisher.triggerTailUpdateAccountingOrderFieldInvoiceStatus(
                        TailUpdateAccountingScoreCustomerFieldInvoiceStatusEvent
                                .builder()
                                .affectedAccountingOrderIds(affectedAccountingOrderIds)
                                .dim(AccountingOrderTypeDimEnum.积分订单)
                                .invoiceApplyId(invoiceApplyEntity.getId())
                                .loginSysUser(loginSysUser)
                                .build());
            }

            return SysNotify.builder()
                    .title(response.getReturnCode())
                    .content(response.getReturnMsg())
                    .build();
        }
        // 异常情况
        // 410387 不能重复作废
        else {
            return SysNotify
                    .builder()
                    .title(response.getReturnCode())
                    .content(response.getReturnMsg())
                    .build();
        }


    }

    /**************************************** 金税盘页面-发起-op作废发票(纸质专用发票)(深圳航信纸质票) start ****************************************/


    /**************************************** 金税盘页面-发起-op发票作废状态修复(纸质专用发票)(深圳航信纸质票) start ****************************************/

    @Override
    public SID5SelectBillInfoRequestBody opBecomeInvalidFakeRequest(
            SzhtxxInvoiceFptxxOpBecomeInvalidForm form,
            SzhtxxElectronicInvoiceFptxxListItemVo fptxxListItemVo,
            InvoiceApply entity,
            LoginSysUser loginSysUser) {

        String   nowStr      = DateUtil.now();
        DateTime nowDate     = DateUtil.date();
        String   batchId     = snowflake.nextIdStr();
        String   fpqqlshBlue = form.getFpqqlsh();

        SID5SelectBillInfoRequestBody sid5SelectBillInfoRequestBody = SID5SelectBillInfoRequestBody
                .builder()

                .SID("5")
//                .SIDParam() ---- packing() 装填
                .batchId(batchId)
                .fpqqlsh(fpqqlshBlue)

                .structVo(SID5SelectBillInfoRequestBodyStructVo
                        .builder()
                        .fpzl(SzhtxxElectronicInvoiceFptxxInvoiceTypeEnum.专票.getKey())
                        .fphm(fptxxListItemVo.getFphm())
                        .fpdm(fptxxListItemVo.getFpdm())
                        .build()
                )
                .build();

        szhtxxPaperInvoiceFptxxLogService.tmpLog("recordRequestForm", "SID5SelectBillInfo", fpqqlshBlue, batchId, JSONUtil.toJsonPrettyStr(form), nowStr);
        szhtxxPaperInvoiceFptxxLogService.tmpLog("recordRequestBody", "SID5SelectBillInfo", fpqqlshBlue, batchId, JSONUtil.toJsonPrettyStr(sid5SelectBillInfoRequestBody.packing()), nowStr);
        szhtxxPaperInvoiceFptxxLogService.tmpLog("recordRequestUser", "SID5SelectBillInfo", fpqqlshBlue, batchId, JSONUtil.toJsonPrettyStr(loginSysUser), nowStr);

        return sid5SelectBillInfoRequestBody;
    }

    @Override
    public SysNotify opBecomeInvalidFakeResponse(
            SzhtxxInvoiceFptxxOpBecomeInvalidForm form,
            SzhtxxElectronicInvoiceFptxxListItemVo fptxxListItemVo,
            InvoiceApply invoiceApplyEntity,
            LoginSysUser loginSysUser) {


        String   nowStr      = DateUtil.now();
        DateTime nowDate     = DateUtil.date();
        String   batchId     = form.getBatchId();
        String   fpqqlshBlue = form.getFpqqlsh();

        SID5SelectBillInfoResponseBody sid5SelectBillInfoResponseBody = SID5SelectBillInfoResponseBody
                .builder()
                .batchId(form.getBatchId())
//                      .fpqqlsh(form.getFpqqlsh()) // 这里是错的 fpqqlsh是发票红冲时用  invoiceApplySn是发起开票时用
                .fpqqlsh(form.getInvoiceApplySn())
                .ENCMSG(form.getENCMSG())
                .build();


        szhtxxPaperInvoiceFptxxLogService.tmpLog("recordResponseForm", "SID5SelectBillInfo", fpqqlshBlue, batchId, JSONUtil.toJsonPrettyStr(form), nowStr);
        szhtxxPaperInvoiceFptxxLogService.tmpLog("recordResponseBody", "SID5SelectBillInfo", fpqqlshBlue, batchId, JSONUtil.toJsonPrettyStr(sid5SelectBillInfoResponseBody.unPacking()), nowStr);
        szhtxxPaperInvoiceFptxxLogService.tmpLog("recordResponseUser", "SID5SelectBillInfo", fpqqlshBlue, batchId, JSONUtil.toJsonPrettyStr(loginSysUser), nowStr);


        sid5SelectBillInfoResponseBody.unPacking();

        log.info("\n表单\n{}\n密文\n{}\n解密\n{}\n总体\n{}",
                JSONUtil.toJsonPrettyStr(form),
                sid5SelectBillInfoResponseBody.getENCMSG(),
                JSONUtil.toJsonStr(sid5SelectBillInfoResponseBody.getEncmsgVo()),
                JSONUtil.toJsonPrettyStr(sid5SelectBillInfoResponseBody)
        );

        SID5SelectBillInfoResponseBodyEncmsgVo response = sid5SelectBillInfoResponseBody.getEncmsgVo();

        // 正常情况 !!!! 返回码 0 查询成功；其它失败 !!!!
        if (ObjectUtil.isNotNull(response)
                && "0".equals(response.getReturnCode())) {


            List<SID5SelectBillInfoResponseBodyEncmsgVoFpItemBean> fpArray = response.getFpArray();

            if (CollUtil.isEmpty(fpArray)) {
                return SysNotify.builder()
//                        .title(response.getReturnCode())
                        .title("555")
//                        .content(response.getReturnMsg())
                        .content("发票作废修复异常，请返回重新修复") // [未返回发票信息]
                        .build();
            }

            List<Predicate<SID5SelectBillInfoResponseBodyEncmsgVoFpItemBean>> predicatesFpdmFphm = new ArrayList<>();
            predicatesFpdmFphm.add(
                    r -> r.getFpdm() != null
                            && r.getFphm() != null
                            && r.getFpdm().equals(fptxxListItemVo.getFpdm())
                            && r.getFphm().equals(fptxxListItemVo.getFphm())
            );
            List<SID5SelectBillInfoResponseBodyEncmsgVoFpItemBean> fpArrayFilter = AnLamdaUtils.filters(fpArray, predicatesFpdmFphm);

            SID5SelectBillInfoResponseBodyEncmsgVoFpItemBean fpItemBean = null;

            if (CollUtil.isNotEmpty(fpArrayFilter)) {
                fpItemBean = fpArrayFilter.get(0);
            } else {
                fpItemBean = fpArray.get(0);

                return SysNotify.builder()
                        .title("500")
                        .content(StrUtil.format("第三方返回{}发票号与当前查询发票号码不一致", fpItemBean.getFphm()))
                        .build();
            }


            if (fpItemBean.getZfbz().equals("0")) {
                return SysNotify.builder()
                        .title("500")
                        .content("该发票未作废，请先在开票软件上使用【发票修复】功能修复数据")
                        .build();
            }


            //（1）若提交深圳航信纸质发票作废，返回作废成功：

            //·将该发票的回款状态变更为“发票作废”；----
            //·将该发票的作废标志变更为“已作废”；----
            //·将该发票的回款状态变更为“发票作废”；----
            //·将作废原因内容覆盖填充到该发票的备注中，非发票备注；---- ? 什么鬼
            //·该发票的作废人和作废时间记录为当前操作人姓名和时间；----
            //·该发票的更新人和更新时间记录为当前操作人姓名和时间；----
            //·将该发票所关联的开票申请的申请状态变更为“已作废”；----
            //·同时解除该开票申请与该发票的开票申请数据的关系；----
            //·作废原因记录到该开票申请的开票备注中；----
            //·将该开票申请的所有订单流水数据释放回该对账单中，流水的申请状态变更为“未申请”，流水的开票状态变更为“待开票”；
            //·该对账单的申请状态“未申请/部分申请/全部申请”，重新校验更新；----
            //·该对账单的更新人和更新时间更新为当前的操作人姓名及时间；---- 级联
            //·该开票申请的更新人和更新时间更新为当前的操作人姓名及时间；----
            //·记录作废操作日志；
            //·弹窗关闭，1.5s提示“该发票已作废”，列表数据更新；
            //（2）若提交深圳航信纸质发票作废，返回作废失败：1.5s提示“第三方返回msg”错误内容；
            //（3）若提交深圳航信电纸质发票作废，30s内（此时间技术可自定）超时第三方仍未返回结果，视为作废失败：----
            //·1.5s提示“发票作废异常，请返回重新作废”，自动跳转到“金税盘发票”列表页面，列表数据更新；
            //·该发票数据保持原状不变；

            SzhtxxElectronicInvoiceFptxxExtendInfo extendInfoBlue = szhtxxElectronicInvoiceFptxxExtendInfoService.findByFpqqlsh(fpqqlshBlue);

            szhtxxElectronicInvoiceFptxxExtendInfoService.saveOrUpdateByFpqqlsh(
                    SzhtxxElectronicInvoiceFptxxExtendInfo
                            .builder()
                            .fpqqlsh(extendInfoBlue.getFpqqlsh())

                            //·将该发票的作废标志变更为“已作废”；
                            .flagVoidSign(InvoiceApplyBecomeInvalidEnum.已作废.getKey())

                            .becomeInvalidReason(form.getBecomeInvalidReason())
                            //·该发票的作废人和作废时间记录为当前操作人姓名和时间；
                            .becomeInvalidTime(nowDate)
                            .becomeInvalidUserId(loginSysUser.getSysUserId())
                            .becomeInvalidUserName(loginSysUser.getFullName())

                            //·将作废原因内容覆盖填充到该发票的备注中，非发票备注；? 什么鬼,原来是这个
                            .remark2(form.getBecomeInvalidReason())

                            //·该发票的更新人和更新时间记录为当前操作人姓名和时间；
                            .updateUserId(loginSysUser.getSysUserId())
                            .updateUserName(loginSysUser.getFullName())
                            .updateTime(nowDate)

                            .build()
            );


            //·作废原因记录到该开票申请的开票备注中；
            //·该开票申请的更新人和更新时间更新为当前的操作人姓名及时间；
            //·将该发票所关联的开票申请的申请状态变更为“已作废”；
            //·将该发票的回款状态变更为“发票作废”；
            int retOpBecomeInvalid = invoiceApplyCustomerFieldBackAccountStatusService
                    .opBecomeInvalidByStateMachine(
                            fpqqlshBlue,
                            form.getBecomeInvalidReason(),
                            loginSysUser
                    );

            log.info("retOpBecomeInvalid = {}", retOpBecomeInvalid);

            if (retOpBecomeInvalid == 1) {

                // 得出受影响的对账单 ids
                List<Long> affectedAccountingOrderIds = invoiceApplyXGoodsService
                        .getAffectedAccountingOrderIdsByInvoiceApplyId(
                                invoiceApplyEntity.getId()
                        );

                // 清理 invoiceApply X goods 对账单相关信息没有在 invoiceApply, 要用 invoiceApplyId 去查 invoiceOrder
                //·同时解除该开票申请与该发票的开票申请数据的关系；

                // 标志 20220509 start ---- 逻辑修改为
                // 包含流水的三个状态复位
                // 1. InvoiceApplyStatus
                // 2. InvoiceMakeStatus
                // 3. BackAccountStatus
                int retSecond = invoiceApplyXGoodsService
                        .dumpXByInvoiceApplyId(
                                invoiceApplyEntity.getId()
                        );


                // 通过 对账单 ids(得出受影响的对账单 ids)
                // 再去 较验 对账单 发票状态

                //·该对账单的申请状态“未申请/部分申请/全部申请”，重新校验更新；----
                //·该对账单的更新人和更新时间更新为当前的操作人姓名及时间；---- 级联
                invoiceApplyCustomerTriggerEventPublisher.triggerTailUpdateAccountingOrderFieldInvoiceStatus(
                        TailUpdateAccountingScoreCustomerFieldInvoiceStatusEvent
                                .builder()
                                .affectedAccountingOrderIds(affectedAccountingOrderIds)
                                .dim(AccountingOrderTypeDimEnum.积分订单)
                                .invoiceApplyId(invoiceApplyEntity.getId())
                                .loginSysUser(loginSysUser)
                                .build());
            }


            return SysNotify.builder()
                    .title(response.getReturnCode())
                    .content(response.getReturnMsg())
                    .build();
        }
        // 异常情况
        else {
            return SysNotify
                    .builder()
                    .title(response.getReturnCode())
                    .content("发票作废修复失败：" + response.getReturnMsg())
                    .build();
        }
    }

    /**************************************** 金税盘页面-发起-op发票作废状态修复(纸质专用发票)(深圳航信纸质票)   end ****************************************/

    /**************************************** 金税盘页面-op申请红字信息表编号-op确认申请(纸质专用发票)(深圳航信纸质票) start ****************************************/

    public SID20BitchLlqRequestBody opRedBitchLlqRequest(
            SzhtxxInvoiceFptxxOpSingleBillingForm form,
            SzhtxxElectronicInvoiceFptxxListItemVo fptxxListItemVo,
            InvoiceApply entity,
            LoginSysUser loginSysUser) {

        String   nowStr      = DateUtil.now();
        DateTime nowDate     = DateUtil.date();
        String   batchId     = snowflake.nextIdStr();
        String   fpqqlshBlue = form.getFpqqlsh();


        SingleBillingRequestBodyKpContent singleBillingRequestBodyKpContent =
                invoiceApplyCustomerFieldMakeInvoiceStatusOpOngoingSzhtxxElectronicInvoiceService.opOngoingInvoiceTypeEq1InvoiceModeEqSzhtxxElectronicInvoiceRedWrite(
                        form,
                        fptxxListItemVo,
                        entity,
                        loginSysUser
                );


        /**************************************** 转换 start ****************************************/

        RedInvReqBillMxType redInvReqBillMxType = new RedInvReqBillMxType();

        List<SingleBillingRequestBodyKpContentXmxxItemVo> xmxx = singleBillingRequestBodyKpContent.getXmxx();
        // 优化20220926 如果多于8条，是要特殊处理
        if(8 < xmxx.size()){  //商品明细大于8行需要对明细做汇总操作
                cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID20BitchLlq.ID0200.GoodsMxType goodsMxType = new GoodsMxType();
                goodsMxType.setGoodsName("详见正数发票及清单");
                goodsMxType.setGoodsUnit("");
                goodsMxType.setGoodsGgxh("");
                goodsMxType.setHSBZ("N");// 20220919 航信的人说，这个参数固定传N
                goodsMxType.setSYYHZCBZ(xmxx.get(0).getYhzcbs());
                goodsMxType.setGoodsNum("");
                goodsMxType.setGoodsPrice("");
                BigDecimal xmje =   xmxx.stream().map(e->new BigDecimal(e.getXmje())).reduce(BigDecimal.ZERO,BigDecimal::add);
                goodsMxType.setGoodsJE(xmje.toString());
                BigDecimal se  =   xmxx.stream().map(e->new BigDecimal(e.getSe())).reduce(BigDecimal.ZERO,BigDecimal::add);
                goodsMxType.setGoodsSE(se.toString());
                goodsMxType.setSPBM("");
                goodsMxType.setGoodsTaxRate(xmxx.get(0).getSl());
                redInvReqBillMxType.getGoodsMx().add(goodsMxType);

        }else{ //项目明细少于8行传所有明细信息

            xmxx.forEach(item -> {

                cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID20BitchLlq.ID0200.GoodsMxType goodsMxType = new GoodsMxType();

                goodsMxType.setGoodsName(item.getXmmc());
                // 优化20220926 对商品单位、商品规格、商品数量、商品单价传空处理
//            goodsMxType.setGoodsUnit(item.getXmdw());
//            goodsMxType.setGoodsGgxh(item.getGgxh());
                goodsMxType.setGoodsUnit("");
                goodsMxType.setGoodsGgxh("");
                goodsMxType.setHSBZ("N");// 20220919 航信的人说，这个参数固定传N
                goodsMxType.setSYYHZCBZ(item.getYhzcbs());
//            goodsMxType.setfphxz(item.getFphxz());
//            goodsMxType.setlslbs(item.getLslbs());
                // goodsMxType.setzzstsgl: 增值税特殊管理;--深圳航信电子票-产物-深圳航信纸质票-没有
//            goodsMxType.setGoodsNum(AnStringUtils.getString(item.getXmsl()));
//            goodsMxType.setGoodsPrice(AnBigDecimalUtils.getBigDecimalFormat(item.getXmdj()));
                goodsMxType.setGoodsNum("");
                goodsMxType.setGoodsPrice("");
//            goodsMxType.setkce(item.getKce());
                goodsMxType.setGoodsJE(item.getXmje());
                goodsMxType.setGoodsSE(item.getSe());
                goodsMxType.setSPBM(item.getSpbm());
                goodsMxType.setGoodsTaxRate(item.getSl());

                redInvReqBillMxType.getGoodsMx().add(goodsMxType);
            });

        }

        // TODO mark by linjinyu at 2022-05-147 02:24:54 - 如果多于6条，是要特殊处理
//        xmxx.forEach(item -> {
//
//            cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID20BitchLlq.ID0200.GoodsMxType goodsMxType = new GoodsMxType();
//
//            goodsMxType.setGoodsName(item.getXmmc());
//            // 优化20220926 对商品单位、商品规格、商品数量、商品单价传空处理
////            goodsMxType.setGoodsUnit(item.getXmdw());
////            goodsMxType.setGoodsGgxh(item.getGgxh());
//            goodsMxType.setGoodsUnit("");
//            goodsMxType.setGoodsGgxh("");
//            goodsMxType.setHSBZ("N");// 20220919 航信的人说，这个参数固定传N
//            goodsMxType.setSYYHZCBZ(item.getYhzcbs());
////            goodsMxType.setfphxz(item.getFphxz());
////            goodsMxType.setlslbs(item.getLslbs());
//            // goodsMxType.setzzstsgl: 增值税特殊管理;--深圳航信电子票-产物-深圳航信纸质票-没有
////            goodsMxType.setGoodsNum(AnStringUtils.getString(item.getXmsl()));
////            goodsMxType.setGoodsPrice(AnBigDecimalUtils.getBigDecimalFormat(item.getXmdj()));
//            goodsMxType.setGoodsNum("");
//            goodsMxType.setGoodsPrice("");
////            goodsMxType.setkce(item.getKce());
//            goodsMxType.setGoodsJE(item.getXmje());
//            goodsMxType.setGoodsSE(item.getSe());
//            goodsMxType.setSPBM(item.getSpbm());
//            goodsMxType.setGoodsTaxRate(item.getSl());
//
//            redInvReqBillMxType.getGoodsMx().add(goodsMxType);
//        });


        SingleBillingRequestBodyKpContentFptxxVo fptxxE = singleBillingRequestBodyKpContent.getFptxx();

        cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID20BitchLlq.ID0200.RedInvReqBillType redInvReqBillType = new RedInvReqBillType();


        redInvReqBillType.setReqNsrsbh(form.getTaxCode());// 取该申请的申请方税号，根据当前“申请选择”决定当前取值，目前默认取销售方税号；【未来可能由于选择取购买方税号】
        redInvReqBillType.setKpjh(form.getMachineNo());// 取该申请的开票机号
        redInvReqBillType.setSbbh(form.getCheckCode());// 取该申请的金税盘号

        redInvReqBillType.setReqBillNo(StrUtil.format("{}{}", form.getCheckCode(), DateUtil.format(DateUtil.date(), "yyMMddHHmmss")));// 取该申请的流水号：金税盘号（设备编号）+年（后两位）月日时分秒
        redInvReqBillType.setBillType("0");// 固定值： 0 正常； 1 逾期(仅销方开具)； 2 为机动车类专票信息表 （涉及退 货和开具错误等，合格证退回）； 3 为机动车类专票信息表（仅涉及销 售折让，合格证不退回）默认：0 正常

        redInvReqBillType.setSzlb("1");// 税种类别 0 营业税，1 增值税 默认：1 增值税
        redInvReqBillType.setIsMutiRate("0");// 多税率标志 固定值 0：一票一税率； 1：一票多税率 默认：0 一票一税率

        redInvReqBillType.setDate(DateUtil.date().toString("yyyy-MM-dd"));//填开日期 格式：yyyy-MM-dd 取该申请的申请日期
        // 数据库的为 yyyyMMddHHmmss
        redInvReqBillType.setKprq(DateUtil.parse(fptxxListItemVo.getKprq(), "yyyyMMddHHmmss").toString("yyyyMM"));// 蓝票开票日期 格式：yyyyMM 取该申请原发票的开票日期

        redInvReqBillType.setTaxRate(fptxxListItemVo.getTaxRate());// TODO mark by linjinyu at 2022-05-147 02:26:28 - 这个税率要看一下要不要除100

        redInvReqBillType.setReqMemo(form.getReqMemo());// 申请说明 "0000000100"
//（1）销方申请：0000000100
//（2）购方申请（已抵扣）：1100000000
//（3）购方申请（未抵扣）：1010000000
//根据当前申请选择，指定不同说明内容：
//（1）当前申请选择为“销售方申请”时，其内容为：0000000100
//注：目前只有此一种说明内容，未来根据需要在新增；

//                .fpqqlsh(fptxxE.getFpqqlsh())
//                .dkbz(fptxxE.getDkbz())

//                .fjh(fptxxE.getFjh()) // : 分机号--深圳航信电子票-产物-深圳航信纸质票-没有


        redInvReqBillType.setSellerName(fptxxE.getXhfmc());//                .xhfmc(fptxxE.getXhfmc()) // : 销货方名称--深圳航信电子票-产物-深圳航信纸质票-没有
        redInvReqBillType.setSellTaxCode(fptxxE.getXhfNsrsbh());//                .xhfNsrsbh(fptxxE.getXhfNsrsbh())

//                .xhfYhzh(fptxxE.getXhfYhzh())
//                .xhfDzdh(fptxxE.getXhfDzdh())

        redInvReqBillType.setBuyerName(fptxxE.getGhfmc());// 购方名称  取该申请的购买方名称              .ghfmc(fptxxE.getGhfmc())
        redInvReqBillType.setBuyTaxCode(fptxxE.getGhfNsrsbh());// 购方税号 取该申请的购买方税号              .ghfNsrsbh(fptxxE.getGhfNsrsbh())


//                .ghfYhzh(fptxxE.getGhfYhzh())
//                .ghfDzdh(fptxxE.getGhfDzdh())

//                .ghfqylx(fptxxE.getGhfqylx()) // : 购货方企业类型;--深圳航信电子票-产物-深圳航信纸质票-没有

//                .kpy(fptxxE.getKpy())
//                .sky(fptxxE.getSky())
//                .fhr(fptxxE.getFhr())

//                //                .billSentSign(fptxxE.getBillSentSign()) // : 交付标志--深圳航信电子票-产物-深圳航信纸质票-没有 SzhtxxElectronicInvoiceFptxxBillSentSignEnum
//                .billSentSign(AnStringUtils.getString(SzhtxxElectronicInvoiceFptxxBillSentSignEnum.不交付.getKey())) // : 交付标志--深圳航信电子票-产物-深圳航信纸质票-没有 SzhtxxElectronicInvoiceFptxxBillSentSignEnum

//                .qdBz(fptxxE.getQdBz())
//                .qdxmmc(fptxxE.getQdxmmc()) // : 清单项目名称--深圳航信电子票-产物-深圳航信纸质票-没有
//                .kplx(fptxxE.getKplx()) // : 开票类型--深圳航信电子票-产物-深圳航信纸质票-没有

        redInvReqBillType.setTypeCode(fptxxE.getYfpDm());//取该申请的发票代码                .yfpDm(fptxxE.getYfpDm()) // : 原发票代码--深圳航信电子票-产物-深圳航信纸质票-没有
        redInvReqBillType.setInvNo(fptxxE.getYfpHm());//  取该申请的发票号码              .yfpHm(fptxxE.getYfpHm()) // : 原发票号码--深圳航信电子票-产物-深圳航信纸质票-没有

//.kphjje(fptxxE.getKphjje()) // : 价税合计--深圳航信电子票-产物-深圳航信纸质票-没有
        redInvReqBillType.setAmount(fptxxE.getHjbhsje());//   合计金额（不含税） 合计金额（请保留两个小数，小数 0 不可舍掉） //                .hjbhsje(fptxxE.getHjbhsje()) // : 合计不含税金额--深圳航信电子票-产物-深圳航信纸质票-没有

        redInvReqBillType.setTax(fptxxE.getHjse());//                .hjse(fptxxE.getHjse()) // : 合计税额--深圳航信电子票-产物-深圳航信纸质票-没有

//                //                .bz(fptxxE.getBz())
//                .bz(StrUtil.format("开具红字增值税专用发票信息表编号{}", fpqqlshBlue))

//                //                .invoiceType(fptxxE.getInvoiceType())
//                .invoiceType(SzhtxxElectronicInvoiceFptxxInvoiceTypeEnum.专票.getKey())

        redInvReqBillType.setRedInvReqBillMx(redInvReqBillMxType);//                .invoiceItems(invoiceItems)


//        InputType inputType = new I
//        FpxtType fpxtType

        /**************************************** 转换   end ****************************************/

        /**************************************** 套娃 start ****************************************/

        SID20BitchLlqRequestID0200FpxtTypeFactory sid20BitchLlqRequestID0200FpxtTypeFactory = new SID20BitchLlqRequestID0200FpxtTypeFactory();

        cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID20BitchLlq.ID0200.FpxtType fpxtTypeID0200 =
                sid20BitchLlqRequestID0200FpxtTypeFactory.createFpxtType();

        fpxtTypeID0200.setINPUT(sid20BitchLlqRequestID0200FpxtTypeFactory.createInputType());

        fpxtTypeID0200.getINPUT().setRedInvReqBill(redInvReqBillType);


        SID20BitchLlqRequestBody sid20BitchLlqRequestBody = SID20BitchLlqRequestBody
                .builder()

                .SID("20")
//                .SIDParam() ---- dataID0200().shell().packing() 装填
                .batchId(batchId)
                .fpqqlsh(fpqqlshBlue)

//                .structVo()
//                .fpxtComInputStruct()
                .fpxtTypeID0200(fpxtTypeID0200)
                .build();

        /**************************************** 套娃 start ****************************************/

        szhtxxPaperInvoiceFptxxSID20BitchLlqService.recordSID20BitchLlqID0200Request(
                form,
                fptxxListItemVo,
                entity,
                sid20BitchLlqRequestBody,
                nowDate,
                loginSysUser
        );

        return sid20BitchLlqRequestBody;

    }

    public SysNotify opRedBitchLlqResponse(
            SzhtxxInvoiceFptxxOpSingleBillingForm form,
            SzhtxxElectronicInvoiceFptxxListItemVo fptxxListItemVo,
            InvoiceApply entity,
            LoginSysUser loginSysUser) {

        String   nowStr      = DateUtil.now();
        DateTime nowDate     = DateUtil.date();
        String   batchId     = form.getBatchId();
        String   fpqqlshBlue = form.getFpqqlsh();

        SID20BitchLlqResponseBody sid20BitchLlqResponseBody = SID20BitchLlqResponseBody
                .builder()
                .batchId(form.getBatchId())
//                      .fpqqlsh(form.getFpqqlsh()) // 这里是错的 fpqqlsh是发票红冲时用  invoiceApplySn是发起开票时用
                .fpqqlsh(form.getInvoiceApplySn())
                .ENCMSG(form.getENCMSG())
                .build();

        sid20BitchLlqResponseBody
                .unPacking()
                .unShell()
                .unDataID0200();

        log.info("\n表单\n{}\n密文\n{}\n解密\n{}\n总体\n{}",
                JSONUtil.toJsonPrettyStr(form),
                sid20BitchLlqResponseBody.getENCMSG(),
                //JSONUtil.toJsonStr(sid20BitchLlqResponseBody.getEncmsgVo()),
                JSONUtil.toJsonStr(sid20BitchLlqResponseBody.getFpxtComOutputStruct().getDATA()),
                JSONUtil.toJsonPrettyStr(sid20BitchLlqResponseBody)
        );

        SID20BitchLlqResponseBodyEncmsgVo response = sid20BitchLlqResponseBody.getEncmsgVo();

        szhtxxPaperInvoiceFptxxSID20BitchLlqService.recordSID20BitchLlqID0200Response(
                form,
                fptxxListItemVo,
                entity,
                sid20BitchLlqResponseBody,
                nowDate,
                loginSysUser
        );

        /**************************************** 这里的解包只为返回，实际入库在 recordSID20BitchLlqID0200Response start ****************************************/

        // 第一层
        if (ObjectUtil.isNotNull(response) && "0".equals(response.getReturnCode())) {

            // TODO ...


            // 第二层
            FpxtComOutputStruct fpxtComOutputStruct = sid20BitchLlqResponseBody.getFpxtComOutputStruct();

            if (ObjectUtil.isNotNull(fpxtComOutputStruct) && "0000".equals(fpxtComOutputStruct.getCODE())) {

                cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID20BitchLlq.ID0200.FpxtType fpxtTypeID0200 = sid20BitchLlqResponseBody.getFpxtTypeID0200();


                if (ObjectUtil.isNotNull(fpxtTypeID0200) && "0000".equals(fpxtTypeID0200.getOUTPUT().getCODE())) {

                    List<cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID20BitchLlq.ID0200.RedInvReqBillType> redInvReqBill =
                            fpxtTypeID0200.getOUTPUT().getDATA().getRedInvReqBill();

                    redInvReqBill.forEach(item -> {
                        if("0000".equals(item.getStatusDM())){
                            response.setReturnMsg(item.getStatusMC());
                        }else{
                            response.setReturnMsg(item.getStatusMC());
                        }

                    });

                } else {
//                    操作结果 0000：上传成功，其它上传失败
                }


            } else {
                // 表示 CODE 不为 0000 DATA 为空
            }

            SzhtxxElectronicInvoiceFptxxExtendInfo extendInfoBlue = szhtxxElectronicInvoiceFptxxExtendInfoService.findByFpqqlsh(fpqqlshBlue);


            return SysNotify.builder()
                    .title(response.getReturnCode())
                    .content(response.getReturnMsg())
                    .build();
        } else {
            return SysNotify.builder()
                    .title(response.getReturnCode())
                    .content(response.getReturnMsg())
                    .build();
        }

        /**************************************** 这里的解包只为返回，实际入库在 recordSID20BitchLlqID0200Response   end ****************************************/


    }

    /**************************************** 金税盘页面-op申请红字信息表编号-op确认申请(纸质专用发票)(深圳航信纸质票)   end ****************************************/

    /**************************************** 金税盘页面-op下载红字信息表编号-op确认下载(纸质专用发票)(深圳航信纸质票) start ****************************************/

    public SID20BitchLlqRequestBody opRedLowerWorkLlqRequest(
            SzhtxxInvoiceFptxxOpRedLowerWorkLlqForm form,
            LoginSysUser loginSysUser) {

        String   nowStr  = DateUtil.now();
        DateTime nowDate = DateUtil.date();
        String   batchId = snowflake.nextIdStr();


//        @ApiModelProperty("op下载红字信息表-op确认下载-信息表编号")
//        private String redTaxInfoSn;
//        @ApiModelProperty("op下载红字信息表-op确认下载-购买方税号")
//        private String ghfNsrsbh;
//        @ApiModelProperty("op下载红字信息表-op确认下载-销售方税号")
//        private String xhfNsrsbh;


        SID20BitchLlqRequestID0201FpxtTypeFactory sid20BitchLlqRequestID0201FpxtTypeFactory = new SID20BitchLlqRequestID0201FpxtTypeFactory();

        cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.request.SID20BitchLlq.ID0201.FpxtType fpxtTypeID0201 =
                sid20BitchLlqRequestID0201FpxtTypeFactory.createFpxtType();


        fpxtTypeID0201.setINPUT(sid20BitchLlqRequestID0201FpxtTypeFactory.createInputType());

        fpxtTypeID0201.getINPUT().setXXBBH(form.getRedTaxInfoSn());
        fpxtTypeID0201.getINPUT().setGFSH(form.getGhfNsrsbh());
        fpxtTypeID0201.getINPUT().setXFSH(form.getXhfNsrsbh());
/*
<?xml version="1.0" encoding="GBK"?>
<FPXT>
    <INPUT>
        <NSRSBH></NSRSBH><!--企业税号-->
        <SBBH></SBBH><!--设备编号-->
        <KPJH></KPJH><!--开票机号-->
        <YQZT></YQZT><!--逾期状态 N:非逾期，Y:逾期-->
        <TKRQ_Q></TKRQ_Q><!--填开日期起，可空-->
        <TKRQ_Z></TKRQ_Z><!--填开日期止，可空-->
        <GFSH></GFSH><!--购方税号，可空-->
        <XFSH></XFSH><!--销方税号，可空-->
        <XXBBH></XXBBH><!--信息表编号，可空-->
        <XXBFW></XXBFW><!--信息表下载范围。0：全部，1：本企业申请，2：其它企业申请-->
        <PAGENO></PAGENO><!--页号，从 1 开始-->
        <PAGESIZE></PAGESIZE><!--每页记录数-->
    </INPUT>
</FPXT>
 */


        SID20BitchLlqRequestBody sid20BitchLlqRequestBody = SID20BitchLlqRequestBody
                .builder()

                .SID("20")
//                .SIDParam() ---- dataID0201().shell().packing() 装填
                .batchId(batchId)

//                .structVo()
//                .fpxtComInputStruct()
                .fpxtTypeID0201(fpxtTypeID0201)
                .build();

        szhtxxPaperInvoiceFptxxSID20BitchLlqService.recordSID20LowerWorkLlqRequestID0201Request(form, sid20BitchLlqRequestBody, nowDate, loginSysUser);


        return sid20BitchLlqRequestBody;
    }

    public SysNotify opRedLowerWorkLlqResponse(
            SzhtxxInvoiceFptxxOpRedLowerWorkLlqForm form,
            LoginSysUser loginSysUser) {

        String   nowStr  = DateUtil.now();
        DateTime nowDate = DateUtil.date();
        String   batchId = form.getBatchId();


        SID20BitchLlqResponseBody sid20BitchLlqResponseBody = SID20BitchLlqResponseBody
                .builder()

                .batchId(form.getBatchId())

                .ENCMSG(form.getENCMSG())

                .batchId(batchId)
                .build();

        sid20BitchLlqResponseBody
                .unPacking()
                .unShell()
                .unDataID0201();

        log.info("\n表单\n{}\n密文\n{}\n解密\n{}\n总体\n{}",
                JSONUtil.toJsonPrettyStr(form),
                sid20BitchLlqResponseBody.getENCMSG(),
                JSONUtil.toJsonStr(sid20BitchLlqResponseBody.getEncmsgVo()),
                JSONUtil.toJsonPrettyStr(sid20BitchLlqResponseBody)
        );

        SID20BitchLlqResponseBodyEncmsgVo response = sid20BitchLlqResponseBody.getEncmsgVo();

        szhtxxPaperInvoiceFptxxSID20BitchLlqService.recordSID20LowerWorkLlqRequestID0201Response(form, sid20BitchLlqResponseBody, nowDate, loginSysUser);

        /**************************************** 这里的解包只为返回，实际入库在 recordSID20LowerWorkLlqRequestID0201Response start ****************************************/

        // 第一层
        if (ObjectUtil.isNotNull(response) && "0".equals(response.getReturnCode())) {

            // TODO ...


            // 第二层
            FpxtComOutputStruct fpxtComOutputStruct = sid20BitchLlqResponseBody.getFpxtComOutputStruct();

            if (ObjectUtil.isNotNull(fpxtComOutputStruct) && "0000".equals(fpxtComOutputStruct.getCODE())) {

                cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID20BitchLlq.ID0201.FpxtType fpxtTypeID0201 = sid20BitchLlqResponseBody.getFpxtTypeID0201();


                if (ObjectUtil.isNotNull(fpxtTypeID0201) && "0000".equals(fpxtTypeID0201.getOUTPUT().getCODE())) {

                    List<cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.paperInvoice.dto.response.SID20BitchLlq.ID0201.RedInvReqBillType> redInvReqBill =
                            fpxtTypeID0201.getOUTPUT().getDATA().getRedInvReqBill();

                    redInvReqBill.forEach(redInvReqBillType -> {

                    });


                    return SysNotify.builder()
                            .title(response.getReturnCode())
                            .content(response.getReturnMsg())
                            .build();

                } else {
//                    操作结果 0000：上传成功，其它上传失败
                }


            } else {
                // 表示 CODE 不为 0000 DATA 为空
            }


            return SysNotify.builder()
                    .title(response.getReturnCode())
                    .content(response.getReturnMsg())
                    .build();
        } else {
            return SysNotify.builder()
                    .title(response.getReturnCode())
                    .content(response.getReturnMsg())
                    .build();
        }

        /**************************************** 这里的解包只为返回，实际入库在 recordSID20LowerWorkLlqRequestID0201Response   end ****************************************/


    }

    /**************************************** 金税盘页面-op下载红字信息表编号-op确认下载(纸质专用发票)(深圳航信纸质票)   end ****************************************/


    /**************************************** 10. 获取金税盘状态接口 SID=121 start ****************************************/

    public SID121TaxInfoRequestBody opCallTaxInfoApiRequest(SzhtxxPaperInvoiceOpTaxInfoForm form, LoginSysUser loginSysUser) {

        String batchId = snowflake.nextIdStr();

        return SID121TaxInfoRequestBody
                .builder()
                .SID("121")
//                .SIDParam() ---- packing() 装填
                .batchId(batchId)
                .build();

    }

    public SysNotify opCallTaxInfoApiResponse(SzhtxxPaperInvoiceOpTaxInfoForm form, LoginSysUser loginSysUser) {


        SID121TaxInfoResponseBody sid121TaxInfoResponseBody = SID121TaxInfoResponseBody
                .builder()
                .batchId(form.getBatchId())
                .ENCMSG(form.getENCMSG())
                .build();

        sid121TaxInfoResponseBody.unPacking();

        log.info("\n表单\n{}\n密文\n{}\n解密\n{}\n总体\n{}",
                JSONUtil.toJsonPrettyStr(form),
                sid121TaxInfoResponseBody.getENCMSG(),
                JSONUtil.toJsonStr(sid121TaxInfoResponseBody.getEncmsgVo()),
                JSONUtil.toJsonPrettyStr(sid121TaxInfoResponseBody)
        );

        SID121TaxInfoResponseBodyEncmsgVo response = sid121TaxInfoResponseBody.getEncmsgVo();

        if (ObjectUtil.isNotNull(response) && "0".equals(response.getReturnCode())) {


            return SysNotify.builder()
                    .title(response.getReturnCode())
                    .content(response.getReturnMsg())
                    .build();
        } else {
            return SysNotify.builder()
                    .title(response.getReturnCode())
                    .content(response.getReturnMsg())
                    .build();
        }

    }

    /**************************************** 10. 获取金税盘状态接口 SID=121   end ****************************************/

    /**************************************** 17. 金税设备查询 SID=25 start ****************************************/

    public SID25TaxDeviceInfoRequestBody opCallTaxDeviceInfoApiRequest(SzhtxxPaperInvoiceOpTaxDeviceInfoForm form, LoginSysUser loginSysUser) {

        String batchId = snowflake.nextIdStr();

        return SID25TaxDeviceInfoRequestBody
                .builder()
                .SID("25")
//                .SIDParam() ---- packing() 装填
                .batchId(batchId)
                .build();

    }

    public SID25TaxDeviceInfoResponseBody opCallTaxDeviceInfoApiResponse(SzhtxxPaperInvoiceOpTaxDeviceInfoForm form, LoginSysUser loginSysUser) {

        SID25TaxDeviceInfoResponseBody sid25TaxDeviceInfoResponseBody = SID25TaxDeviceInfoResponseBody
                .builder()
                .batchId(form.getBatchId())
                .ENCMSG(form.getENCMSG())
                .build();

        sid25TaxDeviceInfoResponseBody.unPacking();

        log.info("\n表单\n{}\n密文\n{}\n解密\n{}\n总体\n{}",
                JSONUtil.toJsonPrettyStr(form),
                sid25TaxDeviceInfoResponseBody.getENCMSG(),
                JSONUtil.toJsonStr(sid25TaxDeviceInfoResponseBody.getEncmsgVo()),
                JSONUtil.toJsonPrettyStr(sid25TaxDeviceInfoResponseBody)
        );

        SID25TaxDeviceInfoResponseBodyEncmsgVo response = sid25TaxDeviceInfoResponseBody.getEncmsgVo();

        if (ObjectUtil.isNotNull(response) && "0".equals(response.getReturnCode())) {


//            return SysNotify.builder()
//                    .title(response.getReturnCode())
//                    .content(response.getReturnMsg())
//                    .build();
        } else {
//            return SysNotify.builder()
//                    .title(response.getReturnCode())
//                    .content(response.getReturnMsg())
//                    .build();
        }

        return sid25TaxDeviceInfoResponseBody;

    }

    /**************************************** 17. 金税设备查询 SID=25   end ****************************************/


}
