package com.xzx.gc.pay.service; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.date.DateUtil; import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult; import com.github.binarywang.wxpay.service.WxPayService; import com.xzx.gc.common.Result; import com.xzx.gc.common.constant.Constants; import com.xzx.gc.common.constant.PayEnum; import com.xzx.gc.common.dto.log.PayInfoLog; import com.xzx.gc.common.exception.wx.WxPayNotifyResponseException; import com.xzx.gc.common.utils.BusinessUtil; import com.xzx.gc.common.utils.ExceptionUtils; import com.xzx.gc.common.utils.RedisUtil; import com.xzx.gc.common.utils.wxpay.WXPayUtil; import com.xzx.gc.entity.AccountInfo; import com.xzx.gc.entity.PayInfo; import com.xzx.gc.entity.PayWxRecord; import com.xzx.gc.pay.dto.PayParamDTO; import com.xzx.gc.pay.dto.PayResultDTO; import com.xzx.gc.pay.mapper.PayInfoMapper; import com.xzx.gc.pay.mapper.PayWxRecordMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; @Service @Transactional @Slf4j public class WeiXinService { @Autowired private WxPayService wxPayService; @Autowired private PayService payService; @Autowired private PayInfoMapper payInfoMapper; @Autowired private HttpServletRequest request; @Autowired private RedisUtil redisUtil; @Autowired private PayWxRecordMapper payWxRecordMapper; @Autowired private PayInfoLogService payInfoLogService; @Autowired private BusinessUtil businessUtil; @Autowired private AccountService accountService; /** * 生成小程序支付签名 * @param payResultDTO * @return * @throws Exception */ private String geWebSign(PayResultDTO payResultDTO) throws Exception { Map packageParams = new HashMap(); packageParams.put("appId", wxPayService.getConfig().getAppId()); packageParams.put("timeStamp", payResultDTO.getTimeStamp()); packageParams.put("nonceStr", payResultDTO.getNonce()); packageParams.put("package", payResultDTO.getPrepayId()); packageParams.put("signType", "MD5"); String packageSign = WXPayUtil.generateSignature(packageParams, wxPayService.getConfig().getMchKey()); return packageSign; } /** * 生成安卓APP签名 * @param payResultDTO * @return * @throws Exception */ private String geAnroidSign(PayResultDTO payResultDTO) throws Exception { Map packageParams = new HashMap(); packageParams.put("appid", wxPayService.getConfig().getAppId()); packageParams.put("partnerid", wxPayService.getConfig().getMchId()); packageParams.put("prepayid", payResultDTO.getPrepayId()); packageParams.put("package", payResultDTO.getExtra()); packageParams.put("noncestr", payResultDTO.getNonce()); packageParams.put("timestamp", payResultDTO.getTimeStamp()); String packageSign = WXPayUtil.generateSignature(packageParams, wxPayService.getConfig().getMchKey()); return packageSign; } /** * 微信预支付 * * @param wxPayUnifiedOrderRequest * @param payParamDTO * @return */ public Result pay(WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest, PayParamDTO payParamDTO) { Result res=new Result<>(); PayResultDTO payResultDTO = new PayResultDTO(); try { String userId = request.getHeader("userId"); WxPayUnifiedOrderResult result = wxPayService.unifiedOrder(wxPayUnifiedOrderRequest); PayInfo payInfo = new PayInfo(); payInfo.setOrderId(result.getPrepayId()); payInfo.setCreateUserId(userId); if(businessUtil.isApp(request.getHeader("clientType"))){ //需要服务费 payInfo.setMoney(businessUtil.changeMoney(payParamDTO.getMoney())); payInfo.setFee(businessUtil.changeMoney(payParamDTO.getFee())); }else { payInfo.setMoney(payParamDTO.getTotalFee().toString()); } AccountInfo accountInfo1 =accountService.findByUserId(userId); if (accountInfo1 == null) { return Result.error(-1, "账户不存在"); } payInfo.setAccountId(accountInfo1.getAccountId()); payInfo.setPayType(PayEnum.待支付.getValue()); payInfo.setOpenId(payParamDTO.getOpenid()); payInfo.setStatus(PayEnum.充值.getValue()); payInfo.setPayOrderId(payParamDTO.getOutTradeNo()); payService.addPay(payInfo); PayInfoLog payInfoLog=new PayInfoLog(); BeanUtil.copyProperties(payInfo,payInfoLog); payInfoLog.setAccount(accountInfo1.getAccountName()); payInfoLog.setAccountClass(PayEnum.微信.getValue()); payInfoLog.setPayType(PayEnum.充值交易.getValue()); payInfoLogService.add(payInfoLog); payResultDTO.setNonce(payParamDTO.getNonceStr()); payResultDTO.setTimeStamp(Convert.toStr(DateUtil.currentSeconds())); payResultDTO.setMchId(wxPayService.getConfig().getMchId()); if(businessUtil.isWeb(payParamDTO.getClientType())){ payResultDTO.setPrepayId("prepay_id="+result.getPrepayId()); payResultDTO.setSign(geWebSign(payResultDTO)); }else if(businessUtil.isApp(payParamDTO.getClientType())){ payResultDTO.setPrepayId(result.getPrepayId()); payResultDTO.setExtra("Sign=WXPay"); payResultDTO.setSign(geAnroidSign(payResultDTO)); } payResultDTO.setAppId(wxPayService.getConfig().getAppId()); payResultDTO.setPayOrderId(payInfo.getPayOrderId()); res.setData(payResultDTO); return res; } catch (Exception e) { ExceptionUtils.err("微信预支付失败",e); } return res; } /** * 微信回调 * */ public String payBack(String xmlResult) { String payOrderId=""; boolean lock=false; try { //记录微信回调日志 record(xmlResult); WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(xmlResult); payOrderId = result.getOutTradeNo(); // 锁+去重 if(redisUtil.setnx(Constants.REDIS_PAY_KEY+"wx:payback:"+payOrderId,payOrderId)) { lock=true; PayInfo payInfo = payInfoMapper.selectByPrimaryKey(payOrderId); if (payInfo != null) { if (payInfo.getStatus().equals(PayEnum.已支付.getValue())) { return WxPayNotifyResponse.success("处理成功!"); }else{ Map map = new HashMap(); map.put("userId", payInfo.getCreateUserId()); map.put("money", payInfo.getMoney()); map.put("status", PayEnum.已支付.getValue()); map.put("payOrderId", payInfo.getPayOrderId()); map.put("fee",payInfo.getFee()); payService.webChatRechargeCallback(map); } } } return WxPayNotifyResponse.success("处理成功!"); } catch (Exception e) { log.error("微信回调失败,订单:"+payOrderId, e); throw new WxPayNotifyResponseException(WxPayNotifyResponse.fail(e.getMessage())); }finally { if(lock) { redisUtil.del(Constants.REDIS_PAY_KEY+"wx:payback:"+payOrderId); } } } private void record(String xmlResult){ WxPayOrderNotifyResult res= WxPayOrderNotifyResult.fromXML(xmlResult); PayWxRecord payWxRecord=new PayWxRecord(); BeanUtils.copyProperties(res,payWxRecord); payWxRecord.setCreateTime(DateUtil.now()); payWxRecordMapper.insertSelective(payWxRecord); } // @Scheduled(cron = "${wx.pay.cron}") // @Async // public void syncPay(){ // log.trace("********定时修复支付订单开始【每1分钟执行1次】*********"); // Example example=new Example(PayInfo.class); // Example.Criteria criteria = example.createCriteria(); // criteria.andEqualTo("payType",PayEnum.充值.getValue()); // criteria.andEqualTo("status",PayEnum.待支付.getValue()); // criteria.andCondition("IFNULL(check_num,0)<2"); // criteria.andCondition("to_days(create_time) = to_days(now())"); // List payInfos = payInfoMapper.selectByExample(example); // // if(CollUtil.isNotEmpty(payInfos)){ // for (PayInfo payInfo : payInfos) { // String createTime = payInfo.getCreateTime(); // String date=DateUtil.now(); // long between = DateUtil.between(DateUtil.parse(createTime,DateUtils.DATE_FORMAT_YMDHMS), DateUtil.parse(date,DateUtils.DATE_FORMAT_YMDHMS), DateUnit.MINUTE); // //3分钟后进行查询 // if(between<3){ // continue; // } // String payOrderId = payInfo.getPayOrderId(); // Integer checkNum = payInfo.getCheckNum(); // if(checkNum==null){ // checkNum=0; // } // WxPayOrderQueryResult wxPayOrderQueryResult = null; // boolean lock=false; // try { // wxPayOrderQueryResult = wxPayService.queryOrder(null, payOrderId); // String returnCode = wxPayOrderQueryResult.getReturnCode(); // String resultCode = wxPayOrderQueryResult.getResultCode(); // if("SUCCESS".equals(returnCode)&&"SUCCESS".equals(resultCode)){ // //SUCCESS—支付成功,REFUND—转入退款,NOTPAY—未支付,CLOSED—已关闭,REVOKED—已撤销(刷卡支付),USERPAYING--用户支付中,PAYERROR--支付失败(其他原因,如银行返回失败) // String tradeState = wxPayOrderQueryResult.getTradeState(); // log.trace("充值交易流水号:{},交易状态:{}",payOrderId,tradeState); // if("SUCCESS".equals(tradeState)){ // // 锁+去重 // if(redisUtil.setnx(Constants.REDIS_PAY_KEY+"wx:payback:"+payOrderId,payOrderId)) { // lock=true; // PayInfo payInfo2 = payInfoMapper.selectByPrimaryKey(payOrderId); // if (payInfo2 != null) { // if (payInfo2.getStatus().equals(PayEnum.已支付.getValue())) { // continue; // }else{ // Map map = new HashMap(); // map.put("userId", payInfo2.getCreateUserId()); // map.put("money", payInfo2.getMoney()); // map.put("status", PayEnum.已支付.getValue()); // map.put("payOrderId", payInfo2.getPayOrderId()); // map.put("fee", payInfo2.getFee()); // payService.webChatRechargeCallback(map); // log.info("支付订单:{}已自动修复成功",payOrderId); // } // } // } // }else{ // PayInfo payInfo2=new PayInfo(); // payInfo2.setPayOrderId(payInfo.getPayOrderId()); // checkNum=2; // payInfo2.setCheckNum(checkNum); // payInfoMapper.updateByPrimaryKeySelective(payInfo2); // } // } // } catch (WxPayException e) { // log.warn("主动调用微信支付查询出现异常"); // PayInfo payInfo2=new PayInfo(); // payInfo2.setPayOrderId(payInfo.getPayOrderId()); // checkNum=2; // payInfo2.setCheckNum(checkNum); // payInfoMapper.updateByPrimaryKeySelective(payInfo2); // }finally { // if(lock) { // redisUtil.del(Constants.REDIS_PAY_KEY+"wx:payback:"+payOrderId); // } // } // } // } // log.trace("********定时修复支付订单完成【每3分钟执行1次】*********"); // // } /** * 修复支付 * @param payOrderId */ public Result payFix(String payOrderId) { PayInfo payInfo2 = payInfoMapper.selectByPrimaryKey(payOrderId); if (payInfo2 != null) { if (payInfo2.getStatus().equals(PayEnum.已支付.getValue())) { return Result.error("当前支付订单已支付成功"); }else{ Map map = new HashMap(); map.put("userId", payInfo2.getCreateUserId()); map.put("money", payInfo2.getMoney()); map.put("status", PayEnum.已支付.getValue()); map.put("payOrderId", payInfo2.getPayOrderId()); map.put("fee", payInfo2.getFee()); payService.webChatRechargeCallback(map); return Result.success(); } } return Result.error("当前支付订单号不存在"); } }