Browse Source

Merge branch 'master' of http://git.izouma.com/xiongzhu/9th

panhui 4 years ago
parent
commit
3b64854f70

+ 5 - 0
pom.xml

@@ -80,6 +80,11 @@
             <artifactId>spring-boot-starter-aop</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-activemq</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>com.github.ben-manes.caffeine</groupId>
             <artifactId>caffeine</artifactId>

+ 3 - 0
src/main/java/com/izouma/nineth/domain/Order.java

@@ -94,6 +94,9 @@ public class Order extends BaseEntity {
     @ApiModelProperty("支付时间")
     private LocalDateTime payTime;
 
+    @ApiModelProperty("取消时间")
+    private LocalDateTime cancelTime;
+
     @ApiModelProperty("交易hash")
     private String txHash;
 

+ 5 - 0
src/main/java/com/izouma/nineth/repo/OrderRepo.java

@@ -1,12 +1,15 @@
 package com.izouma.nineth.repo;
 
 import com.izouma.nineth.domain.Order;
+import com.izouma.nineth.enums.OrderStatus;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 
 import javax.transaction.Transactional;
+import java.time.LocalDateTime;
+import java.util.List;
 import java.util.Optional;
 
 public interface OrderRepo extends JpaRepository<Order, Long>, JpaSpecificationExecutor<Order> {
@@ -16,4 +19,6 @@ public interface OrderRepo extends JpaRepository<Order, Long>, JpaSpecificationE
     void softDelete(Long id);
 
     Optional<Order> findByIdAndDelFalse(Long id);
+
+    List<Order> findByStatusAndCreatedAtBeforeAndDelFalse(OrderStatus status, LocalDateTime time);
 }

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

@@ -1,9 +1,6 @@
 package com.izouma.nineth.service;
 
-import com.izouma.nineth.domain.Asset;
-import com.izouma.nineth.domain.Collection;
-import com.izouma.nineth.domain.Order;
-import com.izouma.nineth.domain.User;
+import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.NFT;
 import com.izouma.nineth.dto.NFTAccount;
 import com.izouma.nineth.dto.PageQuery;
@@ -74,4 +71,43 @@ public class AssetService {
         }
         applicationContext.publishEvent(new CreateAssetEvent(this, false, order, null));
     }
+
+    @Async
+    public void createAsset(Order order, BlindBoxItem winItem) {
+        User user = userRepo.findById(order.getUserId()).orElseThrow(new BusinessException("用户不存在"));
+        if (StringUtils.isEmpty(user.getPublicKey())) {
+            NFTAccount account = nftService.createAccount(user.getUsername());
+            user.setNftAccount(account.getAccountId());
+            user.setKmsId(account.getAccountKmsId());
+            user.setPublicKey(account.getPublicKey());
+            userRepo.save(user);
+        }
+        try {
+            NFT nft = nftService.createToken(user.getNftAccount());
+            if (nft != null) {
+                Asset asset = Asset.builder()
+                        .userId(user.getId())
+                        .orderId(order.getId())
+                        .minter(winItem.getMinter())
+                        .minterId(winItem.getMinterId())
+                        .minterAvatar(winItem.getMinterAvatar())
+                        .name(winItem.getName())
+                        .pic(winItem.getPics())
+                        .properties(winItem.getProperties())
+                        .tokenId(nft.getTokenId())
+                        .blockNumber(nft.getBlockNumber())
+                        .txHash(nft.getTxHash())
+                        .gasUsed(nft.getGasUsed())
+                        .price(order.getPrice())
+                        .status(AssetStatus.NORMAL)
+                        .build();
+                assetRepo.save(asset);
+                applicationContext.publishEvent(new CreateAssetEvent(this, true, order, asset));
+                return;
+            }
+        } catch (Exception e) {
+            log.error("创建token失败", e);
+        }
+        applicationContext.publishEvent(new CreateAssetEvent(this, false, order, null));
+    }
 }

+ 69 - 11
src/main/java/com/izouma/nineth/service/OrderService.java

@@ -38,6 +38,7 @@ import org.apache.http.client.utils.URLEncodedUtils;
 import org.springframework.context.event.EventListener;
 import org.springframework.core.env.Environment;
 import org.springframework.data.domain.Page;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.ui.Model;
 
