Explorar o código

Merge branch 'master' of http://git.izouma.com/xiongzhu/raex_back into dev-meta-dz

 Conflicts:
	src/main/java/com/izouma/nineth/repo/AssetRepo.java
LH %!s(int64=3) %!d(string=hai) anos
pai
achega
e0204e1eec

+ 2 - 0
src/main/java/com/izouma/nineth/config/RedisKeys.java

@@ -21,6 +21,8 @@ public class RedisKeys {
 
     public static final String ORDER_LOCK = "orderLock::";
 
+    public static final String DOMAIN_LOCK = "domainLock::";
+
     public static final String MINT_ACTIVITY_STOCK = "mintActivityStock::";
 
     public static final String MINT_ORDER_LOCK = "mintOrderLock::";

+ 2 - 0
src/main/java/com/izouma/nineth/domain/DomainOrder.java

@@ -76,4 +76,6 @@ public class DomainOrder extends BaseEntity {
     private Long years;
 
     private LocalDateTime endTime;
+
+    private String result;
 }

+ 2 - 1
src/main/java/com/izouma/nineth/enums/AssetStatus.java

@@ -11,7 +11,8 @@ public enum AssetStatus {
     AUCTION_TRADING("拍卖中"),
     AUCTIONED("已拍卖"),
     DESTROYED("已销毁"),
-    DESTROYING("销毁中")
+    DESTROYING("销毁中"),
+    PENDING("元域名审核")
     ;
 
     private final String description;

+ 2 - 2
src/main/java/com/izouma/nineth/repo/AssetRepo.java

@@ -32,7 +32,7 @@ public interface AssetRepo extends JpaRepository<Asset, Long>, JpaSpecificationE
 
     List<Asset> findAllByCollectionIdInAndStatusIn(List<Long> collectionId, Iterable<AssetStatus> statuses);
 
-    List<Asset> findAllByCollectionIdAndStatusInAndUserId(Long collectionId, Iterable<AssetStatus> statuses,Long userId);
+    List<Asset> findAllByCollectionIdAndStatusInAndUserId(Long collectionId, Iterable<AssetStatus> statuses, Long userId);
 
     List<Asset> findByCreatedAtBefore(LocalDateTime localDateTime);
 
@@ -169,5 +169,5 @@ public interface AssetRepo extends JpaRepository<Asset, Long>, JpaSpecificationE
     @Transactional
     void openTrade(String name);
 
-    Long findByNameLike(String name);
+    Asset findFirstByNameAndStatus(String name, AssetStatus status);
 }

+ 12 - 0
src/main/java/com/izouma/nineth/repo/DomainOrderRepo.java

@@ -26,6 +26,10 @@ public interface DomainOrderRepo extends JpaRepository<DomainOrder, Long>, JpaSp
 
     Page<DomainOrder> findAllByOrderStatusOrderByCreatedAtDesc(OrderStatus status, Pageable pageable);
 
+    DomainOrder findByDomainNameAndOrderStatus(String name, OrderStatus status);
+
+    List<DomainOrder> findAllByStatusAndCreatedAtBeforeAndOrderStatus(CollectionStatus status, LocalDateTime endTime, OrderStatus orderStatus);
+
     List<DomainOrder> findAllByPicNameInAndOrderStatus(List<String> strings, OrderStatus status);
 
     Integer countAllByDomainNameEqualsAndOrderStatusNot(String name, OrderStatus status);
@@ -37,4 +41,12 @@ public interface DomainOrderRepo extends JpaRepository<DomainOrder, Long>, JpaSp
 
     @Query("select sum(price) from DomainOrder where createdAt <= ?2 and createdAt >= ?1 and orderStatus = 'FINISH'")
     BigDecimal sumToday(LocalDateTime start, LocalDateTime end);
+
+    @Query(nativeQuery = true, value = "SELECT pic_name from domain_order where order_status ='FINISH' GROUP BY pic_name  having count(pic_name) > 1")
+    List<String> getDomainOrder();
+
+    List<DomainOrder> findAllByOrderStatusAndPicNameOrderByCreatedAtAsc(OrderStatus orderStatus, String pic);
+
+    @Query(nativeQuery = true, value = "select domain_name from domain_order where pic_name regexp '^\\\\d{2}$' and order_status = 'FINISH' order by pic_name")
+    List<String> findThreeNumber();
 }

