package cokr.xit.ens.biz.iup.signtalk.service;

import cokr.xit.ens.biz.iup.billpay.api.IupKkoPayUseSysApiSpec;
import cokr.xit.ens.biz.iup.billpay.service.IupBillKkoPayUseSysService;
import cokr.xit.ens.biz.iup.domain.*;
import cokr.xit.ens.biz.iup.domain.repository.*;
import cokr.xit.ens.core.exception.EnsException;
import cokr.xit.ens.core.exception.code.EnsErrCd;
import cokr.xit.ens.core.utils.CmmnUtil;
import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.code.BillKkoErrCd;
import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoApiRespDTO;
import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.model.BillKkoPayResultData;
import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillReqSeCd;
import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.entity.BillHist;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository;
import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.OrgMng;
import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.TmpltMng;
import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.OrgMngRepository;
import cokr.xit.ens.modules.common.ctgy.sys.mng.domain.repository.TmpltMngRepository;
import com.google.gson.Gson;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Optional;

@Slf4j
@Service("iupBillKkoPayUseSysService_KP")
@RequiredArgsConstructor
public class IupBillKkoPaySigntalkService extends IupBillKkoPayUseSysService {


    private final IntgrnSendDetailRepository intgrnSendDetailRepository;
    private final TmpltMngRepository sendTmpltMngRepository;
    private final OrgMngRepository orgMngRepository;
    private final TbInputDataXitRepository tbInputDataXitRepository;
    private final VKakaoNoticeInfoRepository vKakaoNoticeInfoRepository;
    private final VKakaoNoticeInfoSnRepository vKakaoNoticeInfoSnRepository;
    //    private final TbEnfrcLevRcivRepository tbEnfrcLevRcivRepository;
    private final TbEnfrcLevMastrRepository tbEnfrcLevMastrRepository;
    private final TbKakaoPayResultRepository tbKakaoPayResultRepository;
    private final IupKkoPayUseSysApiSpec iupKkoPayApi;
    private final JPAQueryFactory query;