@@ -120,6 +121,7 @@ public class OrderService {
     public void payOrderAlipay(Long id, Model model) {
         try {
             Order order = orderRepo.findByIdAndDelFalse(id).orElseThrow(new BusinessException("订单不存在"));
+
             if (order.getStatus() != OrderStatus.NOT_PAID) {
                 throw new BusinessException("订单状态错误");
             }
@@ -218,6 +220,8 @@ public class OrderService {
         if (order.getStatus() == OrderStatus.NOT_PAID) {
             if (order.getType() == CollectionType.BLIND_BOX) {
                 List<BlindBoxItem> items = blindBoxItemRepo.findByBlindBoxId(order.getCollectionId());
+
+
                 Map<BlindBoxItem, Range<Integer>> randomRange = new HashMap<>();
                 int c = 0, sum = 0;
                 for (BlindBoxItem item : items) {
@@ -226,35 +230,52 @@ public class OrderService {
                     sum += item.getStock();
                 }
 
-                boolean win = false;
                 int retry = 0;
                 BlindBoxItem winItem = null;
                 while (winItem == null) {
+                    retry++;
                     int rand = RandomUtils.nextInt(0, sum + 1);
                     for (Map.Entry<BlindBoxItem, Range<Integer>> entry : randomRange.entrySet()) {
                         BlindBoxItem item = entry.getKey();
                         Range<Integer> range = entry.getValue();
                         if (rand >= range.getMinimum() && rand < range.getMaximum()) {
+                            int total = items.stream().filter(i -> !i.isRare())
+                                    .mapToInt(BlindBoxItem::getTotal).sum();
+                            int stock = items.stream().filter(i -> !i.isRare())
+                                    .mapToInt(BlindBoxItem::getStock).sum();
                             if (item.isRare()) {
-                                int total = items.stream().filter(i -> !i.isRare())
-                                        .mapToInt(BlindBoxItem::getTotal).sum();
-                                int stock = items.stream().filter(i -> !i.isRare())
-                                        .mapToInt(BlindBoxItem::getStock).sum();
-
                                 double nRate = stock / (double) total;
+                                double rRate = (item.getStock() - 1) / (double) item.getTotal();
+
+                                if (Math.abs(nRate - rRate) < (1 / (double) item.getTotal()) || retry > 1 || rRate == 0) {
+                                    if (!(nRate > 0.1 && item.getStock() == 1)) {
+                                        winItem = item;
+                                    }
+                                }
+                            } else {
+                                double nRate = (stock - 1) / (double) total;
                                 double rRate = item.getStock() / (double) item.getTotal();
 
-                                if (Math.abs(nRate - rRate) < 0.05 || retry > 1) {
+                                if (Math.abs(nRate - rRate) < 0.2 || retry > 1 || nRate == 0) {
                                     winItem = item;
-                                } else {
-                                    retry++;
                                 }
-                            } else {
-                                winItem = item;
                             }
                         }
                     }
+
+                    if (retry > 100 && winItem == null) {
+                        throw new BusinessException("盲盒抽卡失败");
+                    }
                 }
+                winItem.setStock(winItem.getStock() - 1);
+                winItem.setSale(winItem.getSale() + 1);
+
+                order.setStatus(OrderStatus.PROCESSING);
+                order.setPayTime(LocalDateTime.now());
+                order.setTransactionId(MapUtils.getString(params, "trade_no"));
+                order.setPayMethod(PayMethod.ALIPAY);
+                orderRepo.save(order);
+                assetService.createAsset(order, winItem);
 
 
             } else {
@@ -265,6 +286,8 @@ public class OrderService {
                 orderRepo.save(order);
                 assetService.createAsset(order);
             }
+        } else if (order.getStatus() == OrderStatus.CANCELLED) {
+
         }
     }
 
@@ -283,4 +306,39 @@ public class OrderService {
             log.error("创建asset失败");
         }
     }
+
+    public void cancel(Long id) {
+        Order order = orderRepo.findById(id).orElseThrow(new BusinessException("订单不存在"));
+        cancel(order);
+    }
+
+    public void cancel(Order order) {
+        if (order.getStatus() != OrderStatus.NOT_PAID) {
+            throw new BusinessException("已支付订单无法取消");
+        }
+        Collection collection = collectionRepo.findById(order.getCollectionId())
+                .orElseThrow(new BusinessException("藏品不存在"));
+        User minter = userRepo.findById(collection.getMinterId()).orElseThrow(new BusinessException("铸造者不存在"));
+
+        collection.setSale(collection.getSale() - 1);
+        collection.setStock(collection.getStock() + 1);
+        collectionRepo.save(collection);
+
+        minter.setSales(minter.getSales() - 1);
+        userRepo.save(minter);
+
+        order.setStatus(OrderStatus.CANCELLED);
+        order.setCancelTime(LocalDateTime.now());
+        orderRepo.save(order);
+    }
+
+    @Scheduled(fixedRate = 60000)
+    public void batchCancel() {
+        List<Order> orders = orderRepo.findByStatusAndCreatedAtBeforeAndDelFalse(OrderStatus.NOT_PAID,
+                LocalDateTime.now().minusMinutes(5));
+        orders.stream().parallel().forEach(this::cancel);
+    }
+
+    public void refundCancelled(Order order) {
+    }
 }

+ 1 - 0
src/main/nine-space/public/index.html

@@ -14,6 +14,7 @@
     <meta name="x5-orientation" content="portrait" />
     <meta name="full-screen" content="yes" />
     <meta name="x5-fullscreen" content="true" />
+    <meta name="theme-color" content="#000000" />
     <title><%= htmlWebpackPlugin.options.title %></title>
     <style>
       html,