+ 4 - 0
src/main/java/com/izouma/nineth/service/AssetService.java

@@ -265,6 +265,7 @@ public class AssetService {
         asset.setNumber(number);
         asset.setOrderId(orderId);
         asset.setPrice(price);
+        asset.setStatus(AssetStatus.PENDING);
         if (StringUtils.isNumeric(domainOrder.getPicName())) {
             if (domainOrder.getPicName().length() < 6) {
                 asset.setPrefixName("RIDN" + domainOrder.getPicName().length());
@@ -374,6 +375,9 @@ public class AssetService {
         }
         winItem.setCollection(collection);
         Asset asset = Asset.create(winItem, user, holdDays);
+        if (collection.getType().equals(CollectionType.DOMAIN)) {
+            asset.setType(CollectionType.DOMAIN);
+        }
         asset.setTokenId(TokenUtils.genTokenId());
         asset.setNumber(number);
         asset.setOasisId(winItem.getOasisId());

+ 83 - 4
src/main/java/com/izouma/nineth/service/DomainOrderService.java

@@ -3,14 +3,16 @@ package com.izouma.nineth.service;
 import com.alibaba.excel.util.StringUtils;
 import com.alibaba.fastjson.JSONArray;
 import com.google.zxing.WriterException;
+import com.izouma.nineth.config.GeneralProperties;
+import com.izouma.nineth.config.RedisKeys;
+import com.izouma.nineth.domain.Asset;
 import com.izouma.nineth.domain.DomainOrder;
 import com.izouma.nineth.domain.FileObject;
 import com.izouma.nineth.domain.User;
 import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.dto.excel.DomainCountDTO;
-import com.izouma.nineth.enums.CollectionStatus;
-import com.izouma.nineth.enums.OrderStatus;
-import com.izouma.nineth.enums.PayMethod;
+import com.izouma.nineth.enums.*;
+import com.izouma.nineth.event.OrderNotifyEvent;
 import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.AssetRepo;
 import com.izouma.nineth.repo.DomainOrderRepo;
@@ -19,16 +21,20 @@ import com.izouma.nineth.service.storage.StorageService;
 import com.izouma.nineth.utils.ImageUtils;
 import com.izouma.nineth.utils.JpaUtils;
 import com.izouma.nineth.utils.SecurityUtils;
+import com.sun.xml.bind.v2.TODO;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.data.annotation.Transient;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.domain.Sort;
+import org.springframework.data.redis.core.BoundValueOperations;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 
 import javax.imageio.ImageIO;
@@ -43,6 +49,7 @@ import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -62,6 +69,9 @@ public class DomainOrderService {
     private AssetRepo                     assetRepo;
     private RedisTemplate<String, Object> redisTemplate;
     private CacheService                  cacheService;
+    private UserBalanceService            userBalanceService;
+    private GeneralProperties             generalProperties;
+    private RocketMQTemplate              rocketMQTemplate;
 
     public Page<DomainOrder> all(PageQuery pageQuery) {
         return domainOrderRepo
@@ -298,6 +308,13 @@ public class DomainOrderService {
 
     @Transient
     public void notify(Long id, PayMethod payMethod, String transactionId) throws FontFormatException, IOException, WriterException {
+        // 取消订单与订单回调不能同时进行,需要抢锁
+        if (!getOrderLock(id)) {
+            log.info("订单回调失败 orderId: {} redis锁定, 重新发送到队列", id);
+            rocketMQTemplate.syncSend(generalProperties.getOrderNotifyTopic(),
+                    new OrderNotifyEvent(id, payMethod, transactionId, System.currentTimeMillis()));
+            return;
+        }
         DomainOrder domainOrder = domainOrderRepo.findById(id).orElseThrow(new BusinessException("未找到星图"));
         if (!domainOrder.getOrderStatus().equals(OrderStatus.NOT_PAID)) {
             throw new BusinessException("订单已经处理");
@@ -317,21 +334,30 @@ public class DomainOrderService {
         domainOrder.setPayMethod(payMethod);
         domainOrder.setPic(Collections.singletonList(fileObject));
         domainOrder.setTransactionId(transactionId);
-        domainOrder.setStatus(CollectionStatus.SUCCESS);
+//        domainOrder.setStatus(CollectionStatus.SUCCESS);
         domainOrder.setCreateAssetId(createAsset(domainOrder));
         domainOrder.setEndTime(LocalDateTime.now().plusYears(domainOrder.getYears()));
         domainOrderRepo.save(domainOrder);
 
         rockRecordService.addRock(domainOrder.getUserId(), domainOrder.getPrice(), "购买");
+
+        releaseOrderLock(id);
     }
 
     public void cancel(DomainOrder domainOrder) {
+        log.info("尝试取消订单 {}", domainOrder.getId());
+        // 取消订单与订单回调不能同时进行,需要抢锁
+        if (!getOrderLock(domainOrder.getId())) {
+            log.error("订单取消失败 {}, redis锁了", domainOrder.getId());
+            return;
+        }
         domainOrder.setOrderStatus(OrderStatus.CANCELLED);
         domainOrder.setStatus(CollectionStatus.FAIL);
         if (domainOrder.getPicName().length() < 5) {
             decreaseCount(domainOrder);
         }
         domainOrderRepo.save(domainOrder);
+        releaseOrderLock(domainOrder.getId());
     }
 
     public Long createAsset(DomainOrder domainOrder) {
@@ -464,4 +490,57 @@ public class DomainOrderService {
         return jsonArray.toJavaList(DomainCountDTO.class);
     }
 
+    // 获取订单锁,有效时间1小时
+    public boolean getOrderLock(Long orderId) {
+        BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(RedisKeys.DOMAIN_LOCK + orderId);
+        Boolean flag = ops.setIfAbsent(1, 1, TimeUnit.HOURS);
+        return Boolean.TRUE.equals(flag);
+    }
+
+    // 释放订单锁
+    public void releaseOrderLock(Long orderId) {
+        redisTemplate.delete(RedisKeys.DOMAIN_LOCK + orderId);
+    }
+
+    public void pass(Long id) {
+        domainOrderRepo.findById(id).ifPresent(domainOrder -> {
+            domainOrder.setStatus(CollectionStatus.SUCCESS);
+            assetRepo.findById(domainOrder.getCreateAssetId()).ifPresent(asset1 -> {
+                asset1.setStatus(AssetStatus.NORMAL);
+                domainOrderRepo.save(domainOrder);
+                assetRepo.save(asset1);
+            });
+        });
+    }
+
+    public void deny(Long id, String result) {
+        domainOrderRepo.findById(id).ifPresent(domainOrder -> {
+            domainOrder.setStatus(CollectionStatus.FAIL);
+            domainOrder.setOrderStatus(OrderStatus.CANCELLED);
+            domainOrder.setResult(result);
+            assetRepo.findById(domainOrder.getCreateAssetId()).ifPresent(asset1 -> {
+                asset1.setStatus(AssetStatus.DESTROYED);
+                domainOrderRepo.save(domainOrder);
+                assetRepo.save(asset1);
+            });
+            //退款
+            userBalanceService.addBalance(domainOrder.getUserId(), domainOrder.getPrice(), domainOrder
+                    .getId(), BalanceType.REFUND);
+        });
+    }
+
+    @Scheduled(cron = "0 0/60 9-20 * * ?")
+    public void batchPass() {
+        LocalDateTime lastTime = LocalDateTime.now().minusHours(72L);
+        List<DomainOrder> domainOrders = domainOrderRepo
+                .findAllByStatusAndCreatedAtBeforeAndOrderStatus(CollectionStatus.PENDING, lastTime, OrderStatus.FINISH);
+        domainOrders.forEach(domainOrder -> {
+            try {
+                pass(domainOrder.getId());
+            } catch (Exception e) {
+                log.info("自动通过出错" + domainOrder.getDomainName());
+            }
+        });
+    }
+
 }

+ 12 - 0
src/main/java/com/izouma/nineth/web/DomainOrderController.java

@@ -83,5 +83,17 @@ public class DomainOrderController extends BaseController {
         List<DomainOrder> data = all(pageQuery).getContent();
         ExcelUtils.export(response, data);
     }
+
+    @PostMapping("/pass")
+    @PreAuthorize("hasRole('ADMIN')")
+    public void pass(Long id) {
+         domainOrderService.pass(id);
+    }
+
+    @PostMapping("/deny")
+    @PreAuthorize("hasRole('ADMIN')")
+    public void deny(Long id) {
+        domainOrderService.deny(id,"系统审核不通过");
+    }
 }