    /**
     * 청구서 조회
     *
     * @param mParam
     * @return
     */
    @Transactional(propagation = Propagation.NEVER)
    public BillKkoApiRespDTO findNoticeInfo(Map<String, Object> mParam) {
        Map<String, Object> data = (Map<String, Object>) mParam.get("data");
//        data.get("biller_user_key");
//        data.get("billed_year_month");
//        data.get("ordinal");
//        data.get("biller_notice_key");
        Map<String, Object> parameters = (Map<String, Object>) data.get("parameters");
//        data.get("user_birth");


        Map<String, Object> respData = null;
        BillKkoApiRespDTO respVO = null;
        BillKkoErrCd kkoBillErrCd = BillKkoErrCd.OK;
        final String billerUserKey = Optional.ofNullable(data.get("biller_user_key")).isPresent() ?
                String.valueOf(data.get("biller_user_key")) : null;
        final String userBirth = Optional.ofNullable(data.get("user_birth")).isPresent() ?
                String.valueOf(data.get("user_birth")) : null;
        final String orgCd = Optional.ofNullable(parameters.get("orgCd")).isPresent() ?
                String.valueOf(parameters.get("orgCd")) : null;
        final String billUid = Optional.ofNullable(parameters.get("billUid")).isPresent() ?
                String.valueOf(parameters.get("billUid")) : null;

        BillHist billHist = null;
        try {
            billHist = this.addBillHistByReqInfo(BillReqSeCd.NOTICE, billerUserKey, orgCd, billUid, mParam);


            if (CmmnUtil.isEmpty(billerUserKey)) {
                kkoBillErrCd = BillKkoErrCd.E801;
                throw new EnsException(EnsErrCd.ERR401, "사용자식별키가 없습니다.");
            }
            if (CmmnUtil.isEmpty(orgCd)) {
                kkoBillErrCd = BillKkoErrCd.E801;
                throw new EnsException(EnsErrCd.ERR401, "기관코드가 없습니다.");
            }
            if (CmmnUtil.isEmpty(userBirth)) {
                kkoBillErrCd = BillKkoErrCd.E801;
                throw new EnsException(EnsErrCd.ERR401, "생년월일이 없습니다.");
            }


            Optional<IntgrnSendDetail> intgrnSendDetail = intgrnSendDetailRepository.findByLinkedUuid(billerUserKey);
            if (!intgrnSendDetail.isPresent()) {
                kkoBillErrCd = BillKkoErrCd.E402;
                throw new EnsException(EnsErrCd.ERR404, "일치하는 발송상세 자료가 없습니다.");
            }
            if (!orgCd.equals(intgrnSendDetail.get().getIntgrnSendMast().getOrgCd())) {
                kkoBillErrCd = BillKkoErrCd.E402;
                throw new EnsException(EnsErrCd.ERR402, String.format("기관코드가 상이 합니다. ( 요청: %s 실제: %s )", orgCd, intgrnSendDetail.get().getIntgrnSendMast().getOrgCd()));
            }
            Optional<OrgMng> orgMng = orgMngRepository.findById(orgCd);
            if (!orgMng.isPresent()) {
                kkoBillErrCd = BillKkoErrCd.E801;
                throw new EnsException(EnsErrCd.ERR404, "일치하는 기관정보가 없습니다.");
            }
            Optional<TmpltMng> sendTmpltMng = sendTmpltMngRepository.findFetchByOrgCdAndTmpltCdAndUseYn(orgCd, intgrnSendDetail.get().getIntgrnSendMast().getTmpltCd(), "Y");
            if (!sendTmpltMng.isPresent()) {
                kkoBillErrCd = BillKkoErrCd.E801;
                throw new EnsException(EnsErrCd.ERR404, "일치하는 템플릿정보가 없습니다.");
            }
            Optional<TbInputDataXit> tbInputDataXit = tbInputDataXitRepository.findByLinkedUuid(billerUserKey);
            if (!tbInputDataXit.isPresent()) {
                kkoBillErrCd = BillKkoErrCd.E402;
                throw new EnsException(EnsErrCd.ERR404, "일치하는 발송상세정보가 없습니다.");
            }
//            final String dataId = tbInputDataXit.get().getDataId();
            final String dataId = billerUserKey;

            if ("Y".equals(orgMng.get().getKkoBpCsignYn())) {
                Optional<VKakaoNoticeInfoSn> vKakaoNoticeInfoSn = vKakaoNoticeInfoSnRepository.findById(dataId);
                if (!vKakaoNoticeInfoSn.isPresent()) {
                    kkoBillErrCd = BillKkoErrCd.E402;
                    throw new EnsException(EnsErrCd.ERR404, "일치하는 단순미납부과 자료가 없습니다.");
                }
                if (!userBirth.equals(vKakaoNoticeInfoSn.get().getUserBirth())) {
                    kkoBillErrCd = BillKkoErrCd.E402;
                    throw new EnsException(EnsErrCd.ERR402, String.format("생년월일이 일치하지 않습니다. (요청: %s 실제: %s)", userBirth, vKakaoNoticeInfoSn.get().getUserBirth()));
                }


                respData = this.respNoticeSnData(sendTmpltMng.get().getTitle(), orgMng.get(), vKakaoNoticeInfoSn.get());

            } else if ("N".equals(orgMng.get().getKkoBpCsignYn())) {
                if (dataId.length() < 20) {
                    kkoBillErrCd = BillKkoErrCd.E402;
                    throw new EnsException(EnsErrCd.ERR403, "빌러코드가 20자리 미만 입니다.");
                }
                Optional<VKakaoNoticeInfo> vKakaoNoticeInfo = vKakaoNoticeInfoRepository.findById(dataId.substring(0, 20));
                if (!vKakaoNoticeInfo.isPresent()) {
                    kkoBillErrCd = BillKkoErrCd.E402;
                    throw new EnsException(EnsErrCd.ERR404, "일치하는 강제징수부과 자료가 없습니다.");
                }
                if (!userBirth.equals(vKakaoNoticeInfo.get().getUserBirth())) {
                    kkoBillErrCd = BillKkoErrCd.E404;
                    throw new EnsException(EnsErrCd.ERR402, String.format("생년월일이 일치하지 않습니다. (요청: %s 실제: %s)", userBirth, vKakaoNoticeInfo.get().getUserBirth()));
                }


                respData = this.respNoticeData(sendTmpltMng.get().getTitle(), orgMng.get(), vKakaoNoticeInfo.get());

            } else {
                kkoBillErrCd = BillKkoErrCd.E402;
                throw new EnsException(EnsErrCd.ERR999, "위탁업체여부 구분값이 등록되지 않았습니다.");
            }

            respVO = BillKkoApiRespDTO.okBuilder()
                    .data(respData)
                    .build();


            this.modifyBillHistByRespInfo(billHist, respVO, null, null);

        } catch (EnsException e) {
            respVO = BillKkoApiRespDTO.errBuilder()
                    .resCode(kkoBillErrCd.getCode())
                    .message(kkoBillErrCd.getCodeNm())
                    .build();

            this.modifyBillHistByRespInfo(billHist, respVO, e.getErrCd(), e.getMessage());

        } catch (Exception e) {
            respVO = BillKkoApiRespDTO.errBuilder()
                    .resCode(BillKkoErrCd.E801.getCode())
                    .message(BillKkoErrCd.E801.getCodeNm())
                    .build();

            this.modifyBillHistByRespInfo(billHist, respVO, EnsErrCd.ERR999, e.getMessage());
        }

        return respVO;
    }


