OrderStatusMaintenanceTask.java 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package modules.order;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.jfinal.kit.StrKit;
  4. import com.jfinal.plugin.activerecord.Db;
  5. import com.sun.org.apache.xpath.internal.operations.Or;
  6. import common.jfinal.AppConfig;
  7. import common.model.Nftt;
  8. import common.model.Order;
  9. import common.model.OrderLog;
  10. import common.model.User;
  11. import common.utils.bsn.BsnSDK;
  12. import modules.user.UserService;
  13. import modules.user.UserTeamShareTask;
  14. import org.slf4j.Logger;
  15. import org.slf4j.LoggerFactory;
  16. import java.util.List;
  17. import java.util.concurrent.TimeUnit;
  18. public class OrderStatusMaintenanceTask implements Runnable {
  19. private static final Logger LOGGER = LoggerFactory.getLogger(OrderStatusMaintenanceTask.class);
  20. // 通过构造函数注入
  21. OrderService orderService;
  22. UserService userService;
  23. // 任务是否应该停止的标志
  24. private volatile boolean running = true; // 使用 volatile 确保多线程可见性
  25. public OrderStatusMaintenanceTask(OrderService orderService, UserService userService) {
  26. this.orderService = orderService;
  27. this.userService = userService;
  28. LOGGER.info("OrderStatusMaintenanceTask 实例已创建,注入 OrderService。{}", orderService.hashCode());
  29. }
  30. @Override
  31. public void run() {
  32. LOGGER.info("OrderStatusMaintenanceTask 后台任务开始运行...");
  33. while (running) { // 循环直到收到停止指令
  34. try {
  35. // 每次循环后休眠一段时间,避免CPU空转,并控制检查频率
  36. Thread.sleep(TimeUnit.SECONDS.toMillis(10)); // 每 10 秒检查一次
  37. // 只处理已支付但未确权的
  38. String sql = "SELECT id FROM t_order" +
  39. " WHERE order_status=40";
  40. doNftTransfer(Order.dao.find(sql));
  41. } catch (InterruptedException e) {
  42. LOGGER.warn("OrderStatusMaintenanceTask 因中断而停止。");
  43. Thread.currentThread().interrupt(); // 重新设置中断状态
  44. running = false; // 退出循环
  45. } catch (Exception e) {
  46. // 捕获所有其他异常,记录日志,但保持线程继续运行
  47. LOGGER.error("OrderStatusMaintenanceTask 执行异常: {}", e.getMessage(), e);
  48. // 可以在这里添加告警,或在短时间后重试
  49. try {
  50. Thread.sleep(TimeUnit.SECONDS.toMillis(5)); // 发生错误时短暂休眠,避免错误日志刷屏
  51. } catch (InterruptedException ie) {
  52. Thread.currentThread().interrupt();
  53. running = false;
  54. }
  55. }
  56. }
  57. LOGGER.info("OrderStatusMaintenanceTask 后台任务已停止运行。");
  58. }
  59. private void doNftTransfer(List<Order> orderList) throws InterruptedException {
  60. // 未给用户转账的进行转账
  61. for (Order o : orderList) {
  62. // 1秒最多检查1个订单,防止超频
  63. Thread.sleep(TimeUnit.SECONDS.toMillis(1));
  64. // 使用事务锁定
  65. Db.tx(() -> {
  66. Order order = Order.dao.findFirst("SELECT * FROM t_order WHERE id=? FOR UPDATE", o.getId());
  67. User user = User.dao.findById(order.getUserId());
  68. // 已经交付完成或交付失败就不用看状态了
  69. if (order.getOrderStatus() == OrderController.OrderStatus.COMPLETED.code
  70. || order.getOrderStatus() == OrderController.OrderStatus.CANCELED.code
  71. || order.getOrderStatus() == OrderController.OrderStatus.REFUNDED.code) {
  72. return true;
  73. }
  74. // 已经执行过转账的查看是否确权,查看状态
  75. if (StrKit.notBlank(order.getBsnTransferCode())) {
  76. try {
  77. JSONObject searchResponse = BsnSDK.search(order.getBsnTransferCode());
  78. if (searchResponse.getInteger("code") == 0) {
  79. JSONObject data = searchResponse.getJSONObject("data");
  80. // status为1时才是交付成功,其它要么是pending要么是交付失败
  81. if (data.getInteger("status") == 1) {
  82. OrderLog log = new OrderLog();
  83. log.set("order_id", order.getId());
  84. log.set("from_status", order.getOrderStatus());
  85. log.set("to_status", OrderController.OrderStatus.COMPLETED.code);
  86. log.set("operator_id", 0);
  87. log.set("operator_type", 3);
  88. log.set("change_reason", "系统确权成功");
  89. log.set("create_time", System.currentTimeMillis());
  90. log.save();
  91. order.setOrderStatus(OrderController.OrderStatus.COMPLETED.code);// 该笔订单已完成
  92. order.setBsnTransferStatus(searchResponse.toJSONString());
  93. order.setNftMintStatus(4);// nft已确权转移
  94. order.setDeliveryStatus(1);// 交付成功
  95. order.setDeliveryTime(System.currentTimeMillis());
  96. order.setRefundStatus(0);
  97. order.setClosedTime(System.currentTimeMillis());
  98. order.setUpdateTime(System.currentTimeMillis());
  99. order.update();
  100. AppConfig.LOGGER.info("该订单已确权:{}", order);
  101. // 该用户如果没有标记为有效账户进行标记
  102. if (user.getIsEffective() == 0) {
  103. user.setIsEffective(1);
  104. user.setEffectiveTime(System.currentTimeMillis());
  105. user.update();
  106. }
  107. // 异步执行分润过程
  108. AppConfig.TaskScheduler.submit(new UserTeamShareTask(order, userService));
  109. }
  110. // status为2时是交付失败,自动执行退款
  111. if (data.getInteger("status") == 2) {
  112. // 记录日志
  113. OrderLog log = new OrderLog();
  114. log.set("order_id", order.getId());
  115. log.set("from_status", order.getOrderStatus());
  116. log.set("to_status", OrderController.OrderStatus.REFUNDED.code);
  117. log.set("operator_id", 0);
  118. log.set("operator_type", 3);
  119. log.set("change_reason", "系统确权失败");
  120. log.set("create_time", System.currentTimeMillis());
  121. log.save();
  122. // 更新用户余额
  123. user.setBalance(user.getBalance() + order.getTotalPrice());
  124. user.update();
  125. // 更新订单状态
  126. order.setOrderStatus(OrderController.OrderStatus.REFUNDED.code);// 该笔订单已退款
  127. order.setBsnTransferStatus(searchResponse.toJSONString());
  128. order.setNftMintStatus(2);// nft是铸造成功了的,但是确权失败
  129. order.setDeliveryStatus(2);// 交付失败
  130. order.setRefundStatus(2);// 退款成功
  131. order.setClosedTime(System.currentTimeMillis());
  132. order.setUpdateTime(System.currentTimeMillis());
  133. order.update();
  134. AppConfig.LOGGER.error("该订单确权失败:{}", order);
  135. }
  136. } else {
  137. throw new RuntimeException(searchResponse.toJSONString());
  138. }
  139. } catch (Exception e) {
  140. AppConfig.LOGGER.error("查询转账信息执行失败:{}", e.getMessage());
  141. }
  142. }
  143. // 未转账的先进行转账
  144. else {
  145. Nftt nftt = Nftt.dao.findById(order.getNfttId());
  146. // 订单是预购订单并且:如果还未转为正式销售的nft先不转帐
  147. if (order.getOrderType() == 2 && System.currentTimeMillis() < nftt.getBuyingStartTime()) {
  148. return true;
  149. }
  150. // 转账参数整理
  151. String address = user.getBsnAccountAddress();
  152. int quantity = order.getQuantity();
  153. String tokenId = nftt.getBsnTokenId();
  154. String bsnTransferCode = "DLTBH_ORDER_" + order.getId();
  155. try {
  156. JSONObject transferResponse = BsnSDK.sendNft(address, quantity, tokenId, bsnTransferCode);
  157. if (transferResponse.getInteger("code") == 0) {
  158. order.setBsnTransferCode(bsnTransferCode);
  159. order.update();
  160. } else {
  161. throw new RuntimeException(transferResponse.toJSONString());
  162. }
  163. } catch (Exception e) {
  164. AppConfig.LOGGER.error("转账执行失败:{}", e.getMessage());
  165. }
  166. }
  167. return true;
  168. });
  169. }
  170. }
  171. }