MintOrderService.java 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. package com.izouma.nineth.service;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.alibaba.fastjson.serializer.SerializerFeature;
  5. import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
  6. import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
  7. import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
  8. import com.github.binarywang.wxpay.constant.WxPayConstants;
  9. import com.github.binarywang.wxpay.exception.WxPayException;
  10. import com.github.binarywang.wxpay.service.WxPayService;
  11. import com.huifu.adapay.core.exception.BaseAdaPayException;
  12. import com.huifu.adapay.model.AdapayCommon;
  13. import com.huifu.adapay.model.Payment;
  14. import com.izouma.nineth.config.*;
  15. import com.izouma.nineth.domain.*;
  16. import com.izouma.nineth.domain.Collection;
  17. import com.izouma.nineth.dto.PageQuery;
  18. import com.izouma.nineth.enums.*;
  19. import com.izouma.nineth.event.OrderNotifyEvent;
  20. import com.izouma.nineth.exception.BusinessException;
  21. import com.izouma.nineth.repo.*;
  22. import com.izouma.nineth.utils.JpaUtils;
  23. import com.izouma.nineth.utils.SecurityUtils;
  24. import com.izouma.nineth.utils.SnowflakeIdWorker;
  25. import lombok.AllArgsConstructor;
  26. import lombok.extern.slf4j.Slf4j;
  27. import org.apache.commons.codec.EncoderException;
  28. import org.apache.commons.codec.net.URLCodec;
  29. import org.apache.commons.collections.MapUtils;
  30. import org.apache.commons.lang3.ObjectUtils;
  31. import org.apache.commons.lang3.StringUtils;
  32. import org.apache.rocketmq.spring.core.RocketMQTemplate;
  33. import org.springframework.context.annotation.Lazy;
  34. import org.springframework.core.env.Environment;
  35. import org.springframework.data.domain.Page;
  36. import org.springframework.data.redis.core.BoundSetOperations;
  37. import org.springframework.data.redis.core.BoundValueOperations;
  38. import org.springframework.data.redis.core.RedisTemplate;
  39. import org.springframework.scheduling.annotation.Scheduled;
  40. import org.springframework.stereotype.Service;
  41. import javax.transaction.Transactional;
  42. import java.math.BigDecimal;
  43. import java.math.RoundingMode;
  44. import java.time.LocalDateTime;
  45. import java.time.format.DateTimeFormatter;
  46. import java.util.*;
  47. import java.util.concurrent.TimeUnit;
  48. import java.util.stream.Collectors;
  49. @Slf4j
  50. @Service
  51. public class MintOrderService {
  52. private final MintOrderRepo mintOrderRepo;
  53. private final UserRepo userRepo;
  54. private final AssetService assetService;
  55. private final AssetRepo assetRepo;
  56. private final MintActivityRepo mintActivityRepo;
  57. private final UserAddressRepo userAddressRepo;
  58. private final GeneralProperties generalProperties;
  59. private final Environment env;
  60. private final AdapayProperties adapayProperties;
  61. private final SnowflakeIdWorker snowflakeIdWorker;
  62. private final WxPayProperties wxPayProperties;
  63. private final WxPayService wxPayService;
  64. private final MintMaterialRepo mintMaterialRepo;
  65. private final MintActivityService mintActivityService;
  66. private final RedisTemplate<String, Object> redisTemplate;
  67. private final RocketMQTemplate rocketMQTemplate;
  68. private final CollectionRepo collectionRepo;
  69. private final OrderRepo orderRepo;
  70. private final ShowCollectionRepo showCollectionRepo;
  71. private final AirDropService airDropService;
  72. private final OrderPayService orderPayService;
  73. public MintOrderService(MintOrderRepo mintOrderRepo,
  74. UserRepo userRepo,
  75. AssetService assetService,
  76. AssetRepo assetRepo,
  77. MintActivityRepo mintActivityRepo,
  78. UserAddressRepo userAddressRepo,
  79. GeneralProperties generalProperties,
  80. Environment env,
  81. AdapayProperties adapayProperties,
  82. SnowflakeIdWorker snowflakeIdWorker,
  83. WxPayProperties wxPayProperties,
  84. WxPayService wxPayService,
  85. MintMaterialRepo mintMaterialRepo,
  86. MintActivityService mintActivityService,
  87. RedisTemplate<String, Object> redisTemplate,
  88. RocketMQTemplate rocketMQTemplate,
  89. CollectionRepo collectionRepo,
  90. OrderRepo orderRepo,
  91. ShowCollectionRepo showCollectionRepo,
  92. AirDropService airDropService,
  93. @Lazy OrderPayService orderPayService) {
  94. this.mintOrderRepo = mintOrderRepo;
  95. this.userRepo = userRepo;
  96. this.assetService = assetService;
  97. this.assetRepo = assetRepo;
  98. this.mintActivityRepo = mintActivityRepo;
  99. this.userAddressRepo = userAddressRepo;
  100. this.generalProperties = generalProperties;
  101. this.env = env;
  102. this.adapayProperties = adapayProperties;
  103. this.snowflakeIdWorker = snowflakeIdWorker;
  104. this.wxPayProperties = wxPayProperties;
  105. this.wxPayService = wxPayService;
  106. this.mintMaterialRepo = mintMaterialRepo;
  107. this.mintActivityService = mintActivityService;
  108. this.redisTemplate = redisTemplate;
  109. this.rocketMQTemplate = rocketMQTemplate;
  110. this.collectionRepo = collectionRepo;
  111. this.orderRepo = orderRepo;
  112. this.showCollectionRepo = showCollectionRepo;
  113. this.airDropService = airDropService;
  114. this.orderPayService = orderPayService;
  115. }
  116. public Page<MintOrder> all(PageQuery pageQuery) {
  117. return mintOrderRepo.findAll(JpaUtils.toSpecification(pageQuery, MintOrder.class), JpaUtils.toPageRequest(pageQuery));
  118. }
  119. @Transactional
  120. public void create(Long userId, List<Long> assetIds) {
  121. User user = userRepo.findByIdAndDelFalse(userId).orElseThrow(new BusinessException("用户不存在"));
  122. User blackHole = userRepo.findByIdAndDelFalse(1435297L).orElseThrow(new BusinessException("无法铸造"));
  123. if (assetIds.size() != 3) {
  124. throw new BusinessException("数量不正确,请重新选择");
  125. }
  126. List<Asset> assets = assetRepo.findAllByIdInAndUserId(assetIds, userId);
  127. assets = assets.stream()
  128. .filter(asset -> asset.getName().contains("尼尔斯") && AssetStatus.NORMAL.equals(asset.getStatus()))
  129. .collect(Collectors.toList());
  130. if (assets.size() != 3) {
  131. throw new BusinessException("有藏品不符合,请重新选择");
  132. }
  133. // 铸造订单
  134. MintOrder order = mintOrderRepo.save(MintOrder.builder()
  135. .userId(userId)
  136. .phone(user.getPhone())
  137. .consume(true)
  138. .status(MintOrderStatus.AIR_DROP)
  139. .build());
  140. // 铸造资产
  141. List<MintMaterial> materials = assets.stream().map(asset -> {
  142. MintMaterial material = new MintMaterial();
  143. material.setAssetId(asset.getId());
  144. material.setCollectionId(asset.getCollectionId());
  145. material.setName(asset.getName());
  146. material.setNumber(asset.getNumber());
  147. material.setPic(asset.getPic());
  148. material.setCategory(asset.getCategory());
  149. material.setOrderId(order.getId());
  150. return material;
  151. }).collect(Collectors.toList());
  152. mintMaterialRepo.saveAll(materials);
  153. // 改为转赠
  154. assets.forEach(asset -> assetService.transfer(asset, asset.getPrice(), blackHole, TransferReason.GIFT, null));
  155. }
  156. /**
  157. * 订单
  158. *
  159. * @param id 编号
  160. */
  161. public void finish(Long id) {
  162. MintOrder mintOrder = mintOrderRepo.findById(id).orElseThrow(new BusinessException("铸造订单不存在"));
  163. mintOrder.setStatus(MintOrderStatus.FINISH);
  164. mintOrderRepo.save(mintOrder);
  165. }
  166. /**
  167. * 发货
  168. *
  169. * @param id 编号
  170. * @param courierId 快递单号
  171. */
  172. public void dispatch(Long id, String courierId) {
  173. MintOrder mintOrder = mintOrderRepo.findById(id).orElseThrow(new BusinessException("铸造订单不存在"));
  174. mintOrder.setStatus(MintOrderStatus.RECEIVE);
  175. mintOrder.setCourierId(courierId);
  176. mintOrderRepo.save(mintOrder);
  177. }
  178. /**
  179. * @param user 用户
  180. * @param assetId 资产
  181. * @param mintActivityId 铸造活动
  182. * @param addressId 地址
  183. */
  184. // @Transactional
  185. public MintOrder create(User user, List<Long> assetId, Long mintActivityId, Long addressId) {
  186. // 参加的活动
  187. MintActivity mintActivity = mintActivityRepo.findByIdAndDelFalse(mintActivityId)
  188. .orElseThrow(new BusinessException("无此铸造活动"));
  189. if (mintActivity.isScheduleSale()) {
  190. if (mintActivity.getStartTime().isAfter(LocalDateTime.now())) {
  191. throw new BusinessException("当前还未开售");
  192. }
  193. }
  194. if (!mintActivity.isOnShelf()) {
  195. throw new BusinessException("活动已下架");
  196. }
  197. UserAddress userAddress = null;
  198. if (addressId != null) {
  199. userAddress = userAddressRepo.findById(addressId).orElseThrow(new BusinessException("地址信息不存在"));
  200. }
  201. int stock = Optional.ofNullable(mintActivityService.decreaseStock(mintActivityId, 1))
  202. .map(Math::toIntExact)
  203. .orElseThrow(new BusinessException("很遗憾,铸造活动已无库存"));
  204. try {
  205. if (stock < 0) {
  206. throw new BusinessException("铸造活动已无库存");
  207. }
  208. if (mintActivity.getNum() > 0) {
  209. if (assetId.size() != mintActivity.getNum()) {
  210. throw new BusinessException("数量不正确,请重新选择");
  211. }
  212. }
  213. List<Asset> assets = assetRepo.findAllByIdInAndUserId(assetId, user.getId());
  214. // if (assets.stream().anyMatch(a -> a.isPublicShow() || a.isConsignment())) {
  215. // throw new BusinessException("请先下架所选藏品");
  216. // }
  217. if (!mintActivity.isAudit()) {
  218. if (assets.stream().anyMatch(a -> a.getStatus() != AssetStatus.NORMAL)) {
  219. throw new BusinessException("所选藏品不符和规则,请重新选择");
  220. }
  221. if (!mintActivityService.matchRule(new ArrayList<>(assets), mintActivity.getRule())) {
  222. throw new BusinessException("所选藏品不符和规则,请重新选择");
  223. }
  224. } else {
  225. // 资产产品是否符合铸造活动的名称
  226. assets = assets.stream()
  227. .filter(asset -> asset.getName()
  228. .contains(mintActivity.getCollectionName()) && AssetStatus.NORMAL.equals(asset.getStatus()))
  229. .collect(Collectors.toList());
  230. if (mintActivity.getNum() > 0 && (assets.size() != mintActivity.getNum())) {
  231. throw new BusinessException("有藏品不符合,请重新选择");
  232. }
  233. }
  234. Map<Long, Long> privilegeIds = new HashMap<>();
  235. // 铸造特权
  236. if (!mintActivity.isConsume()) {
  237. assets.forEach(asset -> {
  238. List<Privilege> privileges = asset.getPrivileges()
  239. .stream()
  240. .filter(p -> p.getName().equals("铸造"))
  241. .collect(Collectors.toList());
  242. if (privileges.size() == 0) {
  243. throw new BusinessException("无铸造特权");
  244. } else {
  245. boolean flag = false;
  246. for (Privilege privilege : privileges) {
  247. // 打开多次 或者 可打开一次但未使用
  248. if (!privilege.isOnce() || (privilege.isOnce() && !privilege
  249. .isOpened())) {
  250. flag = true;
  251. privilegeIds.put(asset.getId(), privilege.getId());
  252. break;
  253. }
  254. }
  255. if (!flag) {
  256. throw new BusinessException("铸造特权已使用");
  257. }
  258. }
  259. });
  260. assets.forEach(asset -> {
  261. asset.getPrivileges()
  262. .stream()
  263. .filter(p -> p.getId().equals(privilegeIds.get(asset.getId())))
  264. .forEach(p -> {
  265. p.setOpened(true);
  266. p.setOpenTime(LocalDateTime.now());
  267. p.setOpenedBy(SecurityUtils.getAuthenticatedUser().getId());
  268. });
  269. assetRepo.save(asset);
  270. });
  271. } else {
  272. // 转让的用户
  273. userRepo.findByIdAndDelFalse(1435297L).orElseThrow(new BusinessException("无法铸造"));
  274. // 消耗改为转赠
  275. assets.forEach(asset -> {
  276. if (!asset.getUserId().equals(user.getId())) {
  277. throw new BusinessException("此藏品不属于你");
  278. }
  279. // 取消公开展示
  280. if (asset.isPublicShow()) {
  281. if (asset.isConsignment()) {
  282. if (asset.getPublicCollectionId() != null) {
  283. List<Order> orders = orderRepo.findByCollectionId(asset.getPublicCollectionId());
  284. if (orders.stream().anyMatch(o -> o.getStatus() != OrderStatus.CANCELLED)) {
  285. throw new BusinessException("已有订单不可取消寄售");
  286. }
  287. }
  288. // asset.setConsignment(false);
  289. }
  290. Collection collection = collectionRepo.findById(asset.getPublicCollectionId())
  291. .orElseThrow(new BusinessException("无展示记录"));
  292. collectionRepo.delete(collection);
  293. // 如果展厅有此藏品
  294. showCollectionRepo.deleteAllByCollectionId(asset.getPublicCollectionId());
  295. }
  296. });
  297. // 统一处理
  298. assets.forEach(asset -> {
  299. if (asset.isPublicShow()) {
  300. asset.setPublicShow(false);
  301. asset.setPublicCollectionId(null);
  302. if (asset.isConsignment()) {
  303. asset.setConsignment(false);
  304. }
  305. }
  306. asset.setStatus(AssetStatus.MINTING);
  307. assetRepo.save(asset);
  308. });
  309. }
  310. // 铸造订单
  311. MintOrder mintOrder = mintOrderRepo.save(MintOrder.builder()
  312. .userId(user.getId())
  313. .phone(user.getPhone())
  314. .consume(mintActivity.isConsume())
  315. .status(MintOrderStatus.NOT_PAID)
  316. .airDrop(mintActivity.isAirDrop())
  317. .gasPrice(mintActivity.getGasPrice())
  318. .mintActivityId(mintActivityId)
  319. .contactName(Optional.ofNullable(userAddress).map(UserAddress::getName).orElse(null))
  320. .contactPhone(Optional.ofNullable(userAddress).map(UserAddress::getPhone).orElse(null))
  321. .address(Optional.ofNullable(userAddress).map(u ->
  322. u.getProvinceName() + " " + u.getCityName() + " " + u.getDistrictName() + " " + u.getAddress())
  323. .orElse(null))
  324. .build());
  325. // 铸造资产
  326. List<MintMaterial> materials = assets.stream().map(asset -> {
  327. MintMaterial material = new MintMaterial();
  328. material.setAssetId(asset.getId());
  329. material.setCollectionId(asset.getCollectionId());
  330. material.setName(asset.getName());
  331. material.setPrivilegeId(privilegeIds.get(asset.getId()));
  332. material.setNumber(asset.getNumber());
  333. material.setPic(asset.getPic());
  334. material.setCategory(asset.getCategory());
  335. material.setOrderId(mintOrder.getId());
  336. return material;
  337. }).collect(Collectors.toList());
  338. mintMaterialRepo.saveAll(materials);
  339. if (mintOrder.getGasPrice().compareTo(BigDecimal.ZERO) == 0) {
  340. this.mintNotify(mintOrder.getId(), PayMethod.WEIXIN, null);
  341. }
  342. return mintOrder;
  343. } catch (Exception e) {
  344. // 错了加库存
  345. mintActivityService.increaseStock(mintActivityId, 1);
  346. throw e;
  347. }
  348. }
  349. public Object payOrderWeixin(Long id, String tradeType, String openId) throws WxPayException, EncoderException {
  350. MintOrder order = mintOrderRepo.findById(id).orElseThrow(new BusinessException("订单不存在"));
  351. if (order.getStatus() != MintOrderStatus.NOT_PAID) {
  352. throw new BusinessException("订单状态错误");
  353. }
  354. WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
  355. request.setBody("铸造GAS费");
  356. request.setOutTradeNo(String.valueOf(new SnowflakeIdWorker(1, 1).nextId()));
  357. request.setTotalFee(order.getGasPrice().multiply(BigDecimal.valueOf(100)).intValue());
  358. if (Arrays.stream(env.getActiveProfiles()).noneMatch(s -> s.equals("prod"))) {
  359. // 测试环境设为1分
  360. // request.setTotalFee(1);
  361. }
  362. request.setSpbillCreateIp("180.102.110.170");
  363. request.setNotifyUrl(wxPayProperties.getNotifyUrl());
  364. request.setTradeType(tradeType);
  365. request.setOpenid(openId);
  366. request.setSignType("MD5");
  367. JSONObject body = new JSONObject();
  368. body.put("action", "payMintOrder");
  369. body.put("userId", order.getUserId());
  370. body.put("orderId", order.getId());
  371. request.setAttach(body.toJSONString());
  372. if (WxPayConstants.TradeType.MWEB.equals(tradeType)) {
  373. WxPayMwebOrderResult result = wxPayService.createOrder(request);
  374. return result.getMwebUrl() + "&redirect_url=" + new URLCodec().encode(wxPayProperties.getReturnUrl());
  375. } else if (WxPayConstants.TradeType.JSAPI.equals(tradeType)) {
  376. return wxPayService.<WxPayMpOrderResult>createOrder(request);
  377. }
  378. throw new BusinessException("不支持此付款方式");
  379. }
  380. public Object payAdapay(Long id, String payChannel, String openId) throws BaseAdaPayException {
  381. List<String> aliChannels = Arrays.asList("alipay", "alipay_qr", "alipay_wap");
  382. List<String> wxChannels = Arrays.asList("wx_pub", "wx_lite");
  383. if (!aliChannels.contains(payChannel) && !wxChannels.contains(payChannel)) {
  384. throw new BusinessException("不支持此渠道");
  385. }
  386. MintOrder order = mintOrderRepo.findById(id).orElseThrow(new BusinessException("订单不存在"));
  387. if (order.getStatus() != MintOrderStatus.NOT_PAID) {
  388. throw new BusinessException("订单状态错误");
  389. }
  390. Map<String, Object> paymentParams = new HashMap<>();
  391. paymentParams.put("order_no", String.valueOf(snowflakeIdWorker.nextId()));
  392. paymentParams.put("pay_amt", order.getGasPrice().setScale(2, RoundingMode.HALF_UP).toPlainString());
  393. paymentParams.put("app_id", adapayProperties.getAppId());
  394. paymentParams.put("pay_channel", payChannel);
  395. paymentParams.put("goods_title", "铸造GAS费");
  396. paymentParams.put("goods_desc", "铸造GAS费");
  397. paymentParams.put("time_expire", DateTimeFormatter.ofPattern("yyyyMMddHHmmss")
  398. .format(LocalDateTime.now().plusMinutes(5)));
  399. paymentParams.put("notify_url", adapayProperties.getNotifyUrl() + "/mintOrder/" + order.getId());
  400. Map<String, Object> expend = new HashMap<>();
  401. paymentParams.put("expend", expend);
  402. if ("wx_pub".equals(payChannel)) {
  403. if (StringUtils.isBlank(openId)) {
  404. throw new BusinessException("缺少openId");
  405. }
  406. expend.put("open_id", openId);
  407. expend.put("limit_pay", "1");
  408. }
  409. Map<String, Object> response;
  410. if ("wx_lite".equals(payChannel)) {
  411. paymentParams.put("adapay_func_code", "wxpay.createOrder");
  412. paymentParams.put("callback_url", generalProperties.getHost() + "/9th/orders");
  413. response = AdapayCommon.requestAdapayUits(paymentParams);
  414. log.info("createOrderResponse {}", JSON.toJSONString(response, SerializerFeature.PrettyFormat));
  415. } else {
  416. response = Payment.create(paymentParams);
  417. log.info("createOrderResponse {}", JSON.toJSONString(response, SerializerFeature.PrettyFormat));
  418. AdapayService.checkSuccess(response);
  419. // adapay 同步
  420. BoundSetOperations<String, Object> ops = redisTemplate.boundSetOps(RedisKeys.ACTIVITY_PAY_RECORD + order.getId());
  421. ops.add(MapUtils.getString(response, "id"));
  422. ops.expire(7, TimeUnit.DAYS);
  423. }
  424. switch (payChannel) {
  425. case "alipay_wap":
  426. case "alipay":
  427. return MapUtils.getString(MapUtils.getMap(response, "expend"), "pay_info");
  428. case "alipay_qr":
  429. return MapUtils.getString(MapUtils.getMap(response, "expend"), "qrcode_url");
  430. case "wx_pub":
  431. JSONObject payParams = JSON.parseObject(MapUtils.getString(MapUtils.getMap(response, "expend"), "pay_info"));
  432. payParams.put("timestamp", payParams.get("timeStamp"));
  433. payParams.remove("timeStamp");
  434. return payParams;
  435. default:
  436. return MapUtils.getMap(response, "expend");
  437. }
  438. }
  439. @Transactional
  440. public void mintNotify(Long orderId, PayMethod payMethod, String transactionId) {
  441. log.info("铸造订单回调 orderId: {}, payMethod: {}, transactionId: {}", orderId, payMethod, transactionId);
  442. if (!getOrderLock(orderId)) {
  443. log.info("铸造订单回调失败 orderId: {} redis锁定, 重新发送到队列", orderId);
  444. rocketMQTemplate.syncSend(generalProperties.getOrderNotifyTopic(),
  445. new OrderNotifyEvent(orderId, payMethod, transactionId, System.currentTimeMillis(),
  446. OrderNotifyEvent.TYPE_MINT_ORDER));
  447. return;
  448. }
  449. try {
  450. MintOrder order = mintOrderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在"));
  451. if (order.getStatus() == MintOrderStatus.NOT_PAID) {
  452. MintActivity activity = mintActivityRepo.findById(order.getMintActivityId())
  453. .orElseThrow(new BusinessException("无活动"));
  454. //活动是否需要审核
  455. if (activity.isAudit()) {
  456. order.setStatus(MintOrderStatus.PENDING);
  457. order.setTransactionId(transactionId);
  458. order.setPayMethod(payMethod);
  459. order.setPayAt(LocalDateTime.now());
  460. mintOrderRepo.save(order);
  461. } else {
  462. this.notify(order, payMethod, transactionId, true);
  463. }
  464. }
  465. } catch (Exception e) {
  466. log.info("铸造订单回调出错 orderId={}", orderId, e);
  467. }
  468. releaseOrderLock(orderId);
  469. }
  470. public void orderAudit(Long orderId, boolean pass) {
  471. MintOrder order = mintOrderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在"));
  472. if (!MintOrderStatus.PENDING.equals(order.getStatus())) {
  473. throw new BusinessException("状态错误");
  474. }
  475. if (pass) {
  476. this.notify(order, null, null, false);
  477. return;
  478. }
  479. this.cancel(order, true);
  480. }
  481. @Transactional
  482. public void notify(MintOrder mintOrder, PayMethod payMethod, String transactionId, boolean saveTransactionId) {
  483. Long orderId = mintOrder.getId();
  484. try {
  485. // MintOrder mintOrder = mintOrderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在"));
  486. List<MintMaterial> materials = mintMaterialRepo.findAllByOrderIdAndDelFalse(orderId);
  487. List<Asset> assets = assetRepo.findAllById(materials
  488. .stream()
  489. .map(MintMaterial::getAssetId)
  490. .collect(Collectors.toList()));
  491. if (saveTransactionId) {
  492. mintOrder.setPayMethod(payMethod);
  493. mintOrder.setTransactionId(transactionId);
  494. mintOrder.setPayAt(LocalDateTime.now());
  495. }
  496. if (mintOrder.isAirDrop()) {
  497. mintOrder.setStatus(MintOrderStatus.AIR_DROP);
  498. MintActivity mintActivity = mintActivityRepo.findById(mintOrder.getMintActivityId()).orElse(null);
  499. if (ObjectUtils.isNotEmpty(mintActivity) && mintActivity.isAutoDrop()) {
  500. User user = userRepo.findById(mintOrder.getUserId()).orElseThrow(new BusinessException("无用户"));
  501. airDropService.create(AirDrop.builder()
  502. .name("铸造活动[" + mintActivity.getName() + "]空投")
  503. .remark(mintOrder.getId().toString())
  504. .type(AirDropType.asset)
  505. .userIds(Collections.singletonList(mintOrder.getUserId()))
  506. .collectionId(mintActivity.getAirDropCollectionId())
  507. .targets(Collections.singletonList(new DropTarget(user.getId(), user.getPhone(), user.getNickname(), 1)))
  508. .build());
  509. mintOrder.setStatus(MintOrderStatus.FINISH);
  510. mintOrderRepo.save(mintOrder);
  511. }
  512. } else {
  513. mintOrder.setStatus(MintOrderStatus.DELIVERY);
  514. }
  515. if (mintOrder.isConsume()) {
  516. User newOwner = userRepo.findByIdAndDelFalse(1435297L).orElseThrow(new BusinessException("无法铸造"));
  517. assets.forEach(asset -> assetService.transfer(asset, asset.getPrice(), newOwner, TransferReason.GIFT, null));
  518. }
  519. mintOrderRepo.save(mintOrder);
  520. } catch (Exception e) {
  521. if (e instanceof BusinessException) {
  522. log.error("铸造订单回调出错 orderId: {} {}", orderId, e.getMessage());
  523. } else {
  524. log.error("铸造订单回调出错 orderId: " + orderId, e);
  525. }
  526. }
  527. }
  528. public void cancel(MintOrder order, boolean refund) {
  529. if (!getOrderLock(order.getId())) {
  530. log.error("订单取消失败 {}, redis锁了", order.getId());
  531. return;
  532. }
  533. try {
  534. // 审核中或未支付订单可以取消
  535. if (!(MintOrderStatus.PENDING == order.getStatus() || MintOrderStatus.NOT_PAID == order.getStatus() || refund)) {
  536. throw new BusinessException("此状态无法取消");
  537. }
  538. List<MintMaterial> materials = mintMaterialRepo.findAllByOrderIdAndDelFalse(order.getId());
  539. List<Asset> assets = assetRepo.findAllById(materials.stream()
  540. .map(MintMaterial::getAssetId)
  541. .collect(Collectors.toList()));
  542. if (order.isConsume()) {
  543. assets.forEach(asset -> {
  544. asset.setStatus(AssetStatus.NORMAL);
  545. assetRepo.save(asset);
  546. });
  547. } else {
  548. Map<Long, Long> privilegeIds = materials.stream()
  549. .collect(Collectors.toMap(MintMaterial::getAssetId, MintMaterial::getPrivilegeId));
  550. assets.forEach(asset -> {
  551. asset.getPrivileges()
  552. .stream()
  553. .filter(p -> p.getId().equals(privilegeIds.get(asset.getId())))
  554. .forEach(p -> {
  555. p.setOpened(false);
  556. p.setOpenTime(null);
  557. p.setOpenedBy(null);
  558. });
  559. assetRepo.save(asset);
  560. });
  561. }
  562. log.info("set normal mintOrder {}", order.getId());
  563. order.setStatus(MintOrderStatus.CANCELLED);
  564. order.setCancelTime(LocalDateTime.now());
  565. mintOrderRepo.save(order);
  566. // 加库存
  567. mintActivityService.increaseStock(order.getMintActivityId(), 1);
  568. log.info("取消订单{}", order.getId());
  569. if (order.getPayMethod() != null && StringUtils.isNotBlank(order.getTransactionId())) {
  570. log.info("退款铸造订单{}", order.getId());
  571. PayMethod payMethod = order.getPayMethod();
  572. if (PayMethod.ALIPAY == payMethod) {
  573. if (StringUtils.length(order.getTransactionId()) == 28) {
  574. payMethod = PayMethod.HMPAY;
  575. } else if (StringUtils.length(order.getTransactionId()) == 30) {
  576. payMethod = PayMethod.SANDPAY;
  577. }
  578. }
  579. try {
  580. switch (payMethod) {
  581. case HMPAY:
  582. orderPayService.refund(order.getId().toString(), order.getTransactionId(),
  583. order.getGasPrice(), Constants.PayChannel.HM);
  584. log.info("退款成功");
  585. break;
  586. case SANDPAY:
  587. orderPayService.refund(order.getId().toString(), order.getTransactionId(),
  588. order.getGasPrice(), Constants.PayChannel.SAND);
  589. log.info("退款成功");
  590. break;
  591. case PAYEASE:
  592. orderPayService.refund(order.getTransactionId(), order.getTransactionId(),
  593. order.getGasPrice(), Constants.PayChannel.PE);
  594. }
  595. } catch (Exception e) {
  596. log.error("铸造订单退款失败 {} ", order.getId(), e);
  597. }
  598. }
  599. } catch (Exception e) {
  600. log.error("订单取消错误 orderId: " + order.getId(), e);
  601. }
  602. releaseOrderLock(order.getId());
  603. }
  604. public boolean getOrderLock(Long orderId) {
  605. BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(RedisKeys.MINT_ORDER_LOCK + orderId);
  606. Boolean flag = ops.setIfAbsent(1, 1, TimeUnit.DAYS);
  607. return Boolean.TRUE.equals(flag);
  608. }
  609. public void releaseOrderLock(Long orderId) {
  610. redisTemplate.delete(RedisKeys.MINT_ORDER_LOCK + orderId);
  611. }
  612. }