    /**
     * 납부 가능 조회
     *
     * @param mParam
     * @return
     */
    @Transactional(propagation = Propagation.NEVER)
    public BillKkoApiRespDTO findPrepayInfo(Map<String, Object> mParam) {
        Map<String, Object> data = (Map<String, Object>) mParam.get("data");
//        data.get("biller_user_key");
//        data.get("billed_year_month");
//        data.get("ordinal");
//        data.get("biller_notice_key");
        Map<String, Object> parameters = (Map<String, Object>) data.get("parameters");
//        data.get("amount");


        BillKkoApiRespDTO respVO = null;
        BillKkoErrCd kkoBillErrCd = BillKkoErrCd.OK;
        final String billerUserKey = Optional.ofNullable(data.get("biller_user_key")).isPresent() ?
                String.valueOf(data.get("biller_user_key")) : null;
        final int amount = Optional.ofNullable(data.get("amount")).isPresent() ?
                (int) data.get("amount") : 0;
        final String orgCd = Optional.ofNullable(parameters.get("orgCd")).isPresent() ?
                String.valueOf(parameters.get("orgCd")) : null;
        final String billUid = Optional.ofNullable(parameters.get("billUid")).isPresent() ?
                String.valueOf(parameters.get("billUid")) : null;

        BillHist billHist = null;
        try {
            billHist = this.addBillHistByReqInfo(BillReqSeCd.PREPAY, billerUserKey, orgCd, billUid, mParam);


            if (CmmnUtil.isEmpty(billerUserKey)) {
                kkoBillErrCd = BillKkoErrCd.E601;
                throw new EnsException(EnsErrCd.ERR401, "사용자식별키가 없습니다.");
            }
            if (CmmnUtil.isEmpty(orgCd)) {
                kkoBillErrCd = BillKkoErrCd.E601;
                throw new EnsException(EnsErrCd.ERR401, "기관코드가 없습니다.");
            }



//            Optional<OrgMng> orgMng = orgMngRepository.findById(orgCd);
//            if (!orgMng.isPresent()) {
//                kkoBillErrCd = BillKkoErrCd.E601;
//                throw new EnsException(EnsErrCd.ERR404, "일치하는 기관정보가 없습니다.");
//            }
//            Optional<TbInputDataXit> tbInputDataXit = tbInputDataXitRepository.findByLinkedUuid(billerUserKey);
            Optional<TbInputDataXit> tbInputDataXit = this.getTbInputDataXitByLinkedUuid(billerUserKey);
            if (!tbInputDataXit.isPresent()) {
                kkoBillErrCd = BillKkoErrCd.E402;
                throw new EnsException(EnsErrCd.ERR404, "일치하는 발송상세정보가 없습니다.");
            }
            final FsJob fsJob = tbInputDataXit.get().getTbInputXit().getFsJob();
            final String dataId = tbInputDataXit.get().getDataId();

            Optional<VKakaoNoticeInfo> vKakaoNoticeInfo = Optional.ofNullable(null);
//            List<TbEnfrcLevRciv> tbEnfrcLevRcivs = new ArrayList<>();


            if ("Y".equals(fsJob.getBpEntrustYn())) {
                Optional<VKakaoNoticeInfoSn> vKakaoNoticeInfoSn = vKakaoNoticeInfoSnRepository.findById(dataId);
                if (!vKakaoNoticeInfoSn.isPresent()) {
                    kkoBillErrCd = BillKkoErrCd.E502;
                    throw new EnsException(EnsErrCd.ERR404, "일치하는 단순미납 자료가 없습니다.");
                }

                respVO = iupKkoPayApi.callApiByOrg(fsJob.getBpKkoPrepayApi(), mParam);

                if ("OK".equals(respVO.getRes_code()))
                    this.modifyBillHistByRespInfo(billHist, respVO, null, null);
                else
                    this.modifyBillHistByRespInfo(billHist, respVO, EnsErrCd.ERR999, String.format("[%s] %s", respVO.getRes_code(), respVO.getMessage()));

                return respVO;

            } else if ("N".equals(fsJob.getBpEntrustYn())) {
                if (dataId.length() < 20) {
                    kkoBillErrCd = BillKkoErrCd.E502;
                    throw new EnsException(EnsErrCd.ERR403, "빌러코드가 20자리 미만 입니다.");
                }

                vKakaoNoticeInfo = vKakaoNoticeInfoRepository.findById(dataId.substring(0, 20));
                if (!vKakaoNoticeInfo.isPresent()) {
                    kkoBillErrCd = BillKkoErrCd.E502;
                    throw new EnsException(EnsErrCd.ERR404, "일치하는 강제징수 자료가 없습니다.");
                }


//                tbEnfrcLevRcivs = tbEnfrcLevRcivRepository.findAllByEnfrcLevMastrIdAndDeleteAt(dataId.substring(0, 20), "N");
                Optional<TbEnfrcLevMastr> tbEnfrcLevMastr = tbEnfrcLevMastrRepository.findByEnfrcLevMastrIdAndEnfrcLevMastrProcessSttusAndDeleteAt(dataId.substring(0, 20), "04", "N");
                if (!tbEnfrcLevMastr.isPresent()) {
                    kkoBillErrCd = BillKkoErrCd.E601;
                    throw new EnsException(EnsErrCd.ERR507, "납부가능 상태가 아닙니다.");
                }

            } else {
                kkoBillErrCd = BillKkoErrCd.E601;
                throw new EnsException(EnsErrCd.ERR999, "위탁업체여부 구분값이 등록되지 않았습니다.");
            }


            if (CmmnUtil.isEmpty(vKakaoNoticeInfo.get().getAmount())
                    || amount != Integer.parseInt(vKakaoNoticeInfo.get().getAmount())) {
                kkoBillErrCd = BillKkoErrCd.E403;
                throw new EnsException(EnsErrCd.ERR902
                        , String.format("납부 가능 금액이 없거나 일치하지 않습니다. (요청금액:%s, 실제금액:%s)"
                        , amount
                        , vKakaoNoticeInfo.get().getAmount()));
            }
            if (amount > Integer.parseInt(vKakaoNoticeInfo.get().getAmount())) {
                kkoBillErrCd = BillKkoErrCd.E501;
                throw new EnsException(EnsErrCd.ERR902
                        , String.format("납부 가능 금액을 초과했습니다. (요청금액:%s, 실제금액:%s)"
                        , amount
                        , vKakaoNoticeInfo.get().getAmount()));
            }
            if (!vKakaoNoticeInfo.isPresent()) {
                kkoBillErrCd = BillKkoErrCd.E502;
                throw new EnsException(EnsErrCd.ERR404, "일치하는 청구서자료가 없습니다.");
            }
            if (CmmnUtil.isEmpty(vKakaoNoticeInfo.get().getPayExpireDate())) {
                kkoBillErrCd = BillKkoErrCd.E601;
                throw new EnsException(EnsErrCd.ERR401, "납부기한이 값이 없습니다.");
            }
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
            if (Integer.parseInt(vKakaoNoticeInfo.get().getPayExpireDate()) < Integer.parseInt(simpleDateFormat.format(new Date()))) {
                kkoBillErrCd = BillKkoErrCd.E506;
                throw new EnsException(EnsErrCd.ERR902, "납부기한이 경과한 자료 입니다.");
            }
//            if (tbEnfrcLevRcivs.size() > 0) {
//                kkoBillErrCd = BillKkoErrCd.E601;
//                throw new EnsException(EnsErrCd.ERR903, "납부가 완료된 자료 입니다.");
//            }



            respVO = BillKkoApiRespDTO.okBuilder()
                    .data(null)
                    .build();

            this.modifyBillHistByRespInfo(billHist, respVO, null, null);

        } catch (EnsException e) {
            respVO = BillKkoApiRespDTO.errBuilder()
                    .resCode(kkoBillErrCd.getCode())
                    .message(kkoBillErrCd.getCodeNm())
                    .build();

            this.modifyBillHistByRespInfo(billHist, respVO, e.getErrCd(), e.getMessage());

        } catch (Exception e) {
            respVO = BillKkoApiRespDTO.errBuilder()
                    .resCode(BillKkoErrCd.E601.getCode())
                    .message(BillKkoErrCd.E601.getCodeNm())
                    .build();

            this.modifyBillHistByRespInfo(billHist, respVO, EnsErrCd.ERR999, e.getMessage());
        }

        return respVO;
    }

