@Override
 public void bindDevice(Device device, Store store) throws AppBizException {
   List<CupsTrmnl> cupsTrmnlList =
       cupsTrmnlService.findInactiviteTrmnl(store.getMrchNo(), store.getStoreNo());
   if (cupsTrmnlList == null || cupsTrmnlList.size() <= 0) {
     throw new AppBizException(AppExCode.UNAVAILABLE_TERMINAL, "not find available terminal");
   }
   CupsTrmnl cupsTrmnl = cupsTrmnlList.get(0);
   device.setTargetChannel(store.getTargetChannel());
   device.setBindTransId(cupsTrmnl.getTrmnlId());
   cupsTrmnl.setIsActive(Const.VLDSTATE_VALID);
   cupsTrmnl.setRemark(
       StringUtils.isNotBlank(device.getDevSn()) ? device.getDevSn() : device.getDevKsn());
   cupsTrmnlService.updateCupsTrmnl(cupsTrmnl);
 }
 private CreditcardFeeQueryTradeRequestEntity packUp(
     CupsTrmnl cupsTrmnl, UlinkplusKeyManage ulinkplusKeyManage, UlinkplusRequestInfo request)
     throws TransferFailedException {
   // 消费报文打包
   // {2,3,4,11,22,25,41,42,48,49,64}
   CreditcardFeeQueryTradeRequestEntity requestEntity = new CreditcardFeeQueryTradeRequestEntity();
   requestEntity.setCardNo(request.getCardNo()); // 2
   requestEntity.setProcessCode("310000"); // 3
   requestEntity.setTransAmt(StringUtils.amtToBCD(request.getAmount())); // 4
   requestEntity.setTrmnlFlowNo(cupsTrmnl.getTrmnlFlowNo()); // 11
   requestEntity.setPosEntryMode("012"); // 22
   requestEntity.setServiceCode("92"); // 25
   requestEntity.setTrmnlNo(cupsTrmnl.getTrmnlNo());
   requestEntity.setTrmnlMrchNo(cupsTrmnl.getMrchNo());
   // 位置	长度	格式	内容	说明
   // 0	2	n2	用法标志	“PA”
   // 2	2	n2	帐单号码类型	08
   // 4	19	Ans19	信用卡卡码	左对齐,右补空格
   // 23	11	N11	手机号码
   // 34	1	ans1	结束标志	#
   // PA086222040000000001   #
   requestEntity.setSelfDefined48(
       ("PA08" + StringUtils.rightPad(request.getCreditcardNo(), 19, " ") + "#").getBytes());
   requestEntity.setCurrency(Currency.CNY.getCodeN());
   requestEntity.setMacCode(new byte[8]);
   cupsTrmnlService.updateCupsTrmnlFlowNo(cupsTrmnl);
   return requestEntity;
 }
 @Override
 public void syncPayCancelLog(PayCancel payCancel) {
   PayCups payCups = payCupsService.findPayCups(payCancel.getPaycancelNo());
   if (payCups == null) {
     // throw new TransferFailedException(AppExCode.TRANS_NOT_EXIST, "sysncPayLog failed,not find
     // payCups");
     payCancel.setTransStatus(Const.TransStatus.FAILED); // 银联直连表无交易流水记录,未发交易,撤销失败
     return;
   }
   // 如果iso中心已经返回,但app与xposp已经断开
   String isoRespCode = payCups.getRespCode();
   if (StringUtils.isNotBlank(isoRespCode)) {
     // modify zengyj 20140716 服务端到银联已经响应成功,但客户端因超时交易未知
     if (Const.ISO_RESPCODE_OK.equals(isoRespCode)) {
       payCancel.setTransStatus(Const.TransStatus.SUCCESS);
     } else {
       payCancel.setTransStatus(Const.TransStatus.FAILED);
       isoRespCode =
           Const.TP_BEGIN_ISO + StringUtils.leftPad("" + Integer.parseInt(isoRespCode), 3, "0");
       payCancel.setErrCode(isoRespCode);
     }
     return;
   }
   CupsTrmnl cupsTrmnl =
       cupsTrmnlService.findByTrmnlNoAndMrchNo(payCups.getTrmnlNo(), payCups.getTrmnlMrchNo());
   if (cupsTrmnl == null) {
     throw new TransferFailedException(
         AppExCode.TERMINAL_NOT_EXIST, "goodee sysncPayLog failed,not find CupsTrmnl");
   }
   reversalProcess.process(cupsTrmnl, payCups, getAddress(payCancel.getAppAccessId()));
   payCancel.setTransStatus(TransStatus.FAILED);
 }
 @Override
 public boolean signUp(Device device) throws TransferFailedException {
   boolean isSignUpSuccess = false;
   CupsTrmnl cupsTrmnl = cupsTrmnlService.findById(device.getBindTransId());
   if (cupsTrmnl == null) {
     throw new TransferFailedException(
         AppExCode.TERMINAL_NOT_EXIST, "goodee signup failed,not find CupsTrmnl");
   }
   PaySignUp paySignUp =
       paySignUpService.findPaySignUpByMrchNoAndTrmnlNo(
           cupsTrmnl.getMrchNo(), cupsTrmnl.getTrmnlNo());
   if (paySignUp != null) {
     if (StringUtils.isNotBlank(paySignUp.getRespCode())
         && Const.ISO_RESPCODE_OK.equals(paySignUp.getRespCode())) {
       long workingKeyTimeout = paySignUp.getUpdTime().getTime() + Const.WORKING_KEY_TIMEOUT;
       long nowTime = (new Date()).getTime();
       if (workingKeyTimeout > nowTime) {
         isSignUpSuccess = true;
       }
     }
   }
   if (!isSignUpSuccess) {
     signUpProcess.process(cupsTrmnl);
     isSignUpSuccess = true;
   }
   return isSignUpSuccess;
 }
 /**
  * 通道错误码处理
  *
  * @param code
  * @param cupsTrmnl
  */
 private void processErrorCode(String code, CupsTrmnl cupsTrmnl) {
   /*if(AppExCode.ISO_NOT_ALLOW_TERMINAL_TRADE.equalsIgnoreCase(code)){//iso code 58
   	signUpProcess.process(cupsTrmnl);
   }*/
   if (AppExCode.ISO_MAC_ERROR.equals(code)
       || AppExCode.ISO_NOT_ALLOW_TERMINAL_TRADE.equals(code)) { // iso code A0
     signUpProcess.process(cupsTrmnl);
   }
   if (AppExCode.ISO_REPEAT_DEAL.equals(code)) { // iso code 94
     cupsTrmnlService.updateCupsTrmnlFlowNo(cupsTrmnl);
   }
 }
 @Override
 public void syncCashLoadLog(PayCashLoad cashLoad, Integer appSyn) {
   PayCups payCups = payCupsService.findPayCups(cashLoad.getCashLoadNo());
   if (payCups == null) {
     // throw new TransferFailedException(AppExCode.TRANS_NOT_EXIST, "sysncPayLog failed,not find
     // payCups");
     cashLoad.setTransStatus(Const.TransStatus.FAILED); // 银联直连表无交易流水记录,未发交易,消费失败
     return;
   }
   if (appSyn == null) {
     // 如果iso中心已经返回,但app与xposp已经断开,写卡失败
     String isoRespCode = payCups.getRespCode();
     if (StringUtils.isNotBlank(isoRespCode)) {
       // 服务端到银联已经响应成功,但客户端因超时交易未知
       if (Const.ISO_RESPCODE_OK.equals(isoRespCode)) {
         cashLoad.setTransStatus(Const.TransStatus.SUCCESS);
       } else {
         cashLoad.setTransStatus(Const.TransStatus.FAILED);
         isoRespCode =
             Const.TP_BEGIN_ISO
                 + StringUtils.leftPad(
                     "" + Integer.parseInt(isoRespCode.replace("A", "10")), 3, "0");
         cashLoad.setErrCode(isoRespCode);
       }
       return;
     }
   }
   CupsTrmnl cupsTrmnl =
       cupsTrmnlService.findByTrmnlNoAndMrchNo(payCups.getTrmnlNo(), payCups.getTrmnlMrchNo());
   if (cupsTrmnl == null) {
     throw new TransferFailedException(
         AppExCode.TERMINAL_NOT_EXIST, "sysncPayLog failed,not find CupsTrmnl");
   }
   reversalProcess.process(cupsTrmnl, payCups);
   cashLoad.setTransStatus(TransStatus.FAILED);
 }
  /**
   * 分页查询PayUpmp表
   *
   * @return
   */
  public List<SendFlow> insertPayUpmp(List<PayUpmp> payUpmpList) {
    List<SendFlow> flowList = new LinkedList<SendFlow>();
    for (PayUpmp payUpmp : payUpmpList) {
      SendFlow sendFlow = new SendFlow();
      String transCode = null;
      // 交易类型判断
      switch ((payUpmp.getTransType())) {
        case 1:
          transCode = "S00"; // 签到
          break;
        case 2:
          transCode = "S22"; // 消费
          break;
        case 3:
          transCode = "V52"; // 消费撤销
          break;
        case 4:
          transCode = "R22"; // 消费冲正
          break;
        case 5:
          transCode = "R22"; // 撤销冲正
          break;
        case 6:
          transCode = "S00"; // 余额查询
          break;
        case 7:
          transCode = "S22"; // 北京渠道-转账
          break;
        case 8:
          transCode = "V52"; // 北京渠道-转账撤销
          break;
        case 9:
          transCode = "S00"; // 生活服务-余额查询
          break;
        case 10:
          transCode = "S22"; // 生活服务-卡卡转账
          break;
        case 11:
          transCode = "S22"; // 生活服务-信用卡还款
          break;
        case 12:
          transCode = "S22"; // 生活服务-手机充值
          break;
        case 13:
          transCode = "I00"; // IC卡脚本上送
          break;
        case 14:
          transCode = "E23"; // 退货
          break;
        default:
          break;
      }
      sendFlow.setPayNo(payUpmp.getPayNo()); // 本地增值流水ID
      sendFlow.setAccountNo(payUpmp.getCardNo()); // 主账号 2
      sendFlow.setAmount(payUpmp.getTransAmt()); // 交易金额 4
      if ("S22".equals(transCode) || "V52".equals(transCode) || "S00".equals(transCode)) {
        // 消费、撤销、查询、生活服务0200
        sendFlow.setMsgType("0200");
      }
      if ("R22".equals(transCode)) {
        // 冲正交易送0400
        sendFlow.setMsgType("0400");
      }
      if ("I00".equals(transCode)) {
        // IC卡脚本上送 0620
        sendFlow.setMsgType("0620");
      }
      if ("E23".equals(transCode)) {
        // 退货送0220
        sendFlow.setMsgType("0220");
      }
      // 消息类型
      sendFlow.setSettleDate(payUpmp.getSettlementDate()); // 清算日期 15
      sendFlow.setAcqOrgId(payUpmp.getAcqCode()); // 受理机构标识码 32
      sendFlow.setRespCode(payUpmp.getRespCode()); // 应答码 39
      /*List<CupsTrmnl> cupsTrmnlList = cupsTrmnlService.findByMrchNo(payUpmp.getMrchNo());
      if(null != cupsTrmnlList){
      	sendFlow.setTermId(cupsTrmnlList.get(0).getTrmnlNo());//终端编号 41
      }*/
      sendFlow.setTermId("01080209");
      sendFlow.setTermIdt(payUpmp.getMrchNo()); // 受卡方标识码 42 (商户编号)
      sendFlow.setTransCode(transCode); // 交易代码
      sendFlow.setMcc(payUpmp.getMrchNo().substring(7, 11)); // 商户类型(MCC码)

      CardBin cardBin = null;
      String cardType = null;
      if (null != (payUpmp.getCardNo())
          && !("".equals((payUpmp.getCardNo())) && payUpmp.getCardNo().length() > 6)) {
        cardBin = cardBinService.findByCardNo((payUpmp.getCardNo()));
      }
      if (null != cardBin) {
        cardType = cardBin.getCardType();
        sendFlow.setCardType(cardType); // 卡性质
      }

      sendFlow.setBrancStructure("100200"); // 所属分支结构(江苏)
      String acqCode = payUpmp.getAcqCode(); // 受理机构标识码
      String mercInstitution = null;
      if (null != acqCode) {
        acqCode = acqCode.trim();
      }
      // 根据受理机构标识码判断商户所属机构
      if ("48023010".equals(acqCode)) {
        mercInstitution = "100200"; // 南京
      }
      if ("48023070".equals(acqCode)) {
        mercInstitution = "100201"; // 连云港
      }
      if ("48023140".equals(acqCode)) {
        mercInstitution = "100202"; // 镇江
      }
      if ("48023110".equals(acqCode)) {
        mercInstitution = "100203"; // 盐城
      }
      if ("48023060".equals(acqCode)) {
        mercInstitution = "100204"; // 南通
      }
      if ("48023050".equals(acqCode)) {
        mercInstitution = "100205"; // 苏州
      }
      if ("48023020".equals(acqCode)) {
        mercInstitution = "100206"; // 无锡
      }
      if ("48023040".equals(acqCode)) {
        mercInstitution = "100207"; // 常州
      }
      if ("48023120".equals(acqCode)) {
        mercInstitution = "100208"; // 扬州
      }
      if ("48023160".equals(acqCode)) {
        mercInstitution = "100209"; // 泰州
      }
      if ("48023030".equals(acqCode)) {
        mercInstitution = "100210"; // 徐州
      }
      if ("48023080".equals(acqCode)) {
        mercInstitution = "100211"; // 淮安
      }
      if ("48023180".equals(acqCode)) {
        mercInstitution = "100212"; // 宿迁
      }
      sendFlow.setMercInstitution(mercInstitution); // 商户所属机构
      if (!"S22".equals(transCode)) {
        // 冲正类交易
        sendFlow.setOrgAmount(payUpmp.getTransAmt()); // 原始交易金额送交易金额
      }

      sendFlow.setLeadChannel("ulinkTraditon"); // 前置渠道默认upmp
      sendFlow.setPaymentChannel("ulinkTraditon"); // 支付通道默认upmp

      // 业务类型&产品编码&统一后业务类型
      String serviceType = null;
      String productCoding = null;
      String finalServiceType = null;
      if (2 == (payUpmp.getTransType())) {
        // upmp收单
        serviceType = "5A02";
        productCoding = "5A02";
        finalServiceType = "02";
      }
      sendFlow.setServiceType(serviceType); // 业务类型
      sendFlow.setProductCoding(productCoding); // 产品编码
      sendFlow.setFinalServiceType(finalServiceType); // 统一后业务类型
      List<CupsTrmnl> cupsTrmnlList = cupsTrmnlService.findByMrchNo(payUpmp.getMrchNo());
      if (null != cupsTrmnlList) {
        sendFlow.setAccpTermNo(cupsTrmnlList.get(0).getTrmnlNo()); // 受理点终端编号
      }
      sendFlow.setAccpMercNo(payUpmp.getMrchNo()); // 受理点商户编号
      sendFlow.setInitTerm("11"); // 发起终端(移动pos)
      sendFlow.setUpmpTransStatus(payUpmp.getTransStatus() + ""); // UPMP交易状态
      sendFlow.setTransOccrrenceTime(payUpmp.getCreTime()); // 交易发生时间
      sendFlow.setCreTime(new Date()); // 获得创建日期
      // 放入List
      flowList.add(sendFlow);
    }
    return flowList;
  }
  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;
  }
  @Override
  public boolean icScriptUpload(ICScriptUploadRequest request) {
    boolean isIcScriptUloadSuccess = false;
    List<ICScript> lists = request.getIcScripts();
    for (ICScript temp : lists) {
      if (temp == null) {
        continue;
      }
      // 获取原始交易信息
      String originalPayNo = temp.getTransRefNo();
      if (StringUtils.isEmpty(originalPayNo)) {
        throw new TransferFailedException(
            AppExCode.ILLEGAL_PARAMS,
            "goodee isScript upload failed! not find original payNo[" + originalPayNo + "]");
      }
      PayCups originalPayCups = payCupsService.findPayCups(originalPayNo);
      if (originalPayCups == null) {
        throw new TransferFailedException(
            AppExCode.TRANS_NOT_EXIST,
            "goodee isScript upload failed! not find original payNo[" + originalPayNo + "]");
      }
      int transTypeInt = originalPayCups.getTransType();
      if (!(TransType.CONSUME.getOrdinal() == transTypeInt
          || TransType.BALANCE.getOrdinal() == transTypeInt)) {
        throw new TransferFailedException(
            AppExCode.NOT_SUPPORTED_OPERATION,
            getDescription()
                + " channel not support icsSriptUpload["
                + transTypeInt
                + "] operation");
      }
      CupsTrmnl cupsTrmnl =
          cupsTrmnlService.findByTrmnlNoAndMrchNo(
              originalPayCups.getTrmnlNo(), originalPayCups.getTrmnlMrchNo());
      PaySignUp paySignUp =
          paySignUpService.findPaySignUpByMrchNoAndTrmnlNo(
              originalPayCups.getTrmnlMrchNo(), originalPayCups.getTrmnlNo());
      CupsKeyManage cupsKeyManage = new CupsKeyManage();
      cupsKeyManage.setTrmnlMacKey(paySignUp.getTrmnlMacKey());
      // 保存二次授权数据
      JSONObject json = JSONObject.fromObject(temp);
      originalPayCups.setIcScriptRlst(json.toString());
      originalPayCups = payCupsService.updatePayCups(originalPayCups);

      // 如果二次授权失败,则发起冲正交易,成功则保存二次授权数据,并且如果有脚本则上送脚本交易
      if (temp.getSecondAuthRlst() != null && temp.getSecondAuthRlst() == false) {
        // reversalProcess.process(cupsTrmnl, originalPayCups);
      } else {
        if (StringUtils.isNotEmpty(temp.getScriptExecuteRslt())) {
          CupsRequestInfo requestInfo = new CupsRequestInfo();
          requestInfo.setOriginalPayNo(temp.getTransRefNo());
          requestInfo.setIcScript(temp);
          try {
            icScriptUploadProcess.process(cupsTrmnl, cupsKeyManage, requestInfo);
          } catch (TransferFailedException e) {
            throw e;
          }
        }
      }
    }
    isIcScriptUloadSuccess = true;
    return isIcScriptUloadSuccess;
  }
  @Override
  public CardInfo balance(Device device, BalanceRequest request) throws TransferFailedException {
    logger.info("entryMode:" + request.getEntryMode());
    logger.info("Pinblock is not null:" + StringUtils.isNotBlank(request.getPinblock()));
    logger.info("EmvTransInfo is not null:" + StringUtils.isNotBlank(request.getEmvTransInfo()));

    // 校验数据
    if (StringUtils.isBlank(request.getCardNo())) {
      throw new TransferFailedException(
          AppExCode.ILLEGAL_PARAMS, "goodee balance failed,cardNo null");
    }
    if (StringUtils.isBlank(request.getTrack2Data())
        && StringUtils.isBlank(request.getTrackData())) {
      throw new TransferFailedException(
          AppExCode.ILLEGAL_PARAMS, "goodee banlance failed,track2data or trackData null");
    }
    // 卡输入方式
    if (StringUtils.isNotBlank(request.getEntryMode())) {
      boolean isOk =
          isEntryModeOk(request.getEntryMode(), request.getPinblock(), request.getEmvTransInfo());
      if (!isOk) {
        throw new TransferFailedException(
            AppExCode.ILLEGAL_PARAMS,
            "goodee balance failed,entryMode is "
                + request.getEntryMode()
                + " but pinBlock is not null:"
                + StringUtils.isNotBlank(request.getPinblock())
                + " ,emvTransInfo is not null:"
                + StringUtils.isNotBlank(request.getEmvTransInfo()));
      }
    }
    // 获取当前设备的终端信息
    CupsTrmnl cupsTrmnl = cupsTrmnlService.findById(device.getBindTransId());
    if (cupsTrmnl == null) {
      throw new TransferFailedException(
          AppExCode.TERMINAL_NOT_EXIST, "goodee banlance failed,not find CupsTrmnl");
    }
    // 获取密钥信息
    DeviceKeymanage deviceKeymanage =
        deviceKeymanageService.findDeviceKeymanageByDevId(device.getDevId());
    if (deviceKeymanage == null) {
      throw new TransferFailedException(
          AppExCode.DEVICE_KEY_NOT_EXIST, "goodee balance failed,not find deviceKeymanage info");
    }
    PaySignUp paySignUp =
        paySignUpService.findPaySignUpByMrchNoAndTrmnlNo(
            cupsTrmnl.getMrchNo(), cupsTrmnl.getTrmnlNo());
    if (paySignUp == null) {
      throw new TransferFailedException(
          AppExCode.TERMINAL_KEY_NOT_EXIST, "goodee pay failed,not find cups signUp info");
    }
    // 密钥体系转换
    CupsKeyManage cupsKeyManage = new CupsKeyManage();
    cupsKeyManage.setDevPinKey(deviceKeymanage.getPinkey());
    cupsKeyManage.setTrmnlPinKey(paySignUp.getTrmnlPinKey());
    cupsKeyManage.setTrmnlMacKey(paySignUp.getTrmnlMacKey());
    // CUPS请求信息
    CupsRequestInfo requestInfo = new CupsRequestInfo();
    requestInfo.setPinblock(request.getPinblock());
    requestInfo.setEmvTransInfo(request.getEmvTransInfo());
    requestInfo.setCardSeqNum(request.getCardSeqNum());
    requestInfo.setCurrency(request.getCurrency().getCodeN());
    try {
      TrackContext trackContext =
          getTrackData(deviceKeymanage.getDatakey(), request.getTrackData());
      requestInfo.setCardNo(trackContext.getTrack2Data().split("=")[0]);
      requestInfo.setTrack2Data(trackContext.getTrack2Data());
      requestInfo.setTrack3Data(trackContext.getTrack3Data());
    } catch (HSMException e) {
      String hsmRespCode = XPOSPClientUtils.getCode(e);
      if (!AppExCode.UNKNOWN.equals(hsmRespCode)) {
        hsmRespCode = Const.TP_BEGIN_HSM + hsmRespCode;
      }
      throw new TransferFailedException(
          hsmRespCode,
          "goodee balance failed, when descrypt track data form hsm error code["
              + hsmRespCode
              + "]");
    }
    CupsResponseInfo cupsResponseInfo = new CupsResponseInfo();
    try {
      cupsResponseInfo = balanceProcess.process(cupsTrmnl, cupsKeyManage, requestInfo);
    } catch (TransferFailedException e) {
      String errorCode = XPOSPClientUtils.getCode(e);
      processErrorCode(errorCode, cupsTrmnl);
      throw e;
    }
    CardInfo cardInfo = new CardInfo();
    cardInfo.setTransRefNo(cupsResponseInfo.getPayNo());
    cardInfo.setTransCode(cupsResponseInfo.getTransCode());
    cardInfo.setCardNo(request.getCardNo()); // 返回的卡号需带有掩码
    cardInfo.setBalance(cupsResponseInfo.getBalance());
    cardInfo.setEmvTransInfo(cupsResponseInfo.getEmvTransInfo());
    return cardInfo;
  }
  @Override
  public void refund(Device device, PayRefund refund, RefundRequest request)
      throws TransferFailedException {
    logger.info("entryMode:" + request.getEntryMode());
    logger.info("Pinblock is not null:" + StringUtils.isNotBlank(request.getPinblock()));
    logger.info("EmvTransInfo is not null:" + StringUtils.isNotBlank(request.getEmvTransInfo()));

    // 校验数据
    if (StringUtils.isBlank(request.getTrack2Data())
        && StringUtils.isBlank(request.getTrackData())) {
      throw new TransferFailedException(
          AppExCode.ILLEGAL_PARAMS, "goodee refund failed,track2data or trackData null");
    }
    // 卡输入方式
    if (StringUtils.isNotBlank(request.getEntryMode())) {
      boolean isOk =
          isEntryModeOk(request.getEntryMode(), request.getPinblock(), request.getEmvTransInfo());
      if (!isOk) {
        throw new TransferFailedException(
            AppExCode.ILLEGAL_PARAMS,
            "goodee refund failed,entryMode is "
                + request.getEntryMode()
                + " but pinBlock is not null:"
                + StringUtils.isNotBlank(request.getPinblock())
                + " ,emvTransInfo is not null:"
                + StringUtils.isNotBlank(request.getEmvTransInfo()));
      }
    }
    // modify by zengyj 20140331 cancel by orginal trmnl not by device trmnl;
    // 获取当前设备的终端信息
    PayCups originalPayCups = payCupsService.findPayCups(request.getLastTransRefNo());
    if (originalPayCups == null) {
      throw new TransferFailedException(
          AppExCode.TRANS_NOT_EXIST, "goodee refund failed,not find originalPayCups");
    }
    CupsTrmnl cupsTrmnl =
        cupsTrmnlService.findByTrmnlNoAndMrchNo(
            originalPayCups.getTrmnlNo(), originalPayCups.getTrmnlMrchNo());
    if (cupsTrmnl == null) {
      throw new TransferFailedException(
          AppExCode.TERMINAL_NOT_EXIST, "goodee refund failed,not find CupsTrmnl");
    }
    // 获取密钥信息
    DeviceKeymanage deviceKeymanage =
        deviceKeymanageService.findDeviceKeymanageByDevId(device.getDevId());
    if (deviceKeymanage == null) {
      throw new TransferFailedException(
          AppExCode.DEVICE_KEY_NOT_EXIST, "goodee refund failed,not find deviceKeymanage info");
    }
    PaySignUp paySignUp =
        paySignUpService.findPaySignUpByMrchNoAndTrmnlNo(
            cupsTrmnl.getMrchNo(), cupsTrmnl.getTrmnlNo());
    if (paySignUp == null) {
      throw new TransferFailedException(
          AppExCode.TERMINAL_KEY_NOT_EXIST, "goodee refund failed,not find cups signUp info");
    }
    // 密钥体系转换
    CupsKeyManage cupsKeyManage = new CupsKeyManage();
    cupsKeyManage.setDevPinKey(deviceKeymanage.getPinkey());
    cupsKeyManage.setTrmnlPinKey(paySignUp.getTrmnlPinKey());
    cupsKeyManage.setTrmnlMacKey(paySignUp.getTrmnlMacKey());
    // CUPS请求信息
    CupsRequestInfo requestInfo = new CupsRequestInfo();
    requestInfo.setPayNo(refund.getPayrefundNo());
    requestInfo.setAmount(refund.getPayAmt());
    requestInfo.setOriginalPayNo(request.getLastTransRefNo());
    requestInfo.setPinblock(request.getPinblock());
    requestInfo.setEmvTransInfo(request.getEmvTransInfo());
    requestInfo.setCardSeqNum(request.getCardSeqNum());
    requestInfo.setExtFld01(request.getStoreNo());
    requestInfo.setOrderNo(request.getOrderNo());
    try {
      TrackContext trackContext =
          getTrackData(deviceKeymanage.getDatakey(), request.getTrackData());
      requestInfo.setCardNo(trackContext.getTrack2Data().split("=")[0]);
      requestInfo.setTrack2Data(trackContext.getTrack2Data());
      requestInfo.setTrack3Data(trackContext.getTrack3Data());
    } catch (HSMException e) {
      String hsmRespCode = XPOSPClientUtils.getCode(e);
      if (!AppExCode.UNKNOWN.equals(hsmRespCode)) {
        hsmRespCode = Const.TP_BEGIN_HSM + hsmRespCode;
      }
      throw new TransferFailedException(
          hsmRespCode,
          "goodee refund failed, when descrypt track data form hsm error code["
              + hsmRespCode
              + "]");
    }
    try {
      refundProcess.process(
          cupsTrmnl, cupsKeyManage, requestInfo, getAddress(refund.getAppAccessId()));
    } catch (TransferFailedException e) {
      String errorCode = XPOSPClientUtils.getCode(e);
      processErrorCode(errorCode, cupsTrmnl);
      throw e;
    }
    // 如果没有抛异常,则交易成功
    refund.setTransStatus(Const.TransStatus.SUCCESS);
  }
  @Override
  public void cashLoad(Device device, PayCashLoad cashLoad, CashLoadRequest request)
      throws TransferFailedException {
    logger.info("entryMode:" + request.getEntryMode());
    logger.info("Pinblock is not null:" + StringUtils.isNotBlank(request.getPinblock()));
    logger.info("EmvTransInfo is not null:" + StringUtils.isNotBlank(request.getEmvTransInfo()));

    // 校验数据
    if (StringUtils.isBlank(request.getCardNo())) {
      throw new TransferFailedException(AppExCode.ILLEGAL_PARAMS, "cash Load failed,cardNo null");
    }
    if (StringUtils.isBlank(request.getTrackData())) {
      throw new TransferFailedException(
          AppExCode.ILLEGAL_PARAMS, "cash Load failed,track2data or trackData null");
    }
    // 卡输入方式
    if (StringUtils.isNotBlank(request.getEntryMode())) {
      boolean isOk =
          isEntryModeOk(request.getEntryMode(), request.getPinblock(), request.getEmvTransInfo());
      if (!isOk) {
        throw new TransferFailedException(
            AppExCode.ILLEGAL_PARAMS,
            "cash PayCupsTransferChannel failed,entryMode is "
                + request.getEntryMode()
                + " but pinBlock is not null:"
                + StringUtils.isNotBlank(request.getPinblock())
                + " ,emvTransInfo is not null:"
                + StringUtils.isNotBlank(request.getEmvTransInfo()));
      }
    }
    // 获取当前设备的终端信息
    // CupsTrmnl cupsTrmnl = cupsTrmnlService.findById(device.getBindTransId());
    String trmnlNo = XpospSysProperty.getUlinkPlusQmf3TrmnlNo();
    String mrchNo = XpospSysProperty.getUlinkPlusQmf3MrchNo();
    logger.info("电子现金圈存交易 发到渠道的商户号[" + mrchNo + "],终端号[" + trmnlNo + "]");
    CupsTrmnl cupsTrmnl = cupsTrmnlService.findByTrmnlNoAndMrchNo(trmnlNo, mrchNo);
    if (cupsTrmnl == null) {
      throw new TransferFailedException(
          AppExCode.TERMINAL_NOT_EXIST, "cash Load failed,not find CupsTrmnl");
    }
    // 获取密钥信息
    DeviceKeymanage deviceKeymanage =
        deviceKeymanageService.findDeviceKeymanageByDevId(device.getDevId());
    if (deviceKeymanage == null) {
      throw new TransferFailedException(
          AppExCode.DEVICE_KEY_NOT_EXIST, "cash Load failed,not find deviceKeymanage info");
    }
    PaySignUp paySignUp =
        paySignUpService.findPaySignUpByMrchNoAndTrmnlNo(
            cupsTrmnl.getMrchNo(), cupsTrmnl.getTrmnlNo());
    if (paySignUp == null) {
      throw new TransferFailedException(
          AppExCode.TERMINAL_KEY_NOT_EXIST, "cash Load failed,not find cups signUp info");
    }
    // 密钥体系转换
    CupsKeyManage cupsKeyManage = new CupsKeyManage();
    cupsKeyManage.setDevPinKey(deviceKeymanage.getPinkey());
    cupsKeyManage.setTrmnlPinKey(paySignUp.getTrmnlPinKey());
    cupsKeyManage.setTrmnlMacKey(paySignUp.getTrmnlMacKey());
    // CUPS请求信息
    CupsRequestInfo requestInfo = new CupsRequestInfo();
    requestInfo.setPayNo(cashLoad.getCashLoadNo());
    requestInfo.setAmount(request.getAmount());
    requestInfo.setPinblock(request.getPinblock());
    requestInfo.setEmvTransInfo(request.getEmvTransInfo());
    requestInfo.setCardSeqNum(request.getCardSeqNum());
    requestInfo.setCurrency(request.getCurrency().getCodeN());
    requestInfo.setExtFld01(request.getStoreNo());
    requestInfo.setOrderNo(request.getOrderNo());
    try {
      TrackContext trackContext =
          getTrackData(deviceKeymanage.getDatakey(), request.getTrackData());

      requestInfo.setCardNo(trackContext.getTrack2Data().split("=")[0]);
      requestInfo.setTrack2Data(trackContext.getTrack2Data());
      requestInfo.setTrack3Data(trackContext.getTrack3Data());
    } catch (HSMException e) {
      String hsmRespCode = XPOSPClientUtils.getCode(e);
      if (!AppExCode.UNKNOWN.equals(hsmRespCode)) {
        hsmRespCode = Const.TP_BEGIN_HSM + hsmRespCode;
      }
      throw new TransferFailedException(
          hsmRespCode,
          "cash Load failed, when descrypt track data form hsm error code[" + hsmRespCode + "]");
    }

    CupsResponseInfo responseInfo = null;
    try {
      // 构建发起金融交易
      responseInfo = cashLoadProcess.process(cupsTrmnl, cupsKeyManage, requestInfo);
    } catch (TransferFailedException e) {
      String errorCode = XPOSPClientUtils.getCode(e);
      processErrorCode(errorCode, cupsTrmnl);
      throw e;
    }

    // 如果没有抛异常,则交易成功
    cashLoad.setTransStatus(Const.TransStatus.SUCCESS);
    cashLoad.setTransCode(responseInfo.getTransCode());
    cashLoad.setEmvTransInfo(responseInfo.getEmvTransInfo());
  }
  @Override
  public void cashPay(final Device device, final Payment payment, final PaymentRequest request)
      throws TransferFailedException {
    logger.info("entryMode:" + request.getEntryMode());
    logger.info("EmvTransInfo is not null :" + StringUtils.isNotBlank(request.getEmvTransInfo()));

    // 校验数据
    if (StringUtils.isBlank(request.getCardNo())) {
      throw new TransferFailedException(AppExCode.ILLEGAL_PARAMS, "pay failed ,cardNo null");
    }
    // 卡输入方式
    //		if(StringUtils.isNotBlank(request.getEntryMode())){
    //			boolean isOk=isEntryModeOk(request.getEntryMode(),request.getPinblock(),
    // request.getEmvTransInfo());
    //		   if(!isOk){
    //			   throw new TransferFailedException(AppExCode.ILLEGAL_PARAMS, "pay failed,entryMode is
    // "+request.getEntryMode()+" but pinBlock is not
    // null:"+StringUtils.isNotBlank(request.getPinblock())+" ,emvTransInfo is not
    // null:"+StringUtils.isNotBlank(request.getEmvTransInfo()));
    //		   }
    //		}
    // 非接交易时候,55域的tag“9F74”必须出现
    if (StringUtils.isBlank(request.getEmvTransInfo())) {
      throw new TransferFailedException(
          AppExCode.ILLEGAL_PARAMS, "pay failed,emvTransInfo is" + request.getEmvTransInfo());
    }

    // 获取当前设备的终端信息
    CupsTrmnl cupsTrmnl = cupsTrmnlService.findById(device.getBindTransId());
    if (cupsTrmnl == null) {
      throw new TransferFailedException(
          AppExCode.TERMINAL_NOT_EXIST, "pay failed,not find CupsTrmnl");
    }
    // 获取密钥信息
    DeviceKeymanage deviceKeymanage =
        deviceKeymanageService.findDeviceKeymanageByDevId(device.getDevId());
    if (deviceKeymanage == null) {
      throw new TransferFailedException(
          AppExCode.DEVICE_KEY_NOT_EXIST, "pay failed,not find deviceKeymanage info");
    }

    PaySignUp paySignUp =
        paySignUpService.findPaySignUpByMrchNoAndTrmnlNo(
            cupsTrmnl.getMrchNo(), cupsTrmnl.getTrmnlNo());
    if (paySignUp == null) {
      throw new TransferFailedException(
          AppExCode.TERMINAL_KEY_NOT_EXIST, "pay failed,not find cups signUp info");
    }

    // 当定时签到失败的时候,需要重新发起到银联签到
    // 密钥体系转换
    CupsKeyManage cupsKeyManage = new CupsKeyManage();
    cupsKeyManage.setDevPinKey(deviceKeymanage.getPinkey());
    cupsKeyManage.setTrmnlPinKey(paySignUp.getTrmnlPinKey());
    cupsKeyManage.setTrmnlMacKey(paySignUp.getTrmnlMacKey());
    // CUPS请求信息
    CupsRequestInfo requestInfo = new CupsRequestInfo();
    requestInfo.setPayNo(payment.getPayNo());
    requestInfo.setAmount(request.getAmount());
    requestInfo.setPinblock(request.getPinblock());
    requestInfo.setEmvTransInfo(request.getEmvTransInfo());
    requestInfo.setCardSeqNum(request.getCardSeqNum());
    requestInfo.setEntryMode(request.getEntryMode());
    requestInfo.setCurrency(request.getCurrency().getCodeN());
    requestInfo.setExtFld01(request.getStoreNo());
    requestInfo.setCardNo(request.getCardNo());
    requestInfo.setCardExpiryDay(request.getCardExpire());
    requestInfo.setOrderNo(request.getOrderNo());
    requestInfo.setIcScript(request.getIcScript());
    CupsResponseInfo responseInfo = null;
    try {
      responseInfo = cashConsumeProcess.process(cupsTrmnl, cupsKeyManage, requestInfo);
    } catch (TransferFailedException e) {
      String errorCode = XPOSPClientUtils.getCode(e);
      processErrorCode(errorCode, cupsTrmnl);
      throw e;
    }
    // 如果没有抛异常,则交易成功
    payment.setTransStatus(Const.TransStatus.SUCCESS);
    payment.setTransCode(responseInfo.getTransCode());
    payment.setEmvTransInfo(responseInfo.getEmvTransInfo());
  }
  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;
  }