RegisterOrderDonServiceImpl.java 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. package com.cyksj.service.register.impl;
  2. import cn.hutool.core.bean.BeanUtil;
  3. import cn.hutool.core.date.DateTime;
  4. import cn.hutool.core.date.DateUtil;
  5. import cn.hutool.core.util.StrUtil;
  6. import cn.hutool.json.JSONUtil;
  7. import com.alipay.api.AlipayClient;
  8. import com.alipay.api.domain.AlipayTradeRefundModel;
  9. import com.alipay.api.internal.util.AlipaySignature;
  10. import com.alipay.api.request.AlipayTradeRefundRequest;
  11. import com.alipay.api.response.AlipayTradeRefundResponse;
  12. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  13. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  14. import com.cyksj.common.exception.BusinessRuntimeException;
  15. import com.cyksj.common.snowflake.Sequence;
  16. import com.cyksj.common.util.Codec;
  17. import com.cyksj.common.util.Jsons;
  18. import com.cyksj.common.util.Xmls;
  19. import com.cyksj.config.WeChatConfig;
  20. import com.cyksj.config.zfb.AliPayClientFactory;
  21. import com.cyksj.config.zfb.BaseZfbConfig;
  22. import com.cyksj.config.zfb.ZfbProductCode;
  23. import com.cyksj.dto.RedisKey;
  24. import com.cyksj.dto.Result;
  25. import com.cyksj.enums.GatewayResponse;
  26. import com.cyksj.mapper.AppleAutoRegisterDataMapper;
  27. import com.cyksj.mapper.RegisterOrderDonMapper;
  28. import com.cyksj.mapper.SpotifyUnLimitRecordMapper;
  29. import com.cyksj.mapper.UserMapper;
  30. import com.cyksj.mapper.channel.ShopConfigMapper;
  31. import com.cyksj.mapper.manage.coupon.CouponMapper;
  32. import com.cyksj.model.dto.AliPayParams;
  33. import com.cyksj.model.dto.H5JsPayParams;
  34. import com.cyksj.model.entity.*;
  35. import com.cyksj.model.manage.request.RegisterReq;
  36. import com.cyksj.model.request.AlipayOrderDonReq;
  37. import com.cyksj.model.request.OrderAttach;
  38. import com.cyksj.model.request.OrderRefundReq;
  39. import com.cyksj.model.views.CouponUserView;
  40. import com.cyksj.redis.RedisService;
  41. import com.cyksj.service.mange.coupon.CouponCommonService;
  42. import com.cyksj.service.pay.AliPayCommonService;
  43. import com.cyksj.service.register.RegisterOrderDonService;
  44. import com.cyksj.service.register.SpotifyService;
  45. import com.cyksj.service.sys.SysConfigService;
  46. import com.cyksj.service.wechat.WeChatService;
  47. import com.cyksj.task.JobManager;
  48. import com.ejlchina.searcher.BeanSearcher;
  49. import com.ejlchina.searcher.param.Operator;
  50. import com.ejlchina.searcher.util.MapUtils;
  51. import lombok.RequiredArgsConstructor;
  52. import lombok.extern.slf4j.Slf4j;
  53. import org.apache.commons.lang3.StringUtils;
  54. import org.springframework.dao.DuplicateKeyException;
  55. import org.springframework.stereotype.Service;
  56. import org.springframework.transaction.annotation.Transactional;
  57. import java.math.BigDecimal;
  58. import java.math.RoundingMode;
  59. import java.util.List;
  60. import java.util.Map;
  61. import java.util.Optional;
  62. /**
  63. * @author chan
  64. * @date 2022/11/7 2:39 PM
  65. */
  66. @Service
  67. @Slf4j
  68. @RequiredArgsConstructor
  69. public class RegisterOrderDonServiceImpl extends ServiceImpl<RegisterOrderDonMapper ,RegisterOrderDon> implements RegisterOrderDonService {
  70. private static final Sequence SEQUENCE = new Sequence(0);
  71. private static final String REGISTER_PRICE_KEY = "register_price";
  72. private final SpotifyService spotifyService;
  73. private final RedisService redisService;
  74. private final WeChatService weChatService;
  75. private final WeChatConfig weChatConfig;
  76. private final SysConfigService sysConfigService;
  77. private final UserMapper userMapper;
  78. private final AppleAutoRegisterDataMapper appleAutoRegisterDataMapper;
  79. private final JobManager jobManager;
  80. private final RegisterOrderDonMapper registerOrderDonMapper;
  81. private final CouponMapper couponMapper;
  82. private final CouponCommonService couponCommonService;
  83. private final SpotifyUnLimitRecordMapper spotifyUnLimitRecordMapper;
  84. private final BeanSearcher beanSearcher;
  85. private final ShopConfigMapper shopConfigMapper;
  86. private final AliPayCommonService aliPayCommonService;
  87. private static final Long EXPIRY_TIME = 1000 * 60 * 5L;
  88. /**
  89. * 判断是否免费
  90. * @author chan
  91. * @date 2022-11-07 3:34 PM
  92. */
  93. @Override
  94. public boolean isFree(long userId, String platform, String code) {
  95. if (StringUtils.isBlank(code)) {
  96. return false;
  97. }
  98. int count = count(Wrappers.lambdaQuery(RegisterOrderDon.class)
  99. .eq(RegisterOrderDon::getUserId, userId)
  100. .notIn(RegisterOrderDon::getStatus, List.of(RegisterOrderDon.Status.noPayment, RegisterOrderDon.Status.error))
  101. .eq(RegisterOrderDon::getIsFree, true));
  102. if(count > 0){
  103. return false;
  104. }
  105. SysConfig sysConfig = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class).eq(SysConfig::getSysKey, "spotify_free_code"));
  106. if (sysConfig == null) {
  107. return false;
  108. }else {
  109. if (JSONUtil.isJsonArray(sysConfig.getSysValue())) {
  110. List<String> list = JSONUtil.parseArray(sysConfig.getSysValue()).toList(String.class);
  111. return list.contains(code);
  112. }else {
  113. return false;
  114. }
  115. }
  116. }
  117. /**
  118. * 保存注册资料
  119. * @author chan
  120. * @date 2022-11-07 3:34 PM
  121. */
  122. @Override
  123. @Transactional(rollbackFor = Throwable.class)
  124. public RegisterOrderDon saveOrder(long userId, RegisterReq req, boolean isFree) throws Exception {
  125. RegisterOrderDon orderDon = new RegisterOrderDon();
  126. User user = userMapper.selectById(userId);
  127. BeanUtil.copyProperties(req,orderDon);
  128. SysConfig register_price = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class).eq(SysConfig::getSysKey, "register_price").last("limit 1"));
  129. Map<String, Integer> map = Jsons.toMap(register_price.getSysValue());
  130. orderDon.setOrderNo(SEQUENCE.nextId() + "");
  131. orderDon.setUserId(userId);
  132. orderDon.setOpenId(user.getOpenId());
  133. orderDon.setIsFree(isFree);
  134. orderDon.setMoney(isFree ? BigDecimal.ZERO : BigDecimal.valueOf(("apple".equals(req.getPlatform()) && "auto".equals(req.getAppleRegisterType())) ? map.get("appleAuto") : map.get(req.getPlatform())));
  135. orderDon.setStatus(isFree ? RegisterOrderDon.Status.hasPayment : RegisterOrderDon.Status.noPayment);
  136. String shopId = sysConfigService.getDefaultShopConfigByType("zfb");
  137. orderDon.setShopId(shopId);
  138. save(orderDon);
  139. //apple
  140. handleAppleIdAuto(userId, req, orderDon);
  141. return orderDon;
  142. }
  143. /**
  144. * Apple ID自动注册
  145. */
  146. private void handleAppleIdAuto(long userId, RegisterReq req, RegisterOrderDon orderDon) {
  147. if ("apple".equals(req.getPlatform()) && "auto".equals(req.getAppleRegisterType())) {
  148. //是否有未支付的国家或区域的订单
  149. Integer exists = appleAutoRegisterDataMapper.checkNoPayOrder(userId, req.getCountryOrArea());
  150. if (exists != null) {
  151. throw BusinessRuntimeException.getInstance(String.format("您有%s随机生成Apple ID未支付的订单", req.getCountryOrArea().getDesc()));
  152. }
  153. if (req.getCountryOrArea() == null) {
  154. throw BusinessRuntimeException.getInstance("请选择对应的国家或地区");
  155. }
  156. //查看是否有空余账号
  157. AppleAutoRegisterData appleAutoRegisterData = appleAutoRegisterDataMapper.selectOne(Wrappers.lambdaQuery(AppleAutoRegisterData.class).eq(AppleAutoRegisterData::getCountryOrArea, req.getCountryOrArea()).eq(AppleAutoRegisterData::getStatus, false).select(AppleAutoRegisterData::getId).last("limit 1"));
  158. if (appleAutoRegisterData == null) {
  159. throw BusinessRuntimeException.getInstance("自动生成Apple ID库存不足");
  160. }
  161. appleAutoRegisterData.setUserId(userId);
  162. appleAutoRegisterData.setStatus(true);
  163. appleAutoRegisterData.setOrderId(orderDon.getId());
  164. int update = appleAutoRegisterDataMapper.update(appleAutoRegisterData, Wrappers.lambdaUpdate(AppleAutoRegisterData.class).eq(AppleAutoRegisterData::getStatus, false).eq(AppleAutoRegisterData::getId, appleAutoRegisterData.getId()));
  165. if (update != 1) {
  166. throw BusinessRuntimeException.getInstance("系统异常,请重新操作");
  167. }
  168. jobManager.addJob(EXPIRY_TIME, () -> {
  169. updateAppleAutoStatus(orderDon.getId());
  170. });
  171. }
  172. }
  173. @Override
  174. public void updateAppleAutoStatus(Long orderId) {
  175. log.info("校验appleID自动注册订单 orderId:{}", orderId);
  176. RegisterOrderDon registerOrderDon = this.getById(orderId);
  177. if (registerOrderDon != null && RegisterOrderDon.Status.noPayment == registerOrderDon.getStatus()) {
  178. AppleAutoRegisterData appleAutoRegisterData = appleAutoRegisterDataMapper.selectOne(Wrappers.lambdaQuery(AppleAutoRegisterData.class).eq(AppleAutoRegisterData::getOrderId, orderId).last("limit 1"));
  179. if (appleAutoRegisterData != null) {
  180. appleAutoRegisterData.setStatus(false);
  181. appleAutoRegisterData.setUserId(0l);
  182. appleAutoRegisterData.setOrderId(0l);
  183. appleAutoRegisterDataMapper.updateById(appleAutoRegisterData);
  184. log.info("未支付appleID自动注册订单:{},修改appleID使用状态", orderId);
  185. }
  186. //订单关闭
  187. registerOrderDon.setStatus(RegisterOrderDon.Status.close);
  188. registerOrderDonMapper.updateById(registerOrderDon);
  189. }
  190. }
  191. @Override
  192. public CouponUserView spotifyUnLimit(SpotifyUnLimitRecord spotifyUnLimitRecord) {
  193. Boolean isFlag = false;
  194. Long spotifyUnLimitCouponId = null;
  195. //是否配置了优惠券
  196. SysConfig spotify_unLimit_cid = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class).eq(SysConfig::getSysKey, "spotify_unLimit_cid").last("limit 1"));
  197. if (spotify_unLimit_cid != null && StrUtil.isNotBlank(spotify_unLimit_cid.getSysValue())) {
  198. spotifyUnLimitCouponId = Long.parseLong(spotify_unLimit_cid.getSysValue());
  199. Coupon coupon = couponMapper.selectById(spotifyUnLimitCouponId);
  200. if (coupon != null) {
  201. isFlag = couponCommonService.sendCouponToUser(spotifyUnLimitRecord.getUserId(), spotifyUnLimitCouponId, null, null, null, CouponUser.Channel.manual);
  202. }
  203. }
  204. //14天内是否重复提交过该账号
  205. SpotifyUnLimitRecord exists = spotifyUnLimitRecordMapper.selectOne(Wrappers.lambdaQuery(SpotifyUnLimitRecord.class)
  206. .eq(SpotifyUnLimitRecord::getUserId, spotifyUnLimitRecord.getUserId())
  207. .eq(SpotifyUnLimitRecord::getAccount, spotifyUnLimitRecord.getAccount())
  208. .last("limit 1"));
  209. if (exists != null && exists.getUpdateTime().after(DateUtil.offsetDay(DateTime.now(), -14))) {
  210. throw BusinessRuntimeException.getInstance("您已提交过,请勿重复提交");
  211. }
  212. if (exists != null) {
  213. spotifyUnLimitRecord.setId(exists.getId());
  214. spotifyUnLimitRecord.setIsSend(false);
  215. spotifyUnLimitRecordMapper.updateById(spotifyUnLimitRecord);
  216. } else {
  217. try {
  218. spotifyUnLimitRecordMapper.insert(spotifyUnLimitRecord);
  219. } catch (DuplicateKeyException e) {
  220. log.info("用户:{}重复提交解除限制spotify账号:{}", spotifyUnLimitRecord.getUserId(), spotifyUnLimitRecord.getAccount());
  221. }
  222. }
  223. return isFlag ? beanSearcher.searchFirst(CouponUserView.class, MapUtils.builder()
  224. .field(CouponUserView::getUserId, spotifyUnLimitRecord.getUserId()).op(Operator.Equal)
  225. .field(CouponUserView::getCouponId, spotifyUnLimitCouponId).op(Operator.Equal)
  226. .build()) : null;
  227. }
  228. @Override
  229. public CouponUserView getAvailableSpotifyCoupon(long userId) {
  230. SysConfig spotify_register_success_cid = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class).eq(SysConfig::getSysKey, "spotify_register_success_cid").last("limit 1"));
  231. CouponUserView couponUserView = null;
  232. if (spotify_register_success_cid != null && StrUtil.isNotBlank(spotify_register_success_cid.getSysValue())) {
  233. DateTime now = DateTime.now();
  234. Long spotifyRegisterSucCid = Long.parseLong(spotify_register_success_cid.getSysValue());
  235. couponUserView = beanSearcher.searchFirst(CouponUserView.class, MapUtils.builder()
  236. .field(CouponUserView::getUserId, userId).op(Operator.Equal)
  237. .field(CouponUserView::getCouponId, spotifyRegisterSucCid).op(Operator.Equal)
  238. .field(CouponUserView::getCouponUserStatus, CouponUser.Status.unused.name()).op(Operator.Equal)
  239. .field(CouponUserView::getValidStartTime, now).op(Operator.LessThan)
  240. .field(Coupon::getValidEndTime, now).op(Operator.GreaterThan)
  241. .build());
  242. }
  243. return couponUserView;
  244. }
  245. @Override
  246. public void unifiedRefund(OrderRefundReq refundReq) throws Exception {
  247. Long orderId = refundReq.getOrderId();
  248. RegisterOrderDon registerOrderDon = this.getById(orderId);
  249. if (registerOrderDon == null) throw BusinessRuntimeException.getInstance("订单不存在");
  250. if (registerOrderDon.getStatus() == RegisterOrderDon.Status.refund) throw BusinessRuntimeException.getInstance("该订单已退款");
  251. if (registerOrderDon.getStatus() != RegisterOrderDon.Status.error && registerOrderDon.getStatus() != RegisterOrderDon.Status.hasPayment) {
  252. throw BusinessRuntimeException.getInstance("该订单状态不允许退款");
  253. }
  254. if (registerOrderDon.getMoney().compareTo(BigDecimal.ZERO) <= 0) {
  255. throw BusinessRuntimeException.getInstance("该订单金额为0,无需退款");
  256. }
  257. if (!redisService.setNx(String.format("%s", refundReq.getOrderId()), refundReq.getOrderId(), 10l)) {
  258. throw BusinessRuntimeException.getInstance("请勿重复点击,正在退款中..");
  259. }
  260. RegisterOrderDon.Type type = registerOrderDon.getType();
  261. if (type == RegisterOrderDon.Type.WeChat) {
  262. wxRefund(refundReq, registerOrderDon);
  263. }
  264. if (type == RegisterOrderDon.Type.ALI_PAY) {
  265. zfbRefund(refundReq, registerOrderDon);
  266. }
  267. }
  268. @Override
  269. public AliPayParams zfbUnifiedPay(AlipayOrderDonReq re) throws Exception {
  270. String productCode = StrUtil.EMPTY;
  271. if (re.getType() == 1) {
  272. productCode = ZfbProductCode.MOBILE_WEB.getProductCode();
  273. }
  274. if (re.getType() == 2) {
  275. productCode = ZfbProductCode.PC_WEB.getProductCode();
  276. }
  277. return aliPayCommonService.unifiedPayRegister(re.getOrderId(), productCode, re.getPayMode(), re.getReturnUrl());
  278. }
  279. @Override
  280. public void aliPayNotify(Map<String, String> params) throws Exception {
  281. //调用SDK验证签名
  282. String body = Codec.DoBase64.custom().setData(params.get("body")).decodeAsText();
  283. OrderAttach orderAttach = Jsons.parseObject(body, OrderAttach.class);
  284. Long oderId = orderAttach.getO();
  285. RegisterOrderDon orderDon = getById(oderId);
  286. if (null == orderDon) {
  287. throw BusinessRuntimeException.getInstance("订单不存在.");
  288. }
  289. String appId = params.get("app_id");
  290. boolean signVerified = AlipaySignature.rsaCheckV1(params, shopConfigMapper.getByAppId(appId).getPublicKey(), BaseZfbConfig.charset, BaseZfbConfig.signType);
  291. if (!signVerified) {
  292. log.error("支付宝回调校验签名错误,自定义入参:{}", params.get("body"));
  293. throw BusinessRuntimeException.getInstance("支付宝回调校验签名错误");
  294. }
  295. String transactionId = params.get("trade_no");
  296. String payTimeStr = params.get("gmt_payment");
  297. if (!orderDon.getStatus().equals(RegisterOrderDon.Status.noPayment) && !orderDon.getStatus().equals(RegisterOrderDon.Status.close)) {
  298. log.info("支付宝已回调,重复修改状态 id:{}", orderDon.getId());
  299. return;
  300. }
  301. // 更改订单状态
  302. orderDon.setTransactionId(transactionId);
  303. orderDon.setStatus(RegisterOrderDon.Status.hasPayment);
  304. AppleAutoRegisterData appleAutoRegisterData = appleAutoRegisterDataMapper.selectOne(Wrappers.lambdaQuery(AppleAutoRegisterData.class).eq(AppleAutoRegisterData::getOrderId, orderDon.getId()).eq(AppleAutoRegisterData::getStatus, true));
  305. if (appleAutoRegisterData != null) {
  306. orderDon.setStatus(RegisterOrderDon.Status.complete);
  307. }
  308. if (StrUtil.isNotBlank(payTimeStr)) {
  309. orderDon.setPayTime(DateUtil.parse(payTimeStr, "yyyy-MM-dd HH:mm:ss"));
  310. }
  311. this.updateById(orderDon);
  312. }
  313. @Override
  314. public H5JsPayParams pay(Long orderId) throws Exception {
  315. log.info("注册 账号调起微信支付[start] orderId:{}", orderId);
  316. RegisterOrderDon orderDon = this.getById(orderId);
  317. if (orderDon.getStatus() == RegisterOrderDon.Status.close) {
  318. throw BusinessRuntimeException.getInstance("订单已关闭");
  319. }
  320. OrderAttach attach = new OrderAttach();
  321. attach.setO(orderDon.getId());
  322. //获取支付默认商户
  323. String shopId = sysConfigService.getDefaultShopConfigByType("wx");
  324. String toWechatAttach = Codec.DoBase64.custom()
  325. .setData(Jsons.toJson(attach)).encodeAsText();
  326. H5JsPayParams params = weChatService.getJsPayParams(
  327. weChatConfig.getAppid(),
  328. shopId,
  329. orderDon.getOpenId(),
  330. orderDon.getMoney().intValue(),
  331. orderDon.getOrderNo(),
  332. weChatConfig.getDomain() + "applets/register/prepay/notify",
  333. toWechatAttach,
  334. "注册服务",
  335. "JSAPI",
  336. null
  337. );
  338. log.info("微信支付成功[end]");
  339. return params;
  340. }
  341. @Override
  342. @Transactional(rollbackFor = Throwable.class)
  343. public void prepayNotify(Map<String, String> map) throws Exception {
  344. /* 此处处理订单等业务逻辑 */
  345. // 获取订单 和 微信订单号 和 支付的金额
  346. String attach = Codec.DoBase64.custom().setData(map.get("attach")).decodeAsText();
  347. OrderAttach orderAttach = Jsons.parseObject(attach, OrderAttach.class);
  348. final Long oid = orderAttach.getO();
  349. //final Long shareId = orderAttach.getShared();
  350. RegisterOrderDon order = this.getById(oid);
  351. if (null == order) {
  352. throw BusinessRuntimeException.getInstance("订单不存在.");
  353. }
  354. String appId = map.get("mch_id");
  355. // 校验签名
  356. boolean f = weChatService.checkSignWithMd5(map, shopConfigMapper.getByAppId(appId).getSecret());
  357. if (!f) {
  358. log.error("回调数据:{}", map);
  359. throw BusinessRuntimeException.getInstance("支付成功回调, 校验签名失败.");
  360. }
  361. String transactionId = map.get("transaction_id");
  362. if (order.getStatus().equals(RegisterOrderDon.Status.hasPayment)) {
  363. log.info("已回调,重复修改状态 id:{}", order.getId());
  364. return;
  365. }
  366. // 更改订单状态
  367. order.setTransactionId(transactionId);
  368. order.setStatus(RegisterOrderDon.Status.hasPayment);
  369. AppleAutoRegisterData appleAutoRegisterData = appleAutoRegisterDataMapper.selectOne(Wrappers.lambdaQuery(AppleAutoRegisterData.class).eq(AppleAutoRegisterData::getOrderId, order.getId()).eq(AppleAutoRegisterData::getStatus, true));
  370. if (appleAutoRegisterData != null) {
  371. order.setStatus(RegisterOrderDon.Status.complete);
  372. }
  373. order.setPayTime(DateUtil.parse(map.get("time_end"), "yyyyMMddHHmmss"));
  374. if (StringUtils.isBlank(order.getOpenId())) {
  375. order.setOpenId(map.get("openid"));
  376. }
  377. this.updateById(order);
  378. }
  379. @Override
  380. public Result<String> wxRefund(OrderRefundReq refundReq,RegisterOrderDon registerOrderDon) throws Exception {
  381. long time = System.currentTimeMillis();
  382. //退款订单号
  383. String outRefundNo = Codec.DoDigest.custom()
  384. .setAlgorithm(Codec.DoDigest.Algorithm.MD5)
  385. .setStringData(time + String.valueOf(registerOrderDon.getId()))
  386. .toHexString();
  387. if (refundReq.getRefundMoney() == null) {
  388. refundReq.setRefundMoney(registerOrderDon.getMoney());
  389. }
  390. weChatService.refundWxOrder(weChatConfig.getAppid(),
  391. Optional.ofNullable(registerOrderDon.getShopId()).orElse(ShopConfig.WX_DEFAULT_APP_ID),
  392. registerOrderDon.getTransactionId(),
  393. outRefundNo,
  394. registerOrderDon.getMoney(),
  395. refundReq.getRefundMoney(),
  396. weChatConfig.getDomain() + "manage/register/wx/refund/notify");
  397. //修改订单状态
  398. registerOrderDon.setStatus(RegisterOrderDon.Status.refund);
  399. registerOrderDon.setRefundMoney(refundReq.getRefundMoney());
  400. this.updateById(registerOrderDon);
  401. return GatewayResponse.SUCCESS.newBuilder().toResult("退款成功");
  402. }
  403. @Override
  404. public void wxRefundNotify(Map<String, String> map) throws Exception {
  405. // 对退款数据 解密
  406. String md5Key = Codec.DoDigest.custom().setAlgorithm(Codec.DoDigest.Algorithm.MD5).setStringData(shopConfigMapper.getByAppId(map.get("mch_id")).getSecret()).toHexString();
  407. String reqInfoXml = Codec.DoCipher.custom().setAlgorithm(Codec.DoCipher.Trans.AES_ECB_PKCS7Padding).setBase64Data(map.get("req_info")).setStringKey(md5Key).ofDecrypt().toText();
  408. log.info("=== 退款数据解密: \n {}", reqInfoXml);
  409. Map<String, String> reqInfoMap = Xmls.toMap(reqInfoXml);
  410. // 退款失败
  411. if (StrUtil.equals("CHANGE", reqInfoMap.get("refund_status"))) {
  412. throw BusinessRuntimeException.getInstance("退款异常.");
  413. } else if (StrUtil.equals("REFUNDCLOSE", reqInfoMap.get("refund_status"))) {
  414. throw BusinessRuntimeException.getInstance("退款关闭.");
  415. }
  416. /* 此处处理业务逻辑 */
  417. String outRefundNo = reqInfoMap.get("out_refund_no");
  418. String transactionId = reqInfoMap.get("transaction_id");
  419. RegisterOrderDon registerOrderDon = this.getOne(Wrappers.lambdaQuery(RegisterOrderDon.class).eq(RegisterOrderDon::getTransactionId, transactionId).last("limit 1"));
  420. if (registerOrderDon == null) {
  421. log.error("退款回调,transactionId:{}订单不存在", transactionId);
  422. }
  423. if (registerOrderDon.getStatus() != RegisterOrderDon.Status.refund) {
  424. registerOrderDon.setStatus(RegisterOrderDon.Status.refund);
  425. this.updateById(registerOrderDon);
  426. }
  427. log.info("微信退款: 退款单号[{}] 退款成功.", outRefundNo);
  428. }
  429. public void zfbRefund(OrderRefundReq refundReq, RegisterOrderDon registerOrderDon) throws Exception {
  430. AlipayTradeRefundResponse response;
  431. //支付宝退款
  432. AlipayClient alipayClient = AliPayClientFactory.getAlipayClient(Optional.ofNullable(registerOrderDon.getShopId()).orElse(ShopConfig.ZFB_DEFAULT_APP_ID));
  433. AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
  434. AlipayTradeRefundModel model = new AlipayTradeRefundModel();
  435. //支付宝交易号
  436. model.setTradeNo(registerOrderDon.getTransactionId());
  437. if (refundReq.getRefundMoney() == null) {
  438. refundReq.setRefundMoney(registerOrderDon.getMoney());
  439. }
  440. model.setRefundAmount(refundReq.getRefundMoney().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_EVEN).toString());
  441. model.setQueryOptions(List.of("gmt_refund_pay"));
  442. long time = System.currentTimeMillis();
  443. //退款订单号
  444. String outRefundNo = Codec.DoDigest.custom()
  445. .setAlgorithm(Codec.DoDigest.Algorithm.MD5)
  446. .setStringData(time + String.valueOf(registerOrderDon.getId()))
  447. .toHexString();
  448. //退款请求号
  449. model.setOutRequestNo(outRefundNo);
  450. request.setBizModel(model);
  451. String shopId = registerOrderDon.getShopId();
  452. ShopConfig shopConfig = shopConfigMapper.selectOne(Wrappers.lambdaQuery(ShopConfig.class).eq(ShopConfig::getAppId, registerOrderDon.getShopId()));
  453. if (shopId != null && shopConfig != null && shopConfig.getIsCert()) {
  454. response = alipayClient.certificateExecute(request);
  455. } else {
  456. response = alipayClient.execute(request);
  457. }
  458. if (!response.isSuccess()) throw BusinessRuntimeException.getInstance("退款失败,e:{0}", response.getSubMsg());
  459. registerOrderDon.setStatus(RegisterOrderDon.Status.refund);
  460. registerOrderDon.setRefundMoney(refundReq.getRefundMoney());
  461. registerOrderDonMapper.updateById(registerOrderDon);
  462. }
  463. }