    /**
     * 납부결과 저장
     *
     * @param mParam
     * @return
     */
    @Transactional(propagation = Propagation.NEVER)
    public BillKkoApiRespDTO addPayReultIfno(Map<String, Object> mParam) {
        Map<String, Object> data = (Map<String, Object>) mParam.get("data");

        Gson gson = new Gson();
        BillKkoPayResultData kkoBillPayResultVO = gson.fromJson(gson.toJson(data), BillKkoPayResultData.class);

        Map<String, Object> parameters = kkoBillPayResultVO.getParameters();


        BillKkoApiRespDTO respVO = null;
        BillKkoErrCd kkoBillErrCd = BillKkoErrCd.OK;
        final String orgCd = Optional.ofNullable(parameters.get("orgCd")).isPresent() ?
                String.valueOf(parameters.get("orgCd")) : null;
        final String billUid = Optional.ofNullable(parameters.get("billUid")).isPresent() ?
                String.valueOf(parameters.get("billUid")) : null;

        BillHist kkoBillHist = null;
        try {
            kkoBillHist = this.addBillHistByReqInfo(BillReqSeCd.PAYRSLT, kkoBillPayResultVO.getBiller_user_key(), orgCd, billUid, mParam);


            if (CmmnUtil.isEmpty(kkoBillPayResultVO.getBiller_user_key())) {
                kkoBillErrCd = BillKkoErrCd.E601;
                throw new EnsException(EnsErrCd.ERR401, "사용자식별키가 없습니다.");
            }
            if (CmmnUtil.isEmpty(orgCd)) {
                kkoBillErrCd = BillKkoErrCd.E601;
                throw new EnsException(EnsErrCd.ERR401, "기관코드가 없습니다.");
            }



//            Optional<OrgMng> orgMng = orgMngRepository.findById(orgCd);
//            if (!orgMng.isPresent()) {
//                kkoBillErrCd = BillKkoErrCd.E601;
//                throw new EnsException(EnsErrCd.ERR404, "일치하는 기관정보가 없습니다.");
//            }
            Optional<TbInputDataXit> tbInputDataXit = this.getTbInputDataXitByLinkedUuid(kkoBillPayResultVO.getBiller_user_key());
            if (!tbInputDataXit.isPresent()) {
                kkoBillErrCd = BillKkoErrCd.E402;
                throw new EnsException(EnsErrCd.ERR404, "일치하는 발송상세정보가 없습니다.");
            }
            final FsJob fsJob = tbInputDataXit.get().getTbInputXit().getFsJob();

            if (!tbKakaoPayResultRepository.findById(kkoBillPayResultVO.getBiller_user_key()).isPresent())
                tbKakaoPayResultRepository.save(this.createTbKakaoPayResult(kkoBillPayResultVO));


            if ("Y".equals(fsJob.getBpEntrustYn())) {
                respVO = iupKkoPayApi.callApiByOrg(fsJob.getBpKkoPayresultApi(), mParam);

                if (!"OK".equals(respVO.getRes_code()))
                    this.modifyBillHistByRespInfo(kkoBillHist, respVO, EnsErrCd.ERR600, String.format("[%s] %s", respVO.getRes_code(), respVO.getMessage()));

                return respVO;

            } else if ("N".equals(fsJob.getBpEntrustYn())) {

            } else {
                kkoBillErrCd = BillKkoErrCd.E601;
                throw new EnsException(EnsErrCd.ERR999, "위탁업체여부 구분값이 등록되지 않았습니다.");
            }


            respVO = BillKkoApiRespDTO.okBuilder()
                    .data(null)
                    .build();


            this.modifyBillHistByRespInfo(kkoBillHist, respVO, null, null);
        } catch (EnsException e) {
            respVO = BillKkoApiRespDTO.errBuilder()
                    .resCode(kkoBillErrCd.getCode())
                    .message(kkoBillErrCd.getCodeNm())
                    .build();

            this.modifyBillHistByRespInfo(kkoBillHist, respVO, e.getErrCd(), e.getMessage());
        } catch (Exception e) {
            respVO = BillKkoApiRespDTO.errBuilder()
                    .resCode(BillKkoErrCd.E601.getCode())
                    .message(BillKkoErrCd.E601.getCodeNm())
                    .build();

            this.modifyBillHistByRespInfo(kkoBillHist, respVO, EnsErrCd.ERR999, e.getMessage());
        }

        return respVO;
    }


