@Override
  public CCPCBillInfo queryCCPCBillInfo(String mrchNo, String rmtAccNo, String payNo) {
    CCPCBillInfo billInfo = null;
    PayCCPC payCCPC = payCCPCService.findPayCCPCByPayNoAndMrchNo(payNo, mrchNo);
    if (payCCPC != null) {
      if (StringUtils.isNotBlank(rmtAccNo)) {
        if (payCCPC.getRmtAccNo().equals(rmtAccNo)) {
          throw new AppRTException(
              AppExCode.ILLEGAL_PARAMS,
              "非法数据,transRefNo["
                  + payNo
                  + "]对应rmtAccNo["
                  + rmtAccNo
                  + "],但查出的是rmtAccNo["
                  + payCCPC.getRmtAccNo()
                  + "]");
        }
      }
      billInfo = XPOSPClientUtils.payCCPCToCCPCBillInfo(payCCPC);

      String elecsignsPath =
          XpospSysProperty.getESignaturePath()
              + payCCPC.getMrchNo()
              + File.separatorChar
              + payCCPC.getStoreNo()
              + File.separatorChar;
      String rmtElecSignDataFileName =
          payNo + "-rmt" + "." + XPOSPClientUtils.ESIGNATURE_PICTURE_SUFFIX;
      String bnyElecSignDataFileName =
          payNo + "-bny" + "." + XPOSPClientUtils.ESIGNATURE_PICTURE_SUFFIX;
      File remitElecSignDataFile = new File(elecsignsPath + rmtElecSignDataFileName);
      File bnyElecSignDataFile = new File(elecsignsPath + bnyElecSignDataFileName);
      if (remitElecSignDataFile.exists()) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        BufferedImage image;
        try {
          image = ImageIO.read(remitElecSignDataFile);
          ImageIO.write(image, XPOSPClientUtils.BILLINFO_PICTURE_SUFFIX, out);
          billInfo.setRmtElecsignData(CodecUtils.hexString(out.toByteArray()));
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
      if (bnyElecSignDataFile.exists()) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        BufferedImage image;
        try {
          image = ImageIO.read(bnyElecSignDataFile);
          ImageIO.write(image, XPOSPClientUtils.BILLINFO_PICTURE_SUFFIX, out);
          billInfo.setBnyElecsignData(CodecUtils.hexString(out.toByteArray()));
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    return billInfo;
  }
 public TrackContext getTrackData(String key, String input) throws HSMException {
   String track2Str = null;
   String track3Str = null;
   try {
     byte[] tracks =
         hsmService.descryptData(
             HSM.ALGFLAG_3DES_2ECB, CodecUtils.hex2byte(key), CodecUtils.hex2byte(input));
     String trackStr = ISOUtils.bcd2str(tracks, 0, tracks.length * 2, true);
     int offset = 0;
     int lengthLen = 2;
     int track2Len = Integer.valueOf(trackStr.substring(offset, offset + lengthLen));
     offset += lengthLen;
     track2Str = trackStr.substring(offset, offset + track2Len);
     offset += track2Len;
     lengthLen = 3;
     int track3Len = Integer.valueOf(trackStr.substring(offset, offset + lengthLen));
     offset += lengthLen;
     track3Str = trackStr.substring(offset, offset + track3Len);
   } catch (Exception e) {
     e.printStackTrace();
     throw new HSMException(HSMExcCode.DECODE_TRACK_ERROR, "[解密磁道数据失败!]");
   }
   return new TrackContext(track2Str, track3Str);
 }
  @Override
  public BillInfo findBillInfo(String transType, String transRefNo, String mrchNo, String storeNo) {
    BillInfo billInfo = null;
    CashLoad cashLoad = new CashLoad();
    cashLoad.setTransNo(transRefNo);
    cashLoad.setMrchNo(mrchNo);
    cashLoad.setStoreNo(storeNo);
    cashLoad = cashLoadDao.queryLoad(cashLoad);
    TransferChannel channel = transferRouter.findChannel(cashLoad.getTargetChannel());
    billInfo = channel.findBillInfo(transRefNo);

    TransferChannelType channelType =
        TransferChannelType.fromChannelName(cashLoad.getTargetChannel());
    // 设置其他非传统CUPS交易数据
    billInfo.setTransferChannel(channelType.getChannelId());
    billInfo.setMrchName(cashLoad.getMrchName());
    billInfo.setStoreName(cashLoad.getStoreName());
    billInfo.setOperatorName(cashLoad.getOperatorName()); // 是否要显示真实交易姓名
    billInfo.setTransRefNo(cashLoad.getTransNo());
    billInfo.setTransToken(cashLoad.getUpSno());

    String elecsignsPath =
        baseESignaturePath
            + cashLoad.getMrchNo()
            + File.separatorChar
            + cashLoad.getStoreNo()
            + File.separatorChar;
    String fileName = transRefNo + "-" + transType + "." + XPOSPClientUtils.BILLINFO_PICTURE_SUFFIX;
    logger.debug("[圈存电子签购单路径elecsignsPath:" + elecsignsPath + ",fileName:" + fileName + "]");
    File file = new File(elecsignsPath + fileName);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    if (file.exists()) {
      BufferedImage image;
      try {
        image = ImageIO.read(file);
        ImageIO.write(image, XPOSPClientUtils.BILLINFO_PICTURE_SUFFIX, out);
        billInfo.setElecSignData(CodecUtils.hexString(out.toByteArray()));
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return billInfo;
  }
  public UlinkplusResponseInfo process(
      CupsTrmnl cupsTrmnl, UlinkplusKeyManage ulinkplusKeyManage, UlinkplusRequestInfo request)
      throws TransferFailedException {
    logger.info("ulinkplus渠道信用卡手续费查询开始...");
    // 1.组装报文
    CreditcardFeeQueryTradeRequestEntity requestEntity =
        packUp(cupsTrmnl, ulinkplusKeyManage, request);

    // TODO 是否需要记录交易流水

    // 1.2mac计算
    byte[] iso_8583_main = requestEntity.pack();
    byte[] input = ArrayUtils.subarray(iso_8583_main, 6, iso_8583_main.length - 8); // 去除body head
    byte[] macKey = CodecUtils.hex2byte(ulinkplusKeyManage.getTrmnlMacKey());

    //		byte[] mac = MacUtils.tCountMAC_CBC(input, macKey);
    //		input = ArrayUtils.subarray(iso_8583_main, 0, iso_8583_main.length-8);
    //		iso_8583_main = ArrayUtils.addAll(input, mac);

    byte[] mac;
    try {
      mac = CodecUtils.hex2byte(hsmService.calculateMAC_LOCALLIFE(macKey, input));
      input = ArrayUtils.subarray(iso_8583_main, 0, iso_8583_main.length - 8);
      iso_8583_main = ArrayUtils.addAll(input, mac);
    } catch (HSMException e) {
      String hsmRespCode = XPOSPClientUtils.getCode(e);
      if (!AppExCode.UNKNOWN.equals(hsmRespCode)) {
        hsmRespCode = Const.TP_BEGIN_HSM + hsmRespCode;
      }
      logger.error(
          "ulinkplus credicard fee query failed,when calculate mac form hsm error code["
              + hsmRespCode
              + "]");
      throw new TransferFailedException(
          hsmRespCode,
          "ulinkplus credicard fee query failed,when calculate mac form hsm error code["
              + hsmRespCode
              + "]");
    }
    // 1.3组装报文报文头
    byte[] iso_8583_body =
        ArrayUtils.addAll(
            XPOSPClientUtils.getTpduHeader(XpospSysProperty.getUlinkPlusQmf1TPDU()).pack(),
            iso_8583_main);
    String iso_8583_body_length =
        StringUtils.leftPad(Integer.toHexString(iso_8583_body.length), 4, "0");
    byte[] iso_8583_length = ISOUtils.hex2byte(iso_8583_body_length);
    byte[] iso_8583 = ArrayUtils.addAll(iso_8583_length, iso_8583_body);

    // 2.发送报文
    byte[] respData =
        TCPUtils.getInstance().sendReciveMsg(iso_8583, XpospSysProperty.getUlinkPlusQMFIP_PORT());

    // 3.解析报文
    UlinkplusResponseInfo response = new UlinkplusResponseInfo();
    try {
      CreditcardFeeQueryTradeResponseEntity responseEntity = unpack(respData);
      // CreditcardFeeQueryTradeResponseEntity responseEntity = getResponseData(null);
      String isoRespCode = responseEntity.getRespCode();
      if (!Const.ISO_RESPCODE_OK.equals(isoRespCode)) {
        isoRespCode = XPOSPClientUtils.getRespCode(isoRespCode);
        isoRespCode =
            Const.TP_BEGIN_ISO + StringUtils.leftPad("" + Integer.parseInt(isoRespCode), 3, "0");

        logger.info(
            "pay via ulinkplus failed,iso error code[" + responseEntity.getRespCode() + "]");
        throw new TransferFailedException(
            isoRespCode,
            "pay via ulinkplus failed,iso error code[" + responseEntity.getRespCode() + "]");
      }

      // 响应
      try {
        String selfDefined48 = new String(responseEntity.getSelfDefined48(), "GBK");
        logger.debug("信用卡还款手续费查询,48域信息:" + selfDefined48);
        // 位置	长度	格式	内容	说明
        // 0	2	n2	用法标志	“PA”
        // 2	2	n2	帐单号码类型	08
        // 4	12	n12	还款总金额	右对齐,左补空格
        // 16	12	n12	手续费	右对齐,左补空格
        // 28	12	n12	还款金额	右对齐,左补空格
        // 40	100	Ans100	终端提示信息	左对齐,右补空格
        // 140	11	N11	手机号码	左对齐,右补空格
        // 151	1	ans1	结束标志	#
        response.setFee(
            StringUtils.amtToBigDecimal(StringUtils.trimToEmpty(selfDefined48.substring(16, 28)))
                .toPlainString());
        response.setMsgTip(
            StringUtils.trimToEmpty(selfDefined48.substring(40, selfDefined48.length() - 12)));
      } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
      }
    } catch (RuntimeException e) {
      // 更新终端流水
      cupsTrmnlService.updateCupsTrmnlFlowNo(cupsTrmnl);
      throw e;
    }

    logger.info("ulinkplus渠道手机充值结束...");
    return response;
  }
  public PepsiColaResponseInfo process(
      CupsTrmnl cupsTrmnl, CupsKeyManage cupsKeyManage, PepsiColaRequestInfo request)
      throws TransferFailedException {
    logger.info("[PepsiCola渠道IC卡脚本上送开始...]");
    // 1.组装报文
    IcScriptUploadTradeRequestEntity requestEntity = packUp(cupsTrmnl, cupsKeyManage, request);
    // iso mac计算
    byte[] iso_8583_main = requestEntity.pack();
    byte[] input = ArrayUtils.subarray(iso_8583_main, 6, iso_8583_main.length - 8);
    byte[] macKey = CodecUtils.hex2byte(cupsKeyManage.getTrmnlMacKey());
    byte[] mac;
    try {
      mac = hsmService.calculateMAC_CUPS(macKey, input).getBytes();
      input = ArrayUtils.subarray(iso_8583_main, 0, iso_8583_main.length - 8);
      iso_8583_main = ArrayUtils.addAll(input, mac);
    } catch (HSMException e) {
      String hsmRespCode = XPOSPClientUtils.getCode(e);
      if (!AppExCode.UNKNOWN.equals(hsmRespCode)) {
        hsmRespCode = Const.TP_BEGIN_HSM + hsmRespCode;
      }
      logger.error("[IC卡脚本上送失败,calculate mac form hsm error code:" + hsmRespCode + "]");
      throw new TransferFailedException(
          hsmRespCode, "[IC卡脚本上送失败, 加密机计算MAC失败, errorCode:" + hsmRespCode + "]");
    }

    // 组装报文报文头
    byte[] iso_8583_body =
        ArrayUtils.addAll(
            XPOSPClientUtils.getTpduHeader(XpospSysProperty.getPepsiColaTPDU()).pack(),
            iso_8583_main);
    String iso_8583_body_length =
        StringUtils.leftPad(Integer.toHexString(iso_8583_body.length), 4, "0");
    byte[] iso_8583_length = ISOUtils.hex2byte(iso_8583_body_length);
    byte[] iso_8583 = ArrayUtils.addAll(iso_8583_length, iso_8583_body);

    // 新增银联CUPS流水记录 {2,3,4,11,22,25,26,35,36,41,42,49,52,53,60,64}
    String payNo = transRefNoGenerator.generate();
    PayCups payCups = new PayCups();
    payCups.setPayNo(payNo);
    payCups.setCardNo(requestEntity.getCardNo());
    payCups.setProcessCode(requestEntity.getProcessCode());
    payCups.setTrmnlFlowNo(requestEntity.getTrmnlFlowNo());
    payCups.setTrmnlBatchNo(cupsTrmnl.getTrmnlBatchNo());
    payCups.setPosEntryMode(requestEntity.getPosEntryMode());
    payCups.setCardSeqNum(request.getCardSeqNum());
    payCups.setTrmnlNo(requestEntity.getTrmnlNo());
    payCups.setTrmnlMrchNo(requestEntity.getTrmnlMrchNo());
    payCups.setCurrency(requestEntity.getCurrency());
    payCups.setIcData(request.getEmvTransInfo());
    payCups.setSelfDefined060(requestEntity.getSelfDefined60());
    payCups.setOriginalInfo(requestEntity.getOriginalMessage());
    payCups.setTransType(TransType.ICSCRIPTUPLOAD.getOrdinal());
    payCups.setSubChannel(SubChannelType.PEPSICOLATRANSFERCHANNEL.getChannelName());
    payCupsService.addPayCups(payCups);
    // 打包,新增流水记录后更新终端流水信息
    cupsTrmnlService.updateCupsTrmnlFlowNo(cupsTrmnl);

    // 2.发送报文
    byte[] respData =
        TCPUtils.getInstance().sendReciveMsg(iso_8583, XpospSysProperty.getPepsiColaIP_PORT());

    // 3.解析报文
    PepsiColaResponseInfo pepsiColaResponseInfo = new PepsiColaResponseInfo();
    try {
      IcScriptUploadTradeResponseEntity responseEntity = unpack(respData);
      String isoRespCode = responseEntity.getRespCode();
      if (!Const.ISO_RESPCODE_OK.equals(isoRespCode)) {
        payCups.setRespCode(isoRespCode);
        isoRespCode = isoRespCode.replace("A", "10");
        payCupsService.updatePayCups(payCups);
        isoRespCode =
            Const.TP_BEGIN_ISO + StringUtils.leftPad("" + Integer.parseInt(isoRespCode), 3, "0");

        logger.error("[pay via cups failed, iso error code:" + isoRespCode + "]");
        throw new TransferFailedException(
            isoRespCode, "[pay via cups failed, so error code:" + isoRespCode + "]");
      }

      // 更新交易流水
      payCups.setTransDate(responseEntity.getTransDate());
      payCups.setTransTime(responseEntity.getTransTime());
      payCups.setSettlementDate(responseEntity.getSettlementDate());
      payCups.setRespCode(responseEntity.getRespCode());
      payCupsService.updatePayCups(payCups);

      pepsiColaResponseInfo.setTransCode(
          Const.TP_BEGIN_ISO + StringUtils.leftPad("" + Integer.parseInt(isoRespCode), 3, "0"));
      // 响应
    } catch (RuntimeException e) {
      throw e;
    }
    logger.info("[PepsiCola渠道IC卡脚本上送结束...]");
    return pepsiColaResponseInfo;
  }
  /**
   * 获取ICData
   *
   * @param icData 原始交易上送的脚本
   * @param icScript 二次授权获取的脚本
   * @return
   */
  private static byte[] getIcData(String icData, ICScript icScript) {
    if (StringUtils.isBlank(icData)) {
      return null;
    }
    SimpleTLVPackage tlvPackage = new SimpleTLVPackage();

    byte[] icDataRequestByte = CodecUtils.hex2byte(icData);
    SimpleTLVPackage simpleTLVPackage = new SimpleTLVPackage();
    simpleTLVPackage.unpack(icDataRequestByte);
    byte[] tag_9F36 = simpleTLVPackage.getValue(EmvStandardReference.APP_TRANSACTION_COUNTER);
    byte[] tag_82 = simpleTLVPackage.getValue(EmvStandardReference.APPLICATION_INTERCHANGE_PROFILE);
    byte[] tag_9F1A = simpleTLVPackage.getValue(EmvStandardReference.TERMINAL_COUNTRY_CODE);
    byte[] tag_9A = simpleTLVPackage.getValue(EmvStandardReference.TRANSACTION_DATE);

    byte[] tag_9F33 = simpleTLVPackage.getValue(EmvStandardReference.TERMINAL_CAPABILITIES);
    byte[] tag_9F37 = simpleTLVPackage.getValue(EmvStandardReference.UNPREDICTABLE_NUMBER);
    byte[] tag_9F1E =
        simpleTLVPackage.getValue(EmvStandardReference.INTERFACE_DEVICE_SERIAL_NUMBER);

    SimpleTLVMsg tlv_9F36 =
        new SimpleTLVMsg(EmvStandardReference.APP_TRANSACTION_COUNTER, tag_9F36);
    tlvPackage.append(tlv_9F36);
    SimpleTLVMsg tlv_82 =
        new SimpleTLVMsg(EmvStandardReference.APPLICATION_INTERCHANGE_PROFILE, tag_82);
    tlvPackage.append(tlv_82);
    SimpleTLVMsg tlv_9F1A = new SimpleTLVMsg(EmvStandardReference.TERMINAL_COUNTRY_CODE, tag_9F1A);
    tlvPackage.append(tlv_9F1A);
    SimpleTLVMsg tlv_9A = new SimpleTLVMsg(EmvStandardReference.TRANSACTION_DATE, tag_9A);
    tlvPackage.append(tlv_9A);

    if (tag_9F33 != null) {
      SimpleTLVMsg tlv_9F33 =
          new SimpleTLVMsg(EmvStandardReference.TERMINAL_CAPABILITIES, tag_9F33);
      tlvPackage.append(tlv_9F33);
    }
    if (tag_9F37 != null) {
      SimpleTLVMsg tlv_9F37 = new SimpleTLVMsg(EmvStandardReference.UNPREDICTABLE_NUMBER, tag_9F37);
      tlvPackage.append(tlv_9F37);
    }
    if (tag_9F1E != null) {
      SimpleTLVMsg tlv_9F1E =
          new SimpleTLVMsg(EmvStandardReference.INTERFACE_DEVICE_SERIAL_NUMBER, tag_9F1E);
      tlvPackage.append(tlv_9F1E);
    }

    byte[] tag_95 = CodecUtils.hex2byte(icScript.getTrmlVerificationResult());
    SimpleTLVMsg tlv_95 = new SimpleTLVMsg();
    tlv_95.setTag(EmvStandardReference.TERMINAL_VERIFICATION_RESULTS);
    tlv_95.setValue(tag_95);
    tlvPackage.append(tlv_95);

    byte[] tag_9F10 = CodecUtils.hex2byte(icScript.getIssuerAppData());
    SimpleTLVMsg tlv_9F10 = new SimpleTLVMsg();
    tlv_9F10.setTag(EmvStandardReference.ISSUER_APPLICATION_DATA);
    tlv_9F10.setValue(tag_9F10);
    tlvPackage.append(tlv_9F10);

    byte[] tag_9F26 = CodecUtils.hex2byte(icScript.getAppCryptogram());
    SimpleTLVMsg tlv_9F26 = new SimpleTLVMsg();
    tlv_9F26.setTag(EmvStandardReference.APP_CRYPTOGRAM);
    tlv_9F26.setValue(tag_9F26);
    tlvPackage.append(tlv_9F26);

    if (StringUtils.isNotEmpty(icScript.getScriptExecuteRslt())) {
      byte[] tag_DF31 = CodecUtils.hex2byte(icScript.getScriptExecuteRslt());
      SimpleTLVMsg tlv_DF31 = new SimpleTLVMsg();
      tlv_DF31.setTag(EmvSelfDefinedReference.SCRIPT_EXECUTE_RSLT);
      tlv_DF31.setValue(tag_DF31);
      tlvPackage.append(tlv_DF31);
    }

    return tlvPackage.pack();
  }