WechatPayService.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. package com.dk.oauth.service.wxapi.basic;
  2. import com.alibaba.fastjson.JSON;
  3. import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
  4. import com.dk.common.exception.BaseBusinessException;
  5. import com.dk.common.infrastructure.constant.Constant;
  6. import com.dk.common.infrastructure.enums.ErrorCodeEnum;
  7. import com.dk.common.infrastructure.xxl.XxlJobUtils;
  8. import com.dk.common.model.response.mst.StaffResponse;
  9. import com.dk.common.response.ResponseCodeEnum;
  10. import com.dk.common.response.ResponseResultUtil;
  11. import com.dk.common.response.ResponseResultVO;
  12. import com.dk.common.util.*;
  13. import com.dk.oauth.config.WechatPayConfigInfo;
  14. import com.dk.oauth.entity.Company;
  15. import com.dk.oauth.entity.Trade;
  16. import com.dk.oauth.entity.TradeResponse;
  17. import com.dk.oauth.entity.UserLogin;
  18. import com.dk.oauth.feign.service.StaffFeign;
  19. import com.dk.oauth.mapper.CompanyMapper;
  20. import com.dk.oauth.mapper.TradeMapper;
  21. import com.dk.oauth.mapper.UserMapper;
  22. import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
  23. import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
  24. import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
  25. import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
  26. import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
  27. import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
  28. import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result;
  29. import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
  30. import com.github.binarywang.wxpay.config.WxPayConfig;
  31. import com.github.binarywang.wxpay.exception.WxPayException;
  32. import com.github.binarywang.wxpay.service.WxPayService;
  33. import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
  34. import com.xxl.job.core.context.XxlJobHelper;
  35. import com.xxl.job.core.handler.annotation.XxlJob;
  36. import lombok.extern.slf4j.Slf4j;
  37. import org.springframework.beans.factory.annotation.Autowired;
  38. import org.springframework.core.io.ClassPathResource;
  39. import org.springframework.stereotype.Service;
  40. import org.springframework.transaction.annotation.Transactional;
  41. import javax.annotation.Resource;
  42. import java.math.BigDecimal;
  43. import java.math.RoundingMode;
  44. import java.time.LocalDate;
  45. import java.time.LocalDateTime;
  46. import java.time.ZoneOffset;
  47. import java.time.format.DateTimeFormatter;
  48. import java.util.Date;
  49. import java.util.HashMap;
  50. import java.util.List;
  51. import java.util.Map;
  52. /**
  53. * 微信支付服务
  54. * 后台管理设置的金额 从dkic_ms里取数据 金额
  55. * 所以放到了 权限的oauth-server 的服务里240327
  56. *
  57. * @author 姜永辉
  58. * @since 20223-07-01 09:41:05
  59. */
  60. @Service("wechatPayService")
  61. @Slf4j
  62. public class WechatPayService {
  63. @Autowired
  64. private WechatPayConfigInfo wechatPayConfigInfo;
  65. @Autowired
  66. private TradeMapper tradeMapper;
  67. @Autowired
  68. private UserMapper userMapper;
  69. @Autowired
  70. private CompanyMapper companyMapper;
  71. @Autowired
  72. private XxlJobUtils xxlJobUtils;
  73. @Resource
  74. StaffFeign staffFeign;
  75. /**
  76. * 商户 下单选取旗舰版或专业版的订单
  77. *
  78. * @param param
  79. * @return
  80. * @throws WxPayException
  81. */
  82. public ResponseResultVO unifiedOrder(Map<String, Object> param) throws WxPayException {
  83. String paymentSn = param.get("paymentSn").toString();
  84. String openId = param.get("openId").toString();
  85. String payFee = param.get("payFee").toString();
  86. log.info("下单选取旗舰版或专业版的订单1----------" + param.toString());
  87. try {
  88. // 获取单据的金额 --后台管理设置的金额 从dkic_ms里取数据 金额
  89. // 所以放到了 权限的oauth-server 的服务里
  90. // todo。。。。。。。。。。。。
  91. payFee = "0.01";
  92. WxPayService wxPayService = this.getWxPayService();
  93. WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
  94. orderRequest.setBody("商品测试");
  95. orderRequest.setOutTradeNo(paymentSn);
  96. orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(payFee.toString()));//元转成分
  97. orderRequest.setOpenid(openId);
  98. orderRequest.setSpbillCreateIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
  99. orderRequest.setNotifyUrl(wechatPayConfigInfo.getWechatNotifyUrl() + "/" + wechatPayConfigInfo.getAppId());
  100. orderRequest.setTradeType("JSAPI");
  101. // 生成预支付订单
  102. WxPayUnifiedOrderResult wxPayUnifiedOrderResult = wxPayService.unifiedOrder(orderRequest);
  103. String prepay_id = wxPayUnifiedOrderResult.getPrepayId();
  104. String timeStamp = new Date().getTime() + "";
  105. String nonceStr = UUID.fastUUID().toString(true);
  106. String pack = "prepay_id=" + prepay_id;
  107. String signType = "MD5";
  108. String paySign = "";
  109. String sigmTemp = "appId=" + wxPayUnifiedOrderResult.getAppid() + "&nonceStr=" + nonceStr + "&package="
  110. + pack + "&signType=" + signType + "&timeStamp=" + timeStamp;
  111. sigmTemp = sigmTemp + "&key=" + wechatPayConfigInfo.getMchKey();
  112. paySign = Md5Utils.hash(sigmTemp);
  113. log.info("下单选取旗舰版或专业版的订单2----------" + prepay_id + "--" + sigmTemp + "--");
  114. Map<String, Object> params = new HashMap<String, Object>();
  115. params.put("appId", wxPayUnifiedOrderResult.getAppid());
  116. params.put("timeStamp", timeStamp);
  117. params.put("nonceStr", nonceStr);
  118. params.put("pack", pack);
  119. params.put("signType", signType);
  120. params.put("paySign", paySign);
  121. log.info("下单选取旗舰版或专业版的订单3----------" + params.toString());
  122. return ResponseResultUtil.success(params);
  123. } catch (Exception e) {
  124. log.error("unifiedOrder--微信支付失败!支付单号:{},原因:{}", paymentSn, e.getMessage());
  125. return ResponseResultUtil.error("支付失败,请稍后重试!");
  126. }
  127. }
  128. /**
  129. * @desc : 处理支付成功逻辑
  130. * @author : 姜永辉
  131. * @date : 2024/03/06 11:29
  132. */
  133. @Transactional(
  134. rollbackFor = {Exception.class}
  135. )
  136. public ResponseResultVO notifyWechatPay(WxPayOrderNotifyResult info) {
  137. log.info("处理支付成功逻辑----------" + info.getOutTradeNo() + "---------" + info.toString());
  138. UserLogin byWxid = userMapper.getByWxid(info.getOpenid());
  139. log.info("微信用户----------" + byWxid);
  140. // 获取交易记录
  141. TradeResponse tradeResponse = tradeMapper.selectTradeByNo(new Trade().setTradeNo(info.getOutTradeNo()));
  142. if (tradeResponse == null) {
  143. throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(),
  144. ErrorCodeEnum.NO_FIND_TRADE.getMessage());
  145. }
  146. // 更新交易记录状态
  147. Trade trade = new Trade();
  148. trade.setTradeId(tradeResponse.getTradeId());
  149. trade.setWxTradeNo(info.getTransactionId());
  150. trade.setTradeStatus(Constant.TradeStatus.EFFECTIVE.getName());
  151. tradeMapper.updateById(trade);
  152. // 交易类型-续费- 将该公司的 生成一个job的任务
  153. if (Constant.TradeType.RENEW.getName().equals(trade.getTradeType())) {
  154. log.error("交易类型-续费插入任务数据-getTradeType:" + trade.getTradeType());
  155. try {
  156. Company company = companyMapper.selectById(tradeResponse.getCpId());
  157. // 解析license信息
  158. String licenseStr = AESUtil.desEncrypt(company.getLicenseSocial());
  159. log.error("交易类型-续费插入任务数据-licenseStr:" + licenseStr);
  160. if (licenseStr != null) {
  161. Map<String, Object> licenseMap = JSON.parseObject(licenseStr, Map.class);
  162. log.error("交易类型-续费插入任务数据-re_new:" + licenseMap.get("re_new"));
  163. if (licenseMap.get("re_new") != null) {
  164. String d = licenseMap.get("user_end_date") + "";
  165. LocalDateTime localDateTime = LocalDateTime.parse(d, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
  166. int id = xxlJobUtils.create(Math.toIntExact(
  167. (localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli() - System.currentTimeMillis()) / 1000
  168. ), tradeResponse.getCpId() + "", Constant.XxlJobInfo.RENEW.getValue());
  169. log.error("交易类型-续费插入任务数据-:" + id);
  170. }
  171. }
  172. } catch (Exception e) {
  173. log.error("交易类型-续费插入任务数据-异常:" + e.getStackTrace());
  174. }
  175. }
  176. // 更新企业,把临时license更新到license中
  177. log.info("交易记录----------" + trade);
  178. // 企业
  179. Company comp = new Company();
  180. comp.setCpId(tradeResponse.getCpId());
  181. companyMapper.updateCompanyLicense(comp);
  182. log.info("交易记录-企业更新----------" + comp);
  183. return ResponseResultUtil.success();
  184. }
  185. /**
  186. * @desc : 获取商户配置信息
  187. * @author : 姜永辉
  188. * @date : 2023-08-02 17:30
  189. */
  190. public WxPayService getWxPayService() {
  191. log.info("getWxPayService----------" + wechatPayConfigInfo.toString());
  192. WxPayConfig payConfig = new WxPayConfig();
  193. payConfig.setAppId(StringUtils.trimToNull(wechatPayConfigInfo.getAppId()));
  194. payConfig.setMchId(StringUtils.trimToNull(wechatPayConfigInfo.getMchId()));
  195. payConfig.setMchKey(StringUtils.trimToNull(wechatPayConfigInfo.getMchKey()));
  196. // payConfig.setSubAppId(null);
  197. // payConfig.setSubMchId(null);
  198. ClassPathResource classPathResource = new ClassPathResource("apiclient_cert.p12");
  199. payConfig.setKeyPath(StringUtils.trimToNull(classPathResource.getPath()));
  200. log.info("getWxPayService=>" + classPathResource.toString());
  201. // payConfig.setKeyPath(StringUtils.trimToNull(wechatPayConfigInfo.getKeyPath()));
  202. // 可以指定是否使用沙箱环境
  203. payConfig.setUseSandboxEnv(false);
  204. WxPayService wxPayService = new WxPayServiceImpl();
  205. wxPayService.setConfig(payConfig);
  206. return wxPayService;
  207. }
  208. /**
  209. * 退款
  210. */
  211. private Boolean refundWechat(String orderNo, String transactionId, BigDecimal amount) {
  212. try {
  213. log.info("rebackPay=>" + orderNo, transactionId, amount);
  214. WxPayService wxPayService = this.getWxPayService();
  215. //微信支付-申请退款请求参数
  216. WxPayRefundRequest orderRequest = new WxPayRefundRequest();
  217. orderRequest.setOutTradeNo(transactionId);
  218. orderRequest.setOutRefundNo(orderNo);
  219. orderRequest.setRefundFee(BaseWxPayRequest.yuanToFen(amount.toString()));//元转成分
  220. // ShopOrderInfoDto shopOrderInfoDto = new ShopOrderInfoDto();
  221. // shopOrderInfoDto.setPaymentSn(orderInfo.getPaymentSn());
  222. // BigDecimal sumPayFee = shopOrderInfoMapper.selectSumPayFee(shopOrderInfoDto);
  223. // orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(sumPayFee.toString()));
  224. orderRequest.setNotifyUrl(wechatPayConfigInfo.getRefundNotifyUrl() + "/" + wechatPayConfigInfo.getAppId());
  225. //调用微信V3退款API
  226. WxPayRefundResult result = wxPayService.refund(orderRequest);
  227. log.info("微信退款结果:" + result.toString());
  228. return true;
  229. } catch (Exception e) {
  230. log.error("微信退款结果-异常:" + e.getStackTrace());
  231. return false;
  232. }
  233. }
  234. /**
  235. * @desc : 续费的公司提醒回调
  236. * @author : 姜永辉
  237. * @date : 2024-06-29 14:22
  238. */
  239. @Transactional(rollbackFor = {Exception.class})
  240. @XxlJob("renew-reminder")
  241. public ResponseResultVO renewReminder() {
  242. log.info("@XxlJob(\"renewReminder\")id: {}", XxlJobHelper.getJobParam());
  243. try {
  244. // Integer cpid = 382;
  245. Company company = companyMapper.selectById( XxlJobHelper.getJobParam());
  246. // 解析license信息
  247. String licenseStr = AESUtil.desEncrypt(company.getLicense());
  248. log.error("续费的公司提醒回调-licenseStr:" + licenseStr);
  249. if (licenseStr != null) {
  250. Map<String, Object> licenseMap = JSON.parseObject(licenseStr, Map.class);
  251. log.error("续费的公司提醒回调-re_new:" + licenseMap.get("re_new"));
  252. if (licenseMap.get("re_new") != null) {
  253. // 续费 返回的
  254. Map<String, Object> renewM = (Map<String, Object>) licenseMap.get("re_new");
  255. // 生成临时license授权
  256. Map<String, Object> licenseMapNew = new HashMap<>();
  257. licenseMapNew.put("grade_code", licenseMap.get("grade_code"));
  258. licenseMapNew.put("end_date", LocalDate.parse(licenseMap.get("end_date") + ""));
  259. // 续费 返回的
  260. licenseMapNew.put("user_end_date", LocalDate.parse(renewM.get("user_end_date") + ""));
  261. licenseMapNew.put("web_max_num", Integer.parseInt(licenseMap.get("web_max_num") + ""));
  262. // // 续费 返回的
  263. licenseMapNew.put("wx_max_num", Integer.parseInt(renewM.get("wx_max_num") + ""));
  264. licenseMapNew.put("vip", licenseMap.get("vip"));
  265. // 续费 返回的
  266. licenseMapNew.put("fun_package", renewM.get("fun_package"));
  267. // re_new 的值变为null
  268. // licenseMapNew.put("re_new", licenseMap.get("re_new"));
  269. // 续费和升级
  270. Company companynew = new Company();
  271. companynew.setCpId(company.getCpId());
  272. companynew.setLicense(AESUtil.aesEncrypt(JSON.toJSONString(licenseMapNew)));
  273. companyMapper.updateCompanyNewLicense(companynew);
  274. // 续费 返回的 取消授权的员工id 将员工的登录标识修改
  275. if (renewM.get("del_staff_ids") != null) {
  276. List<String> staffids = (List<String>) renewM.get("del_staff_ids");
  277. // 更新员工的登录标识
  278. ResponseResultVO responseResultVO = staffFeign.updateFeignStaffFlgCanLogin(staffids);
  279. }
  280. }
  281. }
  282. } catch (Exception e) {
  283. e.printStackTrace();
  284. log.error("续费的公司提醒回调----异常:{}", e.getMessage());
  285. }
  286. return null;
  287. }
  288. }