    private TbKakaoPayResult createTbKakaoPayResult(BillKkoPayResultData kkoBillPayResultVO) {


        final String jobSe = "EL".equals(kkoBillPayResultVO.getBiller_user_key().substring(0, 2)) ? "2" : "1";


        return TbKakaoPayResult.builder()
                .dataId(kkoBillPayResultVO.getBiller_user_key())
                .jobSe(jobSe)
                .payMn(kkoBillPayResultVO.getPay_by())
                .payTy(kkoBillPayResultVO.getPay_type())
                .payDetail1(kkoBillPayResultVO.getPay_detail1())
                .payDetail2(kkoBillPayResultVO.getPay_detail2())
                .payDetail3(kkoBillPayResultVO.getPay_detail3())
                .payAmount(kkoBillPayResultVO.getPay_amount())
                .payFeeTy(kkoBillPayResultVO.getPay_fee_type())
                .payFeeAmount(kkoBillPayResultVO.getPay_fee())
                .payFeeVat(kkoBillPayResultVO.getPay_fee_tax())
                .excclcPrearngeDe(kkoBillPayResultVO.getAdjust_date())
                .payDt(kkoBillPayResultVO.getPaid_at())
                .payId(kkoBillPayResultVO.getPay_id())
                .payResultProcessSttus("0")
//                    .creatDt()
                .crtr("ENS_SYS")
//                    .updtDt()
//                    .updusr()
                .build();

    }

    private Optional<TbInputDataXit> getTbInputDataXitByLinkedUuid(String linkedUuid) {
        return Optional.ofNullable(query.select(QTbInputDataXit.tbInputDataXit)
                .from(QTbInputDataXit.tbInputDataXit)
                .innerJoin(QTbInputDataXit.tbInputDataXit.tbInputXit, QTbInputXit.tbInputXit)
                .innerJoin(QTbInputDataXit.tbInputDataXit.tbInputXit.fsJob, QFsJob.fsJob)
                .where(QTbInputDataXit.tbInputDataXit.linkedUuid.eq(linkedUuid))
                .fetchOne());
    }
}
