| | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | |
| | | import com.nq.vo.pay.PayOutMD5Util; |
| | | import com.nq.vo.pay.PayoutCallbackData; |
| | | import com.nq.vo.pay.PayoutCallbackRequest; |
| | | import net.sf.json.JSON; |
| | | import net.sf.json.JSONObject; |
| | | import okhttp3.*; |
| | |
| | | if(type == 0){//支付1 |
| | | return getPaymentZero(tradeAmount, uipReqRul, user,request); |
| | | }else if(type == 2){//支付2 |
| | | return getPaymentZero(tradeAmount, uipReqRul, user,request); |
| | | return getPaymentOne(tradeAmount, reqUrl,user,request); |
| | | } else if(type == 3){//支付2 |
| | | return getPaymentTwo(tradeAmount, uipReqRul, user,request); |
| | | }else if(type == 1){ |
| | |
| | | dataObj.put("customerEmail","123456@qq.com");//需替换 |
| | | dataObj.put("customerPhone",user.getPhone());//需替换 |
| | | dataObj.put("merchantOrderNo",generatePayOrderId());//自定义订单号 |
| | | dataObj.put("notifyUrl", "https://api.durocapital.lat/user/rechargeCallbackZero.do");//回调通知地址 |
| | | dataObj.put("notifyUrl", "https://api.greenbackcaps.top/user/rechargeCallbackZero.do");//回调通知地址 |
| | | JSONObject requestObj = new JSONObject(); |
| | | log.info("代收参数:{}", dataObj); |
| | | // 加密数据 |
| | | byte[] encryptedData = encrypt(dataObj.toString(), aesKey, aesIv); |
| | | String base64EncodedData = Base64.getEncoder().encodeToString(encryptedData); |
| | |
| | | Headers headers = new Headers.Builder().add("merchant_key", merchantKey).build();//merchant_key需替换 |
| | | //请求 |
| | | String resp = doPost(url, requestObj.toString(), headers); |
| | | log.info("代收返回:"+resp); |
| | | Gson gson = new Gson(); |
| | | PaymentResponseZero paymentResponse = gson.fromJson(resp, PaymentResponseZero.class); |
| | | if(paymentResponse.getCode() != 0 && !paymentResponse.getMsg().equals("success")){ |
| | |
| | | params.put("merchant_order_id", merchantOrderId); |
| | | params.put("amount", amount.toString()); |
| | | params.put("pay_channel", payChannel); |
| | | params.put("notify_url", "https://api.durocapital.lat/user/rechargeCallbackThree.do"); // 异步通知地址 |
| | | params.put("page_return_url", "https://stock.durocapital.lat/#/user"); // 前端返回地址 |
| | | params.put("notify_url", "https://api.greenbackcaps.top/user/rechargeCallbackThree.do"); // 异步通知地址 |
| | | params.put("page_return_url", "https://stock.greenbackcaps.top/#/user"); // 前端返回地址 |
| | | |
| | | // 可选参数 |
| | | if (user != null) { |
| | |
| | | // 保留两位小数,四舍五入 |
| | | amount = amount.setScale(2, BigDecimal.ROUND_HALF_UP); |
| | | params.put("total_fee", String.valueOf(amount)); // 交易金额(保留两位小数) |
| | | params.put("notify_url", "https://api.durocapital.lat/user/rechargeCallbackTwo.do"); // 异步通知地址 |
| | | params.put("notify_url", "https://api.greenbackcaps.top/user/rechargeCallbackTwo.do"); // 异步通知地址 |
| | | params.put("reply_type", "URL"); // 执行方式 |
| | | params.put("timestamp", String.valueOf(System.currentTimeMillis())); // 时间戳 |
| | | params.put("customer_name", StringUtils.isEmpty(UserNameUtil.formatCustomerName(user.getNickName())) ? "IsNotSet" : UserNameUtil.formatCustomerName(user.getNickName())); // 客户姓名 |
| | |
| | | //商家订单号 保证每笔订单唯一 |
| | | params.put("mch_order_no", generatePayOrderId()); |
| | | //异步通知地址 不超过 200 字节,支付成功后发起,不能携带参数 |
| | | params.put("notify_url", "https://api.durocapital.lat/user/rechargeCallback.do"); |
| | | params.put("notify_url", "https://api.greenbackcaps.top/user/rechargeCallback.do"); |
| | | // 订单时间 时间格式yyyy-MM-dd HH:mm:ss |
| | | params.put("order_date", getOrderTime()); |
| | | //支付类型 请查阅商户后台通道编码 |
| | |
| | | transferResponseService.updateById(transferResponse); |
| | | |
| | | userWithdraw.setWithStatus(2); // 失败 |
| | | userWithdraw.setWithMsg("代付失败:" + vo.getMsg()); |
| | | userWithdraw.setWithMsg("Withdrawal failed:" + vo.getMsg()); |
| | | userWithdraw.setTransTime(new Date()); |
| | | userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw); |
| | | |
| | |
| | | pw.close(); |
| | | } |
| | | } |
| | | |
| | | public Map<String, Object> payoutCallbackTwo(PayoutCallbackRequest request, HttpServletResponse response) { |
| | | |
| | | |
| | | String merchantKey = "qqaC1DH/LeR9iPvm";//商户key 需替换 |
| | | String aesKey = "ge6vK40fHNZPFJ4p";//商户aesKey 需替换 |
| | | |
| | | Map<String, Object> result = new HashMap<>(); |
| | | result.put("code", 200); // 固定返回 200 |
| | | |
| | | try { |
| | | PayoutCallbackData data = request.getData(); |
| | | String signature = request.getSignature_n(); |
| | | |
| | | // 1. 签名验证 |
| | | String signStr = merchantKey |
| | | + nullToEmpty(data.getMessage()) |
| | | + nullToEmpty(data.getAmount()) |
| | | + nullToEmpty(data.getStatus()) |
| | | + nullToEmpty(data.getMerchantOrderNo()) |
| | | + nullToEmpty(data.getOrderNo()) |
| | | + aesKey; |
| | | |
| | | String calculatedSign = PayOutMD5Util.md5(signStr).toLowerCase(); |
| | | |
| | | if (!calculatedSign.equals(signature)) { |
| | | log.error("代付回调签名验证失败,merchantOrderNo={},本地签名={},回调签名={}", |
| | | data.getMerchantOrderNo(), calculatedSign, signature); |
| | | // 签名失败不处理业务,但依旧返回 200 |
| | | return result; |
| | | } |
| | | |
| | | // 2. 查询本地代付记录 |
| | | TransferResponse transfer = transferResponseService.getOne( |
| | | new LambdaQueryWrapper<TransferResponse>() |
| | | .eq(TransferResponse::getMerTransferId, data.getMerchantOrderNo()) |
| | | .last("limit 1") |
| | | ); |
| | | |
| | | if (transfer == null) { |
| | | log.error("代付回调未找到对应记录,merchantOrderNo={}", data.getMerchantOrderNo()); |
| | | return result; |
| | | } |
| | | |
| | | // 3. 防止重复回调 |
| | | if (transfer.getCallbackState() != 0) { |
| | | log.info("代付回调已处理过,merchantOrderNo={},状态={}", data.getMerchantOrderNo(), transfer.getCallbackState()); |
| | | return result; |
| | | } |
| | | |
| | | // 4. 查询提现记录 |
| | | UserWithdraw withdraw = userWithdrawMapper.selectByPrimaryKey(transfer.getWithId()); |
| | | if (withdraw == null) { |
| | | log.error("代付回调未找到提现记录,withId={}", transfer.getWithId()); |
| | | return result; |
| | | } |
| | | |
| | | // 5. 根据状态处理 |
| | | String status = data.getStatus(); |
| | | if ("SUCCESS".equals(status)) { |
| | | handleSuccess(transfer, withdraw, data, signature); |
| | | } else if ("FAILURE".equals(status)) { |
| | | handleFailure(transfer, withdraw, data, signature); |
| | | } else { |
| | | log.info("代付回调未知状态:{},暂不处理,merchantOrderNo={}", status, data.getMerchantOrderNo()); |
| | | } |
| | | |
| | | } catch (Exception e) { |
| | | log.error("代付回调处理异常", e); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 处理成功回调 |
| | | */ |
| | | private void handleSuccess(TransferResponse transfer, UserWithdraw withdraw, |
| | | PayoutCallbackData data, String signature) { |
| | | // 更新代付记录 |
| | | transfer.setTradeResult(1); // 成功 |
| | | transfer.setCallbackState(1); // 已处理成功 |
| | | transfer.setRespCode("SUCCESS"); |
| | | transfer.setSignType("MD5"); |
| | | transfer.setSign(signature); |
| | | transfer.setUpdatedAt(new Date()); |
| | | transferResponseService.updateById(transfer); |
| | | |
| | | // 更新提现记录 |
| | | withdraw.setWithStatus(1); // 成功 |
| | | withdraw.setWithMsg("代付成功"); |
| | | withdraw.setTransTime(new Date()); |
| | | userWithdrawMapper.updateByPrimaryKeySelective(withdraw); |
| | | |
| | | // 扣除冻结资金(提现时已冻结,此处只需将冻结减少,可用余额不变) |
| | | UserAssets assets = iUserAssetsServices.assetsByTypeAndUserId("IN", withdraw.getUserId()); |
| | | if (assets != null) { |
| | | assets.setFreezeMoney(assets.getFreezeMoney().subtract(withdraw.getWithAmt())); |
| | | userAssetsMapper.updateById(assets); |
| | | } |
| | | |
| | | log.info("代付成功处理完成,商户订单号={},平台订单号={}", data.getMerchantOrderNo(), data.getOrderNo()); |
| | | } |
| | | |
| | | /** |
| | | * 处理失败回调 |
| | | */ |
| | | private void handleFailure(TransferResponse transfer, UserWithdraw withdraw, |
| | | PayoutCallbackData data, String signature) { |
| | | // 更新代付记录 |
| | | transfer.setTradeResult(2); // 失败 |
| | | transfer.setCallbackState(2); // 已处理失败 |
| | | transfer.setRespCode("FAIL"); |
| | | transfer.setErrorMsg(data.getMessage()); |
| | | transfer.setSignType("MD5"); |
| | | transfer.setSign(signature); |
| | | transfer.setUpdatedAt(new Date()); |
| | | transferResponseService.updateById(transfer); |
| | | |
| | | // 更新提现记录 |
| | | withdraw.setWithStatus(2); // 失败 |
| | | withdraw.setWithMsg("Withdrawal failed:" + data.getMessage()); |
| | | withdraw.setTransTime(new Date()); |
| | | userWithdrawMapper.updateByPrimaryKeySelective(withdraw); |
| | | |
| | | // 返还资金:解冻并增加可用余额 |
| | | UserAssets assets = iUserAssetsServices.assetsByTypeAndUserId("IN", withdraw.getUserId()); |
| | | if (assets != null) { |
| | | assets.setAvailableBalance(assets.getAvailableBalance().add(withdraw.getWithAmt())); |
| | | assets.setFreezeMoney(assets.getFreezeMoney().subtract(withdraw.getWithAmt())); |
| | | userAssetsMapper.updateById(assets); |
| | | } |
| | | |
| | | log.info("代付失败处理完成,商户订单号={},平台订单号={},失败原因={}", |
| | | data.getMerchantOrderNo(), data.getOrderNo(), data.getMessage()); |
| | | } |
| | | |
| | | /** |
| | | * 将 null 转为空字符串,防止拼接 NPE |
| | | */ |
| | | private String nullToEmpty(String str) { |
| | | return str == null ? "" : str; |
| | | } |
| | | } |