xiongzhu 4 tahun lalu
induk
melakukan
c504a17833

+ 52 - 0
src/main/java/com/izouma/nineth/repo/CollectionRepo.java

@@ -1,6 +1,9 @@
 package com.izouma.nineth.repo;
 
 import com.izouma.nineth.domain.Collection;
+import com.izouma.nineth.domain.CollectionProperty;
+import com.izouma.nineth.domain.FileObject;
+import com.izouma.nineth.domain.Privilege;
 import com.izouma.nineth.dto.RecommendCollection;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.CachePut;
@@ -23,6 +26,16 @@ public interface CollectionRepo extends JpaRepository<Collection, Long>, JpaSpec
     @CacheEvict(value = {"collection", "recommend"}, allEntries = true)
     void softDelete(Long id);
 
+    @Transactional
+    @Modifying
+    @Query("update Collection c set c.onShelf = ?2, c.salable = ?3, c.startTime = ?4, " +
+            "c.scheduleSale = ?5, c.sort = ?6, c.detail = ?7, c.privileges = ?8, " +
+            "c.properties = ?9, c.model3d = ?10 where c.id = ?1")
+    @CacheEvict(value = {"collection", "recommend"}, allEntries = true)
+    void update(@Nonnull Long id, boolean onShelf, boolean salable, LocalDateTime startTime,
+                boolean schedule, int sort, String detail, List<Privilege> privileges,
+                List<CollectionProperty> properties, FileObject model3d);
+
     @Cacheable("collection")
     Optional<Collection> findById(Long id);
 
@@ -46,4 +59,43 @@ public interface CollectionRepo extends JpaRepository<Collection, Long>, JpaSpec
     @Query("select new com.izouma.nineth.dto.RecommendCollection(c,r) from Collection c join Recommend r on c.id = r.collectionId " +
             "where c.del = false and c.onShelf = true and r.type = ?1 order by r.sort desc")
     List<RecommendCollection> recommend(String type);
+
+    @Transactional
+    @Modifying
+    @Query("update Collection c set c.onShelf = true, c.salable = true where c.id = ?1")
+    @CacheEvict(value = "collection", key = "#id")
+    void scheduleOnShelf(Long id);
+
+    @Transactional
+    @Modifying
+    @Query("update Collection c set c.currentNumber = COALESCE(c.currentNumber, 0) + ?2 where c.id = ?1")
+    @CacheEvict(value = "collection", key = "#id")
+    void increaseNumber(Long id, int d);
+
+    @Transactional
+    @Modifying
+    @Query("update Collection c set c.sale = COALESCE(c.sale, 0) + ?2 where c.id = ?1")
+    @CacheEvict(value = "collection", key = "#id")
+    void increaseSale(Long id, int d);
+
+    @Transactional
+    @Modifying
+    @Query("update Collection c set c.stock = COALESCE(c.stock, 0) + ?2 where c.id = ?1")
+    @CacheEvict(value = "collection", key = "#id")
+    void increaseStock(Long id, int d);
+
+    @Transactional
+    @Modifying
+    @Query("update Collection c set c.total = COALESCE(c.total, 0) + ?2 where c.id = ?1")
+    @CacheEvict(value = "collection", key = "#id")
+    void increaseTotal(Long id, int d);
+
+    @Transactional
+    @Modifying
+    @Query("update Collection c set c.onShelf = ?2 where c.id = ?1")
+    @CacheEvict(value = "collection", key = "#id")
+    void setOnShelf(Long id, boolean onShelf);
+
+    @Query("select c.currentNumber from Collection c where c.id = ?1")
+    Optional<Integer> getCurrentNumber(Long id);
 }

+ 36 - 13
src/main/java/com/izouma/nineth/service/AssetMintService.java

@@ -8,7 +8,6 @@ import com.izouma.nineth.dto.NFTAccount;
 import com.izouma.nineth.event.CreateAssetEvent;
 import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.AssetRepo;
-import com.izouma.nineth.repo.TokenHistoryRepo;
 import com.izouma.nineth.repo.UserRepo;
 import io.ipfs.api.IPFS;
 import io.ipfs.api.MerkleNode;
@@ -18,11 +17,10 @@ import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.context.ApplicationContext;
-import org.springframework.core.env.Environment;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import java.io.File;
-import java.util.concurrent.LinkedBlockingQueue;
 
 @Service
 @Slf4j
@@ -32,11 +30,10 @@ public class AssetMintService {
     private UserRepo           userRepo;
     private NFTService         nftService;
     private ApplicationContext applicationContext;
-    private TokenHistoryRepo   tokenHistoryRepo;
-    private Environment        env;
 
-    public void mint(Asset asset, Long historyId) {
-        User user = userRepo.findById(asset.getUserId()).orElseThrow(new BusinessException("用户不存在"));
+    @Async
+    public void mint(Long assetId, Long userId) {
+        User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
         if (StringUtils.isEmpty(user.getPublicKey())) {
             NFTAccount account = nftService.createAccount(user.getUsername() + "_");
             user.setNftAccount(account.getAccountId());
@@ -45,7 +42,8 @@ public class AssetMintService {
             userRepo.save(user);
         }
         try {
-            NFT nft = nftService.createToken(user.getNftAccount());
+            Asset asset = assetRepo.findById(assetId).orElseThrow(new BusinessException("asset不存在"));
+            NFT nft = nftService.createToken(user.getNftAccount(), asset.getTokenId());
             if (nft != null) {
                 asset.setTokenId(nft.getTokenId());
                 asset.setBlockNumber(nft.getBlockNumber());
@@ -55,14 +53,39 @@ public class AssetMintService {
                     asset.setIpfsUrl(ipfsUpload(asset.getPic().get(0).getUrl()));
                 }
                 assetRepo.save(asset);
+                applicationContext.publishEvent(new CreateAssetEvent(this, true, asset));
+            } else {
+                log.error("铸造失败");
+            }
+        } catch (Exception e) {
+            log.error("铸造失败", e);
+        }
+    }
 
-                tokenHistoryRepo.findById(historyId).ifPresent(tokenHistory -> {
-                    tokenHistory.setTokenId(nft.getTokenId());
-                    tokenHistoryRepo.save(tokenHistory);
-                });
+    @Async
+    public void mint(Asset asset) {
+        User user = userRepo.findById(asset.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(), asset.getTokenId());
+            if (nft != null) {
+                asset.setTokenId(nft.getTokenId());
+                asset.setBlockNumber(nft.getBlockNumber());
+                asset.setTxHash(nft.getTxHash());
+                asset.setGasUsed(nft.getGasUsed());
+                if (asset.getIpfsUrl() == null) {
+                    asset.setIpfsUrl(ipfsUpload(asset.getPic().get(0).getUrl()));
+                }
+                assetRepo.save(asset);
             }
         } catch (Exception e) {
-            e.printStackTrace();
+            log.error("铸造失败", e);
         }
         applicationContext.publishEvent(new CreateAssetEvent(this, true, asset));
     }

+ 14 - 16
src/main/java/com/izouma/nineth/service/AssetService.java

@@ -1,8 +1,8 @@
 package com.izouma.nineth.service;
 
 import com.izouma.nineth.TokenHistory;
-import com.izouma.nineth.domain.*;
 import com.izouma.nineth.domain.Collection;
+import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.PageQuery;
 import com.izouma.nineth.dto.UserHistory;
 import com.izouma.nineth.enums.AssetStatus;
@@ -15,6 +15,7 @@ import com.izouma.nineth.lock.RedisLockable;
 import com.izouma.nineth.repo.*;
 import com.izouma.nineth.utils.JpaUtils;
 import com.izouma.nineth.utils.SecurityUtils;
+import com.izouma.nineth.utils.TokenUtils;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -23,14 +24,12 @@ import org.springframework.context.ApplicationContext;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.scheduling.annotation.Async;
-import org.springframework.scheduling.annotation.AsyncResult;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.time.temporal.ChronoUnit;
 import java.util.*;
-import java.util.concurrent.Future;
 import java.util.stream.Collectors;
 
 @Service
@@ -51,16 +50,15 @@ public class AssetService {
         return assetRepo.findAll(JpaUtils.toSpecification(pageQuery, Asset.class), JpaUtils.toPageRequest(pageQuery));
     }
 
-    @Async
-    public Future<Asset> createAsset(Collection collection, User user, Long orderId, BigDecimal price, String type, Integer number) {
+    public Asset createAsset(Collection collection, User user, Long orderId, BigDecimal price, String type, Integer number) {
         Asset asset = Asset.create(collection, user);
+        asset.setTokenId(TokenUtils.genTokenId());
         asset.setNumber(number);
         asset.setOrderId(orderId);
         asset.setPrice(price);
-        asset.setIpfsUrl(assetMintService.ipfsUpload(collection.getPic().get(0).getUrl()));
         assetRepo.save(asset);
 
-        TokenHistory tokenHistory = tokenHistoryRepo.save(TokenHistory.builder()
+        tokenHistoryRepo.save(TokenHistory.builder()
                 .tokenId(asset.getTokenId())
                 .fromUser(collection.getMinter())
                 .fromUserId(collection.getMinterId())
@@ -71,19 +69,19 @@ public class AssetService {
                 .operation(type)
                 .price(price)
                 .build());
-        assetMintService.mint(asset, tokenHistory.getId());
-        return new AsyncResult<>(asset);
+        assetMintService.mint(asset);
+        return asset;
     }
 
-    @Async
-    public Future<Asset> createAsset(BlindBoxItem winItem, User user, Long orderId, BigDecimal price, String type, Integer number) {
+    public Asset createAsset(BlindBoxItem winItem, User user, Long orderId, BigDecimal price, String type, Integer number) {
         Asset asset = Asset.create(winItem, user);
+        asset.setTokenId(TokenUtils.genTokenId());
         asset.setNumber(number);
         asset.setOrderId(orderId);
         asset.setPrice(price);
-        asset.setIpfsUrl(assetMintService.ipfsUpload(winItem.getPic().get(0).getUrl()));
-        assetRepo.save(asset);
-        TokenHistory tokenHistory = tokenHistoryRepo.save(TokenHistory.builder()
+        assetRepo.saveAndFlush(asset);
+
+        tokenHistoryRepo.save(TokenHistory.builder()
                 .tokenId(asset.getTokenId())
                 .fromUser(winItem.getMinter())
                 .fromUserId(winItem.getMinterId())
@@ -94,8 +92,8 @@ public class AssetService {
                 .operation(type)
                 .price(price)
                 .build());
-        assetMintService.mint(asset, tokenHistory.getId());
-        return new AsyncResult<>(asset);
+        assetMintService.mint(asset.getId(), user.getId());
+        return asset;
     }
 
 

+ 23 - 0
src/main/java/com/izouma/nineth/service/CacheService.java

@@ -0,0 +1,23 @@
+package com.izouma.nineth.service;
+
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CacheService {
+    @CacheEvict(value = "collection", allEntries = true)
+    public void clearCollection() {
+    }
+
+    @CacheEvict(value = "collection", key = "#id")
+    public void clearCollection(Long id) {
+    }
+
+    @CacheEvict(value = "user", allEntries = true)
+    public void clearUser() {
+    }
+
+    @CacheEvict(value = "user", key = "#username")
+    public void clearUser(String username) {
+    }
+}

+ 61 - 35
src/main/java/com/izouma/nineth/service/CollectionService.java

@@ -1,7 +1,7 @@
 package com.izouma.nineth.service;
 
-import com.izouma.nineth.domain.*;
 import com.izouma.nineth.domain.Collection;
+import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.CollectionDTO;
 import com.izouma.nineth.dto.CreateBlindBox;
 import com.izouma.nineth.dto.PageQuery;
@@ -17,36 +17,43 @@ import org.apache.commons.lang3.RandomUtils;
 import org.apache.commons.lang3.Range;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
-import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Sort;
 import org.springframework.data.jpa.domain.Specification;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.scheduling.TaskScheduler;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.PostConstruct;
 import javax.persistence.criteria.Predicate;
 import javax.transaction.Transactional;
 import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.util.*;
+import java.util.concurrent.ScheduledFuture;
 import java.util.stream.Collectors;
 
 @Service
 @AllArgsConstructor
 public class CollectionService {
 
-    private CollectionRepo                collectionRepo;
-    private LikeRepo                      likeRepo;
-    private BlindBoxItemRepo              blindBoxItemRepo;
-    private AppointmentRepo               appointmentRepo;
-    private UserRepo                      userRepo;
-    private AssetService                  assetService;
-    private RedisTemplate<String, Object> redisTemplate;
+    private CollectionRepo   collectionRepo;
+    private LikeRepo         likeRepo;
+    private BlindBoxItemRepo blindBoxItemRepo;
+    private AppointmentRepo  appointmentRepo;
+    private UserRepo         userRepo;
+    private TaskScheduler    taskScheduler;
+    private CacheService     cacheService;
 
-    @CacheEvict(value = "collection", allEntries = true)
-    public void clearCache() {
+    private final Map<Long, ScheduledFuture<?>> tasks = new HashMap<>();
+
+    @PostConstruct
+    public void init() {
+        List<Collection> collections = collectionRepo.findByScheduleSaleTrueAndOnShelfFalseAndStartTimeBeforeAndDelFalse(LocalDateTime.now());
+        for (Collection collection : collections) {
+            onShelfTask(collection);
+        }
     }
 
     public Page<Collection> all(PageQuery pageQuery) {
@@ -96,9 +103,46 @@ public class CollectionService {
             if (record.getStartTime() == null) {
                 throw new BusinessException("请填写定时发布时间");
             }
-            record.setOnShelf(record.getStartTime().isBefore(LocalDateTime.now()));
+            if (record.getStartTime().isBefore(LocalDateTime.now())) {
+                record.setOnShelf(true);
+                record.setSalable(true);
+                record.setStartTime(null);
+            }
+        }
+        record = collectionRepo.save(record);
+        onShelfTask(record);
+        return record;
+    }
+
+    public Collection update(Collection record) {
+        collectionRepo.update(record.getId(), record.isOnShelf(), record.isSalable(),
+                record.getStartTime(), record.isScheduleSale(), record.getSort(),
+                record.getDetail(), record.getPrivileges(), record.getProperties(),
+                record.getModel3d());
+        record = collectionRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+        onShelfTask(record);
+        return record;
+    }
+
+    private void onShelfTask(Collection record) {
+        ScheduledFuture<?> task = tasks.get(record.getId());
+        if (task != null) {
+            if (!task.cancel(true)) {
+                return;
+            }
+        }
+        if (record.isScheduleSale()) {
+            if (record.getStartTime().minusSeconds(2).isAfter(LocalDateTime.now())) {
+                Date date = Date.from(record.getStartTime().atZone(ZoneId.systemDefault()).toInstant());
+                ScheduledFuture<?> future = taskScheduler.schedule(() -> {
+                    collectionRepo.scheduleOnShelf(record.getId());
+                    tasks.remove(record.getId());
+                }, date);
+                tasks.put(record.getId(), future);
+            } else {
+                collectionRepo.scheduleOnShelf(record.getId());
+            }
         }
-        return collectionRepo.save(record);
     }
 
     public CollectionDTO toDTO(Collection collection) {
@@ -206,18 +250,6 @@ public class CollectionService {
                 .build());
     }
 
-    @Scheduled(fixedRate = 10000)
-    public void scheduleOnShelf() {
-        List<Collection> collections = collectionRepo.findByScheduleSaleTrueAndOnShelfFalseAndStartTimeBeforeAndDelFalse(LocalDateTime.now());
-        for (Collection collection : collections) {
-            collection.setScheduleSale(false);
-            collection.setOnShelf(true);
-            collection.setSalable(true);
-        }
-        collectionRepo.saveAll(collections);
-    }
-
-
     public BlindBoxItem draw(Long collectionId) {
         List<BlindBoxItem> items = blindBoxItemRepo.findByBlindBoxId(collectionId);
 
@@ -273,14 +305,8 @@ public class CollectionService {
     }
 
     public synchronized Integer getNextNumber(Long collectionId) {
-        Collection collection = collectionRepo.findById(collectionId).orElse(null);
-        if (collection == null) return 0;
-        if (collection.getCurrentNumber() == null) {
-            collection.setCurrentNumber(0);
-        }
-        collection.setCurrentNumber(collection.getCurrentNumber() + 1);
-        collectionRepo.save(collection);
-        return collection.getCurrentNumber();
+        collectionRepo.increaseNumber(collectionId, 1);
+        return collectionRepo.getCurrentNumber(collectionId).orElse(0);
     }
 
     public synchronized Integer getNextNumber(Collection collection) {

+ 34 - 15
src/main/java/com/izouma/nineth/service/NFTService.java

@@ -24,6 +24,8 @@ import org.springframework.retry.annotation.Retryable;
 import org.springframework.stereotype.Service;
 
 import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
 
 @Service
 @Slf4j
@@ -33,6 +35,7 @@ public class NFTService {
     private final RestClientProperties restClientProperties;
     private final GeneralProperties    generalProperties;
 
+    @Retryable(maxAttempts = 10, backoff = @Backoff(delay = 5000), value = BusinessException.class)
     public NFTAccount createAccount(String username) {
         CallRestBizParam callRestBizParam = CallRestBizParam.builder()
                 .orderId(String.valueOf(new SnowflakeIdWorker(0, 0).nextId()))
@@ -46,7 +49,7 @@ public class NFTService {
         try {
             BaseResp baseResp = restClient.chainCallForBiz(callRestBizParam);
             NFTAccount account = new NFTAccount(username, Constants.kmsKey, baseResp.getData());
-            if (baseResp.isSuccess()) {
+            if (baseResp.isSuccess() || "400123".equals(baseResp.getCode())) {
                 log.info("创建账户成功 {}", account);
                 return account;
             } else {
@@ -59,16 +62,17 @@ public class NFTService {
         }
     }
 
-    @Retryable(maxAttempts = 100, backoff = @Backoff(delay = 5000), value = BusinessException.class)
-    public synchronized NFT createToken(String toAccount) throws Exception {
+    @Retryable(maxAttempts = 10, backoff = @Backoff(delay = 5000), value = BusinessException.class)
+    public synchronized NFT createToken(String toAccount, String tokenId) throws Exception {
         JSONArray jsonArray = new JSONArray();
         jsonArray.add(Utils.getIdentityByName(toAccount));
+        jsonArray.add(new BigInteger(tokenId, 16));
         CallRestBizParam callRestBizParam = CallRestBizParam.builder()
                 .orderId(String.valueOf(new SnowflakeIdWorker(0, 0).nextId()))
                 .bizid(restClientProperties.getBizid())
                 .account(restClientProperties.getAccount())
                 .contractName(generalProperties.getContractName())
-                .methodSignature("mint(identity)")
+                .methodSignature("mint(identity,uint256)")
                 .inputParamListStr(jsonArray.toJSONString())
                 .outTypes("[]")//合约返回值类型
                 .mykmsKeyId(restClientProperties.getKmsId())
@@ -87,22 +91,37 @@ public class NFTService {
             BigInteger gasUsed = txReceipt.getGasUsed();
             long result = txReceipt.getResult();
             log.info("EVM合约交易内容: 哈希 " + txReceipt.getHash() + ", 消耗燃料 " + gasUsed + ", 结果 " + result);
-            for (LogEntry logEntry : txReceipt.getLogs()) {
-                if (logEntry.getTopics().get(0).equals(HashUtils.Keccak256("Transfer(identity,identity,uint256)"))) {
-                    String tokenId = logEntry.getTopics().get(3);
-                    txReceipt.getBlockNumber();
-                    NFT nft = new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed());
-                    log.info("NFT生成成功 {}", nft);
-                    return nft;
-                }
-            }
-        } else {
+            NFT nft = new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed());
+            log.info("NFT生成成功 {}", nft);
+            return nft;
+        } else if ("211".equals(resp.getCode())) {
+
+        } else if ("10201".equals(resp.getCode())) {
             // 异步交易未成功需要根据状态码判断交易状态
-            log.error("EVM合约执行未成功: " + resp.getCode());
+            ReceiptDecoration txReceipt = JSON.parseObject(resp.getData(), ReceiptDecoration.class);
+            String out = new String(matchAndReplaceNonEnglishChar(txReceipt.getOutput()));
+            // 异步交易未成功需要根据状态码判断交易状态
+            log.error("EVM合约执行未成功: {}, {}", resp.getCode(), out);
+            if (out.endsWith("ERC721: token already minted")) {
+                return new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed());
+            }
         }
         throw new BusinessException("创建nft失败");
     }
 
+    public static byte[] matchAndReplaceNonEnglishChar(byte[] data) {
+        List<Byte> list = new ArrayList<>();
+        for (byte c : data) {
+            if (c >= 32 && c <= 127) {
+                list.add(c);
+            }
+        }
+        byte[] bytes = new byte[list.size()];
+        for (int i = 0; i < list.size(); i++) {
+            bytes[i] = list.get(i);
+        }
+        return bytes;
+    }
 
     public NFT transferToken(String tokenId, String fromAccount, String toAccount) throws Exception {
         JSONArray jsonArray = new JSONArray();

+ 7 - 9
src/main/java/com/izouma/nineth/service/OrderService.java

@@ -116,9 +116,8 @@ public class OrderService {
             userAddress = userAddressRepo.findById(addressId).orElseThrow(new BusinessException("地址信息不存在"));
         }
 
-        collection.setStock(collection.getStock() - qty);
-        collection.setSale(collection.getSale() + qty);
-        collectionRepo.save(collection);
+        collectionRepo.increaseStock(collectionId, -qty);
+        collectionRepo.increaseSale(collectionId, qty);
 
         BigDecimal gasFee = sysConfigService.getBigDecimal("gas_fee");
         Order order = Order.builder()
@@ -273,7 +272,7 @@ public class OrderService {
         paymentParams.put("goods_title", collection.getName());
         paymentParams.put("goods_desc", collection.getName());
         paymentParams.put("time_expire", DateTimeFormatter.ofPattern("yyyyMMddHHmmss")
-                .format(LocalDateTime.now().plusMinutes(5)));
+                .format(LocalDateTime.now().plusMinutes(3)));
         paymentParams.put("notify_url", adapayProperties.getNotifyUrl() + "/order/" + order.getId());
 
         List<Map<String, Object>> divMembers = new ArrayList<>();
@@ -457,9 +456,8 @@ public class OrderService {
             }
             collection.setOnShelf(true);
         }
-        collection.setSale(collection.getSale() - 1);
-        collection.setStock(collection.getStock() + 1);
-        collectionRepo.save(collection);
+        collectionRepo.increaseSale(collection.getId(), -order.getQty());
+        collectionRepo.increaseStock(collection.getId(), order.getQty());
 
         order.setStatus(OrderStatus.CANCELLED);
         order.setCancelTime(LocalDateTime.now());
@@ -474,10 +472,10 @@ public class OrderService {
         }
     }
 
-    @Scheduled(fixedRate = 60000)
+    @Scheduled(fixedRate = 30000)
     public void batchCancel() {
         List<Order> orders = orderRepo.findByStatusAndCreatedAtBeforeAndDelFalse(OrderStatus.NOT_PAID,
-                LocalDateTime.now().minusMinutes(5));
+                LocalDateTime.now().minusSeconds(210));
         orders.forEach(o -> {
             try {
                 cancel(o);

+ 2 - 1
src/main/java/com/izouma/nineth/service/UserService.java

@@ -65,6 +65,7 @@ public class UserService {
     private CollectionService collectionService;
     private AdapayService     adapayService;
     private UserBankCardRepo  userBankCardRepo;
+    private CacheService      cacheService;
 
     @CacheEvict(value = "user", key = "#user.username")
     public User update(User user) {
@@ -78,7 +79,7 @@ public class UserService {
         userRepo.updateOrderMinter(orig.getId());
         userRepo.updateHistoryFromUser(orig.getId());
         userRepo.updateHistoryToUser(orig.getId());
-        collectionService.clearCache();
+        cacheService.clearCollection();
         return orig;
     }
 

+ 23 - 0
src/main/java/com/izouma/nineth/utils/TokenUtils.java

@@ -0,0 +1,23 @@
+package com.izouma.nineth.utils;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class TokenUtils {
+    public static String genTokenId() {
+        try {
+            Random random = ThreadLocalRandom.current();
+            byte[] r = new byte[32];
+            random.nextBytes(r);
+            MessageDigest m = MessageDigest.getInstance("MD5");
+            m.update(r, 0, r.length);
+            return new BigInteger(1, m.digest()).toString(16);
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+}

+ 1 - 4
src/main/java/com/izouma/nineth/web/CollectionController.java

@@ -9,7 +9,6 @@ import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.CollectionRepo;
 import com.izouma.nineth.service.CollectionService;
 import com.izouma.nineth.service.LikeService;
-import com.izouma.nineth.utils.ObjUtils;
 import com.izouma.nineth.utils.SecurityUtils;
 import com.izouma.nineth.utils.excel.ExcelUtils;
 import io.swagger.annotations.ApiOperation;
@@ -36,9 +35,7 @@ public class CollectionController extends BaseController {
     //@PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/save")
     public Collection save(@RequestBody Collection record) {
-        Collection orig = collectionRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
-        ObjUtils.merge(orig, record);
-        return collectionRepo.save(orig);
+        return collectionService.update(record);
     }
 
     @PostMapping("/create")

+ 1 - 245
src/main/resources/application.yaml

@@ -131,7 +131,7 @@ aliyun:
   sms-code: SMS_11685095
 general:
   host: https://nfttest.9space.vip
-  contract-name: nine_space
+  contract-name: nine_space_new
   name: 第九空间
   org: 广州麦塔沃司信息技术有限公司
   short-name: 麦塔沃司
@@ -218,247 +218,3 @@ alipay:
   return-url: https://nft.9space.vip/9th/home
 adapay:
   notify-url: https://nft.9space.vip/notify/adapay
----
-spring:
-  profiles: dev_raex
-  datasource:
-    url: jdbc:mysql://rm-wz9sc79f5255780opqo.mysql.rds.aliyuncs.com/raex_test?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8
-    username: raex
-    password: K@SdS7e6NTw4CK
-  redis:
-    host: 120.78.171.194
-    password: jV%93RtjUx82Tp
-wx:
-  mp:
-    app_id: wx32eeacbe7e6e7f6e
-    app_secret: fbeb320efd8401ac52c28f4c94389771
-  ma:
-    app_id: wx6517cbf58115c508
-    app_secret: 8af0e8ba28ffddfb7e574e6c7cb6aaf1
-    msg_token: msgToken
-    msg_aes_key: aesKey
-    msg_format: JSON
-  pay:
-    app-id: wx32eeacbe7e6e7f6e
-    mch-id: 1614898941
-    mch-key: A2qWTQzN5EkvgeWgmnnTSY4vV3Y6Xxbj
-    sub-app-id:
-    sub-mch-id:
-    key-path: classpath:/cert/apiclient_cert.p12
-    notify-url: https://raextest.izouma.com/notify/order/weixin
-    refund-notify-url: https://raextest.izouma.com/wx/refundNotify
-    return-url: https://raextest.izouma.com/9th/orders
-storage:
-  provider: aliyun
-  local_path: /var/www/upload/
-aliyun:
-  access-key-id: LTAI5tPoBCiEMSDaS1Q4HKr9
-  access-key-secret: F8ZNiqdH35T7gikBkn6Fq8tgbvdY88
-  oss-end-point: oss-cn-shenzhen.aliyuncs.com
-  oss-bucket-name: raex-meta
-  oss-domain: https://raex-meta.oss-cn-shenzhen.aliyuncs.com
-  sms-sign: 华储艺术品中心
-  sms-code: SMS_228870098
-general:
-  host: https://raextest.izouma.com
-  contract-name: raex
-  name: 绿洲数字藏品中心
-  org: 华储艺术品中心(深圳)有限公司
-  short-name: 华储
-mychain:
-  rest:
-    bizid: a00e36c5
-    cipher-suit: ec
-    rest-url: https://rest.baas.alipay.com
-    access-id: 1KKUWLPoBDCUECOE
-    access-secret: access2.key
-    tenantid: BDCUECOE
-    read-file-from-ext: false
-    account: raex_official
-    kmsId: W0A6XaE5BDCUECOE1638182878495
-alipay:
-  app-id: 2021002186606637
-  gateway: https://openapi.alipay.com/gateway.do
-  private-key: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDGPN0GkL4ISuFSgeqPAjC6VXTdvnkrC6EyYhRBAwurYLYVcHmI+ffx4pcxXLXrbveXwdxNj2GpUCvy56a5ACu9wiaWwxaF6moV3NILKmJa6c7D/4N3Cy4KG7RcLRyeWpdbRFP7OeM+Y8iRFRp0EhAv7btAqimny32ETvIXMyCSvZbI0hrmtwUFMgPW8ofpIoQ5VhMixdKn2niAyQs5TBL1QuVEP1Qe7WRWBrvtwMx1VmI01zkjgFkfehVJwG+BtHYhRwI1pcDrpQv3sDAHl6Qa2th+BkOX1Qtwmzc/SvUELeqJJCsZ+DVr9kTBNke1A4aR2DrlfTezZpl/sN/fJmlTAgMBAAECggEBAIks+K1gX3+RgVX8vHj1RQ7Lr7D56xLUW1ln8SgDmYGfzKANUqxsfRyOdZ0c0G34PbBv36hz/VqSNbdCgWYnLh2DSfytRtqoGXzDbz12uNS8Ue3i0+/+dn9cKHRYayNRAMeRAqQnrI4xskpi1glXrofb8+WNWoHYGCUEFBXltTaUbSNa4saIuvRQvy1i8qZMiAGu+rd/A5TaI+6C7MnHWmYtZ6fFFUeMnJAPRbn4CqNntKmPwF2IrSHaQlefgaQMY6Il56Ws7D9LuNAqn9xuD1duOiK2VrJTLONkEY001iXczZi6JqGzX83ZyDy3kcbQ4BoWRZ6ehwlfPTmovyuKysECgYEA+5QwUXOlStA3wvYbT5lwvva/y51Di/fi5PCnSL3wBEcTXGPkbAvaH6CV6x11nuJWOSgwD1fBMyzAVASDYd0oRQq2+NUBx2v1PFRc3PM4Yp85oZV3eNDyRV9SzhsT1dR/OfuWyJefuCuxJDsBGJpJV0t7e5lq2qqYgZjvpymZhKMCgYEAybizrkcexSnhlnSaY7ENa7fZsIP5l/y3xbtg/65JsARF1VNOLURj9QgbVEoi5FnCMHiYEal25mTZGEWIawCD+XWdkCu4orvxBXU4boIca6R9lfbzJuY3We3Ts3TEXOp1Tkmn5bMM8ImLU9teetufvQa3+Mq7qI21gB0vEXawI5ECgYAZnagh0wWkjXjwCAEV5Mi/GP7Ea7nh+ZaHux09YeGbfeUxxhYPDlHiYIaDTxeX2vHulfH2zfelD0xyAZejElK0XPfudDnfJVXuE6T09mrqV84VbtOgYJ4ahC85PzaQ0jc2HzDmMdIYfZJm3v8okyUel1f2aNOhejdXEsxsF+dCwwKBgQCuV8Zj/+/mNBZW9RxiwSl6SgIJf2b/J1qluRdSpA3n5Sl+AGv2z78cjg8gwJp7heBCCFhWG4M6CTtgsOgAowdtWWv+qOsBKzJapz9Is4dguWAZdsAchKiePuDTnz3/mFwed6Z27lNmqVoT9esogB0FQINMsduTCDcwLQj7LPt7IQKBgCcPiM5BXeOnIQBlQNA4MrP7th4NIltOEIF6uarqUfnzCy52blRJaXf2VTZNgnY4KovdBIl4JukRyk2Iwcg/Kt+IIv/uBQOLNpQm1cSqMpDs+YZlmKjeTfZiqShuUDueypjQ6t4kK8cHRBQs7FEuKfg842MjJHenNt97TNHAoT5P
-  app-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjzdBpC+CErhUoHqjwIwulV03b55KwuhMmIUQQMLq2C2FXB5iPn38eKXMVy16273l8HcTY9hqVAr8uemuQArvcImlsMWhepqFdzSCypiWunOw/+DdwsuChu0XC0cnlqXW0RT+znjPmPIkRUadBIQL+27QKopp8t9hE7yFzMgkr2WyNIa5rcFBTID1vKH6SKEOVYTIsXSp9p4gMkLOUwS9ULlRD9UHu1kVga77cDMdVZiNNc5I4BZH3oVScBvgbR2IUcCNaXA66UL97AwB5ekGtrYfgZDl9ULcJs3P0r1BC3qiSQrGfg1a/ZEwTZHtQOGkdg65X03s2aZf7Df3yZpUwIDAQAB
-  ali-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2KS67bzs6FQ7+PYCm6Zp1gE06VVpuTpV9Mbqn7RqSKmzKZORbL0pG7UyN/Iu3dooNJLQIcxuUDZF6JNgOiX7nxRPyhLud45EXBBR+TUeJCfdSU/7kg2+XBgwD/zzLfj+cAR8SnlmYE5dA81hsM/l1MQrtLTryT/lAHR36eChb6QUnxAwwUZC8QiWDaFerlScJrJG0VJUEKQD6ANV2qP2fmU8IMxNZBT6WMvRvPIN34hCm9B8Kx2Tr8rOjZvwLwVwd1nR5a5mrbwG+kNY7olHW2ICYxJxIxXzypg4jTa5NyW7XR7tdgecRlAGJNxMeBqWwMRmN5l8G2ozV3iOIwhCMQIDAQAB
-  ali-pub-cert-path: classpath:cert/alipayCertPublicKey_RSA2.crt
-  api-key: CRv5YFAOIEGY5PgVf14Y9g==
-  app-cert-path: classpath:cert/appCertPublicKey_2021002120645023.crt
-  root-cert-path: classpath:cert/alipayRootCert.crt
-  notify-url: https://raextest.izouma.com/notify/order/alipay
-  return-url: https://raextest.izouma.com/9th/home
-adapay:
-  app-id: app_0e8d3acb-3d95-4ebb-8445-e470c378a787
-  debug: true
-  prod: true
-  api-key: api_live_dc298e47-c0be-4acf-a962-a2c2988e4cae
-  mock-key: api_test_26e9eee7-6695-4169-90a1-203c6d2cf196
-  public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi3khLvAl4OIsKUbQGqSBqW7qCXcgIdxNhYCKjiUjBP9Pg7HLiFFc30MzFoF0/fGXfGikC5o01h8ek4OtAwhScyQZCEmWGqhfTnPmHT3teUyDaaebMig5O9lnlBFv45V4i8Csnhccwr3nW6W3QFItHD+uFEvy7JRqIRxllK4I/1gUd974MANjQB0fs4hqfCIRVFx6FrV3QY8BrFrmelrfZljlXhiBz+jslGM4ZFbg8hTGesJQOtD6sTwEK72Rt1T9pkpaVk7O8UBzPZ5PEZ9qUA1JnsR5ikv8J+F2b5d0vSkbOv5fMA6pQVuUIZhGTUcIjhvJ/xaasVDCIRRY+EkqtQIDAQAB
-  priv-key: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCLeSEu8CXg4iwpRtAapIGpbuoJdyAh3E2FgIqOJSME/0+DscuIUVzfQzMWgXT98Zd8aKQLmjTWHx6Tg60DCFJzJBkISZYaqF9Oc+YdPe15TINpp5syKDk72WeUEW/jlXiLwKyeFxzCvedbpbdAUi0cP64US/LslGohHGWUrgj/WBR33vgwA2NAHR+ziGp8IhFUXHoWtXdBjwGsWuZ6Wt9mWOVeGIHP6OyUYzhkVuDyFMZ6wlA60PqxPAQrvZG3VP2mSlpWTs7xQHM9nk8Rn2pQDUmexHmKS/wn4XZvl3S9KRs6/l8wDqlBW5QhmEZNRwiOG8n/FpqxUMIhFFj4SSq1AgMBAAECggEAVwmWXbZbzQUXzgJ058t1ZwjiYFnI4ZibgA6BaMdgHUQ+mM6hV0Z/EIzdGtRa8AaOJIMgrGTlSCJPcHshwty0p0oFnRhe5e/g2hKVrfXxdlr7PznrLdfQL7syWkKvcnTar0vj7Rw7RIRCFv1JaIhfwlszBVOIG39a46LW+XvJ/Z5Lk5wB8tkt0xWDUghAU1xP10P8OHcr/x3aFhiyAvmWWr7syYKD1rDAtC+n+6Imb8MvTxwk4Gz1wpM+a7gHeYk2n91yR94G6A2wMSeM80T4hCbYKutD5rkdi5i3hoeIiPiq5qbR0rmI/dudVbGkVT+xkh1z1IsKeYiD2ef4Ddy2QQKBgQDIqOuaml9bnJpKie9Z0ysiPWxc771byxhgx7bwsoJey4x5bcLx+G9IAvkGwWFUl+25jgpeVn/LZ6147e9ozeip7WSKvStniND+CB7SvA5ZDRm7CfqFQub//9Q1DWNfl+ThGAXHMlKgS7DanLqvpUsRdhUOceZwwrdkV93v7by8nQKBgQCx8EdYbxNIEnVI3Y98YCAWtvgBCCa8yurL+9IXe9VKCFGdGRZ4b61GWDNyjUAfiboXY4ByzvX4cdlZ1euVmqMYsEv28xXEFdGxSDpa+oeETbv1U2GEGL4Ups3z28Sx4TGGSyvReyQOhZftIF6vCZtZ8dZMEf8IdxyudJkcJp+u+QKBgBFtemkHF1khlNT8felTSd/DbfH0cIHUdd2R+vWUy3XoP98cBV52sVOTzoUjroxmVaNUDtp6sMa9znc+UxjLKXX4xE64d1iarWwi0GqFIsnhNWblSvjgAqghVBD3hLX8v0g9ieLvH/YEHOwfyKcQuCBgHRwQEG+iucLhTslT4JyRAoGAHa25CKwGKEhD3bJuw0z5LTC5btqgM28Y+Ir5AMe7zIxUqIJNuCrQWOJPOnUK0/fR3SLQgtW4OwcqPIysrZhMScrl8Luczsbg4dPtP813mv6oMgQFSNYjpigoQ9tNFGo+K2sQVPFYEz//FiMHB+TvT3JBzxBVXGEZnJOAEizzB2kCgYEAxUFRiJMcmp5IyGcFlmGP219OcEfzt8BV8s3yoPHPpgYX/zPsH9764UMSZb+FRXFLd8HC+UqqppQ4cq2RmMu5X7H/DWoj9FqXgusjOmZUyWiJgTPC4ktFesuhJhCHuk/50/nXmc6O8rWLwXqXf1XNaoNfzDmZNQ20jRZGr8eVc4g=
-  app-public-key: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwN6xgd6Ad8v2hIIsQVnbt8a3JituR8o4Tc3B5WlcFR55bz4OMqrG/356Ur3cPbc2Fe8ArNd/0gZbC9q56Eb16JTkVNA/fye4SXznWxdyBPR7+guuJZHc/VW2fKH2lfZ2P3Tt0QkKZZoawYOGSMdIvO+WqK44updyax0ikK6JlNQIDAQAB
-  wx-app-id:
-  notify-url: https://raextest.izouma.com/notify/adapay
----
-spring:
-  profiles: test_raex
-  datasource:
-    url: jdbc:mysql://rm-wz9sc79f5255780opqo.mysql.rds.aliyuncs.com/raex_test?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8
-    username: raex
-    password: K@SdS7e6NTw4CK
-  redis:
-    host: 120.78.171.194
-    password: jV%93RtjUx82Tp
-wx:
-  mp:
-    app_id: wx32eeacbe7e6e7f6e
-    app_secret: fbeb320efd8401ac52c28f4c94389771
-  ma:
-    app_id: wx6517cbf58115c508
-    app_secret: 8af0e8ba28ffddfb7e574e6c7cb6aaf1
-    msg_token: msgToken
-    msg_aes_key: aesKey
-    msg_format: JSON
-  pay:
-    app-id: wx32eeacbe7e6e7f6e
-    mch-id: 1614898941
-    mch-key: A2qWTQzN5EkvgeWgmnnTSY4vV3Y6Xxbj
-    sub-app-id:
-    sub-mch-id:
-    key-path: classpath:/cert/apiclient_cert.p12
-    notify-url: https://raextest.izouma.com/notify/order/weixin
-    refund-notify-url: https://raextest.izouma.com/wx/refundNotify
-    return-url: https://raextest.izouma.com/9th/orders
-storage:
-  provider: aliyun
-  local_path: /var/www/upload/
-aliyun:
-  access-key-id: LTAI5tPoBCiEMSDaS1Q4HKr9
-  access-key-secret: F8ZNiqdH35T7gikBkn6Fq8tgbvdY88
-  oss-end-point: oss-cn-shenzhen.aliyuncs.com
-  oss-bucket-name: raex-meta
-  oss-domain: https://raex-meta.oss-cn-shenzhen.aliyuncs.com
-  sms-sign: 华储艺术品中心
-  sms-code: SMS_228870098
-general:
-  host: https://raextest.izouma.com
-  contract-name: raex
-  name: 绿洲数字藏品中心
-  org: 华储艺术品中心(深圳)有限公司
-  short-name: 华储
-mychain:
-  rest:
-    bizid: a00e36c5
-    cipher-suit: ec
-    rest-url: https://rest.baas.alipay.com
-    access-id: 1KKUWLPoBDCUECOE
-    access-secret: access2.key
-    tenantid: BDCUECOE
-    read-file-from-ext: false
-    account: raex_official
-    kmsId: W0A6XaE5BDCUECOE1638182878495
-alipay:
-  app-id: 2021002186606637
-  gateway: https://openapi.alipay.com/gateway.do
-  private-key: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDGPN0GkL4ISuFSgeqPAjC6VXTdvnkrC6EyYhRBAwurYLYVcHmI+ffx4pcxXLXrbveXwdxNj2GpUCvy56a5ACu9wiaWwxaF6moV3NILKmJa6c7D/4N3Cy4KG7RcLRyeWpdbRFP7OeM+Y8iRFRp0EhAv7btAqimny32ETvIXMyCSvZbI0hrmtwUFMgPW8ofpIoQ5VhMixdKn2niAyQs5TBL1QuVEP1Qe7WRWBrvtwMx1VmI01zkjgFkfehVJwG+BtHYhRwI1pcDrpQv3sDAHl6Qa2th+BkOX1Qtwmzc/SvUELeqJJCsZ+DVr9kTBNke1A4aR2DrlfTezZpl/sN/fJmlTAgMBAAECggEBAIks+K1gX3+RgVX8vHj1RQ7Lr7D56xLUW1ln8SgDmYGfzKANUqxsfRyOdZ0c0G34PbBv36hz/VqSNbdCgWYnLh2DSfytRtqoGXzDbz12uNS8Ue3i0+/+dn9cKHRYayNRAMeRAqQnrI4xskpi1glXrofb8+WNWoHYGCUEFBXltTaUbSNa4saIuvRQvy1i8qZMiAGu+rd/A5TaI+6C7MnHWmYtZ6fFFUeMnJAPRbn4CqNntKmPwF2IrSHaQlefgaQMY6Il56Ws7D9LuNAqn9xuD1duOiK2VrJTLONkEY001iXczZi6JqGzX83ZyDy3kcbQ4BoWRZ6ehwlfPTmovyuKysECgYEA+5QwUXOlStA3wvYbT5lwvva/y51Di/fi5PCnSL3wBEcTXGPkbAvaH6CV6x11nuJWOSgwD1fBMyzAVASDYd0oRQq2+NUBx2v1PFRc3PM4Yp85oZV3eNDyRV9SzhsT1dR/OfuWyJefuCuxJDsBGJpJV0t7e5lq2qqYgZjvpymZhKMCgYEAybizrkcexSnhlnSaY7ENa7fZsIP5l/y3xbtg/65JsARF1VNOLURj9QgbVEoi5FnCMHiYEal25mTZGEWIawCD+XWdkCu4orvxBXU4boIca6R9lfbzJuY3We3Ts3TEXOp1Tkmn5bMM8ImLU9teetufvQa3+Mq7qI21gB0vEXawI5ECgYAZnagh0wWkjXjwCAEV5Mi/GP7Ea7nh+ZaHux09YeGbfeUxxhYPDlHiYIaDTxeX2vHulfH2zfelD0xyAZejElK0XPfudDnfJVXuE6T09mrqV84VbtOgYJ4ahC85PzaQ0jc2HzDmMdIYfZJm3v8okyUel1f2aNOhejdXEsxsF+dCwwKBgQCuV8Zj/+/mNBZW9RxiwSl6SgIJf2b/J1qluRdSpA3n5Sl+AGv2z78cjg8gwJp7heBCCFhWG4M6CTtgsOgAowdtWWv+qOsBKzJapz9Is4dguWAZdsAchKiePuDTnz3/mFwed6Z27lNmqVoT9esogB0FQINMsduTCDcwLQj7LPt7IQKBgCcPiM5BXeOnIQBlQNA4MrP7th4NIltOEIF6uarqUfnzCy52blRJaXf2VTZNgnY4KovdBIl4JukRyk2Iwcg/Kt+IIv/uBQOLNpQm1cSqMpDs+YZlmKjeTfZiqShuUDueypjQ6t4kK8cHRBQs7FEuKfg842MjJHenNt97TNHAoT5P
-  app-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjzdBpC+CErhUoHqjwIwulV03b55KwuhMmIUQQMLq2C2FXB5iPn38eKXMVy16273l8HcTY9hqVAr8uemuQArvcImlsMWhepqFdzSCypiWunOw/+DdwsuChu0XC0cnlqXW0RT+znjPmPIkRUadBIQL+27QKopp8t9hE7yFzMgkr2WyNIa5rcFBTID1vKH6SKEOVYTIsXSp9p4gMkLOUwS9ULlRD9UHu1kVga77cDMdVZiNNc5I4BZH3oVScBvgbR2IUcCNaXA66UL97AwB5ekGtrYfgZDl9ULcJs3P0r1BC3qiSQrGfg1a/ZEwTZHtQOGkdg65X03s2aZf7Df3yZpUwIDAQAB
-  ali-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2KS67bzs6FQ7+PYCm6Zp1gE06VVpuTpV9Mbqn7RqSKmzKZORbL0pG7UyN/Iu3dooNJLQIcxuUDZF6JNgOiX7nxRPyhLud45EXBBR+TUeJCfdSU/7kg2+XBgwD/zzLfj+cAR8SnlmYE5dA81hsM/l1MQrtLTryT/lAHR36eChb6QUnxAwwUZC8QiWDaFerlScJrJG0VJUEKQD6ANV2qP2fmU8IMxNZBT6WMvRvPIN34hCm9B8Kx2Tr8rOjZvwLwVwd1nR5a5mrbwG+kNY7olHW2ICYxJxIxXzypg4jTa5NyW7XR7tdgecRlAGJNxMeBqWwMRmN5l8G2ozV3iOIwhCMQIDAQAB
-  ali-pub-cert-path: classpath:cert/alipayCertPublicKey_RSA2.crt
-  api-key: CRv5YFAOIEGY5PgVf14Y9g==
-  app-cert-path: classpath:cert/appCertPublicKey_2021002120645023.crt
-  root-cert-path: classpath:cert/alipayRootCert.crt
-  notify-url: https://raextest.izouma.com/notify/order/alipay
-  return-url: https://raextest.izouma.com/9th/home
-adapay:
-  app-id: app_0e8d3acb-3d95-4ebb-8445-e470c378a787
-  debug: true
-  prod: true
-  api-key: api_live_dc298e47-c0be-4acf-a962-a2c2988e4cae
-  mock-key: api_test_26e9eee7-6695-4169-90a1-203c6d2cf196
-  public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi3khLvAl4OIsKUbQGqSBqW7qCXcgIdxNhYCKjiUjBP9Pg7HLiFFc30MzFoF0/fGXfGikC5o01h8ek4OtAwhScyQZCEmWGqhfTnPmHT3teUyDaaebMig5O9lnlBFv45V4i8Csnhccwr3nW6W3QFItHD+uFEvy7JRqIRxllK4I/1gUd974MANjQB0fs4hqfCIRVFx6FrV3QY8BrFrmelrfZljlXhiBz+jslGM4ZFbg8hTGesJQOtD6sTwEK72Rt1T9pkpaVk7O8UBzPZ5PEZ9qUA1JnsR5ikv8J+F2b5d0vSkbOv5fMA6pQVuUIZhGTUcIjhvJ/xaasVDCIRRY+EkqtQIDAQAB
-  priv-key: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCLeSEu8CXg4iwpRtAapIGpbuoJdyAh3E2FgIqOJSME/0+DscuIUVzfQzMWgXT98Zd8aKQLmjTWHx6Tg60DCFJzJBkISZYaqF9Oc+YdPe15TINpp5syKDk72WeUEW/jlXiLwKyeFxzCvedbpbdAUi0cP64US/LslGohHGWUrgj/WBR33vgwA2NAHR+ziGp8IhFUXHoWtXdBjwGsWuZ6Wt9mWOVeGIHP6OyUYzhkVuDyFMZ6wlA60PqxPAQrvZG3VP2mSlpWTs7xQHM9nk8Rn2pQDUmexHmKS/wn4XZvl3S9KRs6/l8wDqlBW5QhmEZNRwiOG8n/FpqxUMIhFFj4SSq1AgMBAAECggEAVwmWXbZbzQUXzgJ058t1ZwjiYFnI4ZibgA6BaMdgHUQ+mM6hV0Z/EIzdGtRa8AaOJIMgrGTlSCJPcHshwty0p0oFnRhe5e/g2hKVrfXxdlr7PznrLdfQL7syWkKvcnTar0vj7Rw7RIRCFv1JaIhfwlszBVOIG39a46LW+XvJ/Z5Lk5wB8tkt0xWDUghAU1xP10P8OHcr/x3aFhiyAvmWWr7syYKD1rDAtC+n+6Imb8MvTxwk4Gz1wpM+a7gHeYk2n91yR94G6A2wMSeM80T4hCbYKutD5rkdi5i3hoeIiPiq5qbR0rmI/dudVbGkVT+xkh1z1IsKeYiD2ef4Ddy2QQKBgQDIqOuaml9bnJpKie9Z0ysiPWxc771byxhgx7bwsoJey4x5bcLx+G9IAvkGwWFUl+25jgpeVn/LZ6147e9ozeip7WSKvStniND+CB7SvA5ZDRm7CfqFQub//9Q1DWNfl+ThGAXHMlKgS7DanLqvpUsRdhUOceZwwrdkV93v7by8nQKBgQCx8EdYbxNIEnVI3Y98YCAWtvgBCCa8yurL+9IXe9VKCFGdGRZ4b61GWDNyjUAfiboXY4ByzvX4cdlZ1euVmqMYsEv28xXEFdGxSDpa+oeETbv1U2GEGL4Ups3z28Sx4TGGSyvReyQOhZftIF6vCZtZ8dZMEf8IdxyudJkcJp+u+QKBgBFtemkHF1khlNT8felTSd/DbfH0cIHUdd2R+vWUy3XoP98cBV52sVOTzoUjroxmVaNUDtp6sMa9znc+UxjLKXX4xE64d1iarWwi0GqFIsnhNWblSvjgAqghVBD3hLX8v0g9ieLvH/YEHOwfyKcQuCBgHRwQEG+iucLhTslT4JyRAoGAHa25CKwGKEhD3bJuw0z5LTC5btqgM28Y+Ir5AMe7zIxUqIJNuCrQWOJPOnUK0/fR3SLQgtW4OwcqPIysrZhMScrl8Luczsbg4dPtP813mv6oMgQFSNYjpigoQ9tNFGo+K2sQVPFYEz//FiMHB+TvT3JBzxBVXGEZnJOAEizzB2kCgYEAxUFRiJMcmp5IyGcFlmGP219OcEfzt8BV8s3yoPHPpgYX/zPsH9764UMSZb+FRXFLd8HC+UqqppQ4cq2RmMu5X7H/DWoj9FqXgusjOmZUyWiJgTPC4ktFesuhJhCHuk/50/nXmc6O8rWLwXqXf1XNaoNfzDmZNQ20jRZGr8eVc4g=
-  app-public-key: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwN6xgd6Ad8v2hIIsQVnbt8a3JituR8o4Tc3B5WlcFR55bz4OMqrG/356Ur3cPbc2Fe8ArNd/0gZbC9q56Eb16JTkVNA/fye4SXznWxdyBPR7+guuJZHc/VW2fKH2lfZ2P3Tt0QkKZZoawYOGSMdIvO+WqK44updyax0ikK6JlNQIDAQAB
-  wx-app-id:
-  notify-url: https://raextest.izouma.com/notify/adapay
----
-spring:
-  profiles: prod_raex
-  datasource:
-    url: jdbc:mysql://rm-wz9sc79f5255780opqo.mysql.rds.aliyuncs.com/raex_test?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8
-    username: raex
-    password: K@SdS7e6NTw4CK
-  redis:
-    host: 120.78.171.194
-    password: jV%93RtjUx82Tp
-    database: 1
-wx:
-  mp:
-    app_id: wx32eeacbe7e6e7f6e
-    app_secret: fbeb320efd8401ac52c28f4c94389771
-  ma:
-    app_id: wx6517cbf58115c508
-    app_secret: 8af0e8ba28ffddfb7e574e6c7cb6aaf1
-    msg_token: msgToken
-    msg_aes_key: aesKey
-    msg_format: JSON
-  pay:
-    app-id: wx32eeacbe7e6e7f6e
-    mch-id: 1614898941
-    mch-key: A2qWTQzN5EkvgeWgmnnTSY4vV3Y6Xxbj
-    sub-app-id:
-    sub-mch-id:
-    key-path: classpath:/cert/apiclient_cert.p12
-    notify-url: https://raex.izouma.com/notify/order/weixin
-    refund-notify-url: https://raex.izouma.com/wx/refundNotify
-    return-url: https://raex.izouma.com/9th/orders
-storage:
-  provider: aliyun
-  local_path: /var/www/upload/
-aliyun:
-  access-key-id: LTAI5tPoBCiEMSDaS1Q4HKr9
-  access-key-secret: F8ZNiqdH35T7gikBkn6Fq8tgbvdY88
-  oss-end-point: oss-cn-shenzhen.aliyuncs.com
-  oss-bucket-name: raex-meta
-  oss-domain: https://raex-meta.oss-cn-shenzhen.aliyuncs.com
-  sms-sign: 华储艺术品中心
-  sms-code: SMS_228870098
-general:
-  host: https://raex.izouma.com
-  contract-name: raex
-  name: 绿洲数字藏品中心
-  org: 华储艺术品中心(深圳)有限公司
-  short-name: 华储
-mychain:
-  rest:
-    bizid: a00e36c5
-    cipher-suit: ec
-    rest-url: https://rest.baas.alipay.com
-    access-id: 1KKUWLPoBDCUECOE
-    access-secret: access2.key
-    tenantid: BDCUECOE
-    read-file-from-ext: false
-    account: raex_official
-    kmsId: W0A6XaE5BDCUECOE1638182878495
-alipay:
-  app-id: 2021002186606637
-  gateway: https://openapi.alipay.com/gateway.do
-  private-key: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDGPN0GkL4ISuFSgeqPAjC6VXTdvnkrC6EyYhRBAwurYLYVcHmI+ffx4pcxXLXrbveXwdxNj2GpUCvy56a5ACu9wiaWwxaF6moV3NILKmJa6c7D/4N3Cy4KG7RcLRyeWpdbRFP7OeM+Y8iRFRp0EhAv7btAqimny32ETvIXMyCSvZbI0hrmtwUFMgPW8ofpIoQ5VhMixdKn2niAyQs5TBL1QuVEP1Qe7WRWBrvtwMx1VmI01zkjgFkfehVJwG+BtHYhRwI1pcDrpQv3sDAHl6Qa2th+BkOX1Qtwmzc/SvUELeqJJCsZ+DVr9kTBNke1A4aR2DrlfTezZpl/sN/fJmlTAgMBAAECggEBAIks+K1gX3+RgVX8vHj1RQ7Lr7D56xLUW1ln8SgDmYGfzKANUqxsfRyOdZ0c0G34PbBv36hz/VqSNbdCgWYnLh2DSfytRtqoGXzDbz12uNS8Ue3i0+/+dn9cKHRYayNRAMeRAqQnrI4xskpi1glXrofb8+WNWoHYGCUEFBXltTaUbSNa4saIuvRQvy1i8qZMiAGu+rd/A5TaI+6C7MnHWmYtZ6fFFUeMnJAPRbn4CqNntKmPwF2IrSHaQlefgaQMY6Il56Ws7D9LuNAqn9xuD1duOiK2VrJTLONkEY001iXczZi6JqGzX83ZyDy3kcbQ4BoWRZ6ehwlfPTmovyuKysECgYEA+5QwUXOlStA3wvYbT5lwvva/y51Di/fi5PCnSL3wBEcTXGPkbAvaH6CV6x11nuJWOSgwD1fBMyzAVASDYd0oRQq2+NUBx2v1PFRc3PM4Yp85oZV3eNDyRV9SzhsT1dR/OfuWyJefuCuxJDsBGJpJV0t7e5lq2qqYgZjvpymZhKMCgYEAybizrkcexSnhlnSaY7ENa7fZsIP5l/y3xbtg/65JsARF1VNOLURj9QgbVEoi5FnCMHiYEal25mTZGEWIawCD+XWdkCu4orvxBXU4boIca6R9lfbzJuY3We3Ts3TEXOp1Tkmn5bMM8ImLU9teetufvQa3+Mq7qI21gB0vEXawI5ECgYAZnagh0wWkjXjwCAEV5Mi/GP7Ea7nh+ZaHux09YeGbfeUxxhYPDlHiYIaDTxeX2vHulfH2zfelD0xyAZejElK0XPfudDnfJVXuE6T09mrqV84VbtOgYJ4ahC85PzaQ0jc2HzDmMdIYfZJm3v8okyUel1f2aNOhejdXEsxsF+dCwwKBgQCuV8Zj/+/mNBZW9RxiwSl6SgIJf2b/J1qluRdSpA3n5Sl+AGv2z78cjg8gwJp7heBCCFhWG4M6CTtgsOgAowdtWWv+qOsBKzJapz9Is4dguWAZdsAchKiePuDTnz3/mFwed6Z27lNmqVoT9esogB0FQINMsduTCDcwLQj7LPt7IQKBgCcPiM5BXeOnIQBlQNA4MrP7th4NIltOEIF6uarqUfnzCy52blRJaXf2VTZNgnY4KovdBIl4JukRyk2Iwcg/Kt+IIv/uBQOLNpQm1cSqMpDs+YZlmKjeTfZiqShuUDueypjQ6t4kK8cHRBQs7FEuKfg842MjJHenNt97TNHAoT5P
-  app-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjzdBpC+CErhUoHqjwIwulV03b55KwuhMmIUQQMLq2C2FXB5iPn38eKXMVy16273l8HcTY9hqVAr8uemuQArvcImlsMWhepqFdzSCypiWunOw/+DdwsuChu0XC0cnlqXW0RT+znjPmPIkRUadBIQL+27QKopp8t9hE7yFzMgkr2WyNIa5rcFBTID1vKH6SKEOVYTIsXSp9p4gMkLOUwS9ULlRD9UHu1kVga77cDMdVZiNNc5I4BZH3oVScBvgbR2IUcCNaXA66UL97AwB5ekGtrYfgZDl9ULcJs3P0r1BC3qiSQrGfg1a/ZEwTZHtQOGkdg65X03s2aZf7Df3yZpUwIDAQAB
-  ali-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2KS67bzs6FQ7+PYCm6Zp1gE06VVpuTpV9Mbqn7RqSKmzKZORbL0pG7UyN/Iu3dooNJLQIcxuUDZF6JNgOiX7nxRPyhLud45EXBBR+TUeJCfdSU/7kg2+XBgwD/zzLfj+cAR8SnlmYE5dA81hsM/l1MQrtLTryT/lAHR36eChb6QUnxAwwUZC8QiWDaFerlScJrJG0VJUEKQD6ANV2qP2fmU8IMxNZBT6WMvRvPIN34hCm9B8Kx2Tr8rOjZvwLwVwd1nR5a5mrbwG+kNY7olHW2ICYxJxIxXzypg4jTa5NyW7XR7tdgecRlAGJNxMeBqWwMRmN5l8G2ozV3iOIwhCMQIDAQAB
-  ali-pub-cert-path: classpath:cert/alipayCertPublicKey_RSA2.crt
-  api-key: CRv5YFAOIEGY5PgVf14Y9g==
-  app-cert-path: classpath:cert/appCertPublicKey_2021002120645023.crt
-  root-cert-path: classpath:cert/alipayRootCert.crt
-  notify-url: https://raex.izouma.com/notify/order/alipay
-  return-url: https://raex.izouma.com/9th/home
-adapay:
-  app-id: app_0e8d3acb-3d95-4ebb-8445-e470c378a787
-  debug: true
-  prod: true
-  api-key: api_live_dc298e47-c0be-4acf-a962-a2c2988e4cae
-  mock-key: api_test_26e9eee7-6695-4169-90a1-203c6d2cf196
-  public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi3khLvAl4OIsKUbQGqSBqW7qCXcgIdxNhYCKjiUjBP9Pg7HLiFFc30MzFoF0/fGXfGikC5o01h8ek4OtAwhScyQZCEmWGqhfTnPmHT3teUyDaaebMig5O9lnlBFv45V4i8Csnhccwr3nW6W3QFItHD+uFEvy7JRqIRxllK4I/1gUd974MANjQB0fs4hqfCIRVFx6FrV3QY8BrFrmelrfZljlXhiBz+jslGM4ZFbg8hTGesJQOtD6sTwEK72Rt1T9pkpaVk7O8UBzPZ5PEZ9qUA1JnsR5ikv8J+F2b5d0vSkbOv5fMA6pQVuUIZhGTUcIjhvJ/xaasVDCIRRY+EkqtQIDAQAB
-  priv-key: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCLeSEu8CXg4iwpRtAapIGpbuoJdyAh3E2FgIqOJSME/0+DscuIUVzfQzMWgXT98Zd8aKQLmjTWHx6Tg60DCFJzJBkISZYaqF9Oc+YdPe15TINpp5syKDk72WeUEW/jlXiLwKyeFxzCvedbpbdAUi0cP64US/LslGohHGWUrgj/WBR33vgwA2NAHR+ziGp8IhFUXHoWtXdBjwGsWuZ6Wt9mWOVeGIHP6OyUYzhkVuDyFMZ6wlA60PqxPAQrvZG3VP2mSlpWTs7xQHM9nk8Rn2pQDUmexHmKS/wn4XZvl3S9KRs6/l8wDqlBW5QhmEZNRwiOG8n/FpqxUMIhFFj4SSq1AgMBAAECggEAVwmWXbZbzQUXzgJ058t1ZwjiYFnI4ZibgA6BaMdgHUQ+mM6hV0Z/EIzdGtRa8AaOJIMgrGTlSCJPcHshwty0p0oFnRhe5e/g2hKVrfXxdlr7PznrLdfQL7syWkKvcnTar0vj7Rw7RIRCFv1JaIhfwlszBVOIG39a46LW+XvJ/Z5Lk5wB8tkt0xWDUghAU1xP10P8OHcr/x3aFhiyAvmWWr7syYKD1rDAtC+n+6Imb8MvTxwk4Gz1wpM+a7gHeYk2n91yR94G6A2wMSeM80T4hCbYKutD5rkdi5i3hoeIiPiq5qbR0rmI/dudVbGkVT+xkh1z1IsKeYiD2ef4Ddy2QQKBgQDIqOuaml9bnJpKie9Z0ysiPWxc771byxhgx7bwsoJey4x5bcLx+G9IAvkGwWFUl+25jgpeVn/LZ6147e9ozeip7WSKvStniND+CB7SvA5ZDRm7CfqFQub//9Q1DWNfl+ThGAXHMlKgS7DanLqvpUsRdhUOceZwwrdkV93v7by8nQKBgQCx8EdYbxNIEnVI3Y98YCAWtvgBCCa8yurL+9IXe9VKCFGdGRZ4b61GWDNyjUAfiboXY4ByzvX4cdlZ1euVmqMYsEv28xXEFdGxSDpa+oeETbv1U2GEGL4Ups3z28Sx4TGGSyvReyQOhZftIF6vCZtZ8dZMEf8IdxyudJkcJp+u+QKBgBFtemkHF1khlNT8felTSd/DbfH0cIHUdd2R+vWUy3XoP98cBV52sVOTzoUjroxmVaNUDtp6sMa9znc+UxjLKXX4xE64d1iarWwi0GqFIsnhNWblSvjgAqghVBD3hLX8v0g9ieLvH/YEHOwfyKcQuCBgHRwQEG+iucLhTslT4JyRAoGAHa25CKwGKEhD3bJuw0z5LTC5btqgM28Y+Ir5AMe7zIxUqIJNuCrQWOJPOnUK0/fR3SLQgtW4OwcqPIysrZhMScrl8Luczsbg4dPtP813mv6oMgQFSNYjpigoQ9tNFGo+K2sQVPFYEz//FiMHB+TvT3JBzxBVXGEZnJOAEizzB2kCgYEAxUFRiJMcmp5IyGcFlmGP219OcEfzt8BV8s3yoPHPpgYX/zPsH9764UMSZb+FRXFLd8HC+UqqppQ4cq2RmMu5X7H/DWoj9FqXgusjOmZUyWiJgTPC4ktFesuhJhCHuk/50/nXmc6O8rWLwXqXf1XNaoNfzDmZNQ20jRZGr8eVc4g=
-  app-public-key: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwN6xgd6Ad8v2hIIsQVnbt8a3JituR8o4Tc3B5WlcFR55bz4OMqrG/356Ur3cPbc2Fe8ArNd/0gZbC9q56Eb16JTkVNA/fye4SXznWxdyBPR7+guuJZHc/VW2fKH2lfZ2P3Tt0QkKZZoawYOGSMdIvO+WqK44updyax0ikK6JlNQIDAQAB
-  wx-app-id:
-  notify-url: https://raex.izouma.com/notify/adapay

+ 112 - 21
src/test/java/com/izouma/nineth/service/AdapayServiceTest.java

@@ -1,26 +1,49 @@
 package com.izouma.nineth.service;
 
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.annotation.ExcelProperty;
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.huifu.adapay.Adapay;
 import com.huifu.adapay.core.exception.BaseAdaPayException;
 import com.huifu.adapay.model.AdapayCommon;
+import com.huifu.adapay.model.MerConfig;
 import com.huifu.adapay.model.Payment;
-import com.izouma.nineth.ApplicationTests;
-import com.izouma.nineth.config.GeneralProperties;
+import com.huifu.adapay.model.Refund;
+import com.izouma.nineth.utils.SnowflakeIdWorker;
+import com.izouma.nineth.utils.excel.BigIntegerConverter;
+import com.izouma.nineth.utils.excel.LocalDateConverter;
+import com.izouma.nineth.utils.excel.LocalDateTimeConverter;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
 import org.junit.Test;
-import org.springframework.beans.factory.annotation.Autowired;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-public class AdapayServiceTest extends ApplicationTests {
-    @Autowired
-    private AdapayService     adapayService;
-    @Autowired
-    private GeneralProperties generalProperties;
+public class AdapayServiceTest {
+    private final String appId = "app_f8760acc-f4d8-46f6-8f70-d80e36517075";
+
+    public AdapayServiceTest() {
+        Adapay.debug = true;
+        Adapay.prodMode = true;
+
+        MerConfig merConfig = new MerConfig();
+        merConfig.setApiKey("api_live_8818cac1-894b-40bc-ac77-803e02e9c260");
+        merConfig.setApiMockKey("api_test_0b1b0eb9-30e1-4acd-8e03-10b529de1856");
+        merConfig.setRSAPrivateKey("MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQCnIaIrFP598qcf/s3FqXxMTjrVAevnf1w5CAMdJqcRFv0WvdLEmNRxxqAYSLl/iQ8AyU4yqVwkwYqvn/aENBg0iQ5h5qboxb8T6xmrZLctk97TiIuCUwbd7Q5NBHJXzHlaKc1p1KBvTCJDMw8+t0Jh3sBkBvu7l0KPliEQHtPLBDkKvy3NBQD6BMy47kPersjSUH53HBvNpcjcPZGpUX/TmL3SNkS98RkoebFxuorK5UdazYN5xvarjfcYziShIjU3WIZJb52DGUxYWTk6vJKZrJhw7AhWIEQpH7qJxvml/B8RMQ4guHdtp3ojxwkHDtZdPU9rY8i6EHwba4qOYgobAgMBAAECggEAT36L5/oAYl+8ZleIAHBxEspS6WYUkvPdJbNN59uus04/60U2rxQSWFulYmeU87h5TmJxs18i2MjF8msfkhpFORfHo4FV+nm0PQEiIIezKRagcfUMhlx/c6eBmdh3mpNDVUN01NWxyb5ovZXXtnjsNikBUZKQwdVcb3d1GnnPO0xtt6/0xwiduCkA2ihS1tgnsYYDhMHgukIdZ3eczn3stRPQ+QyCt1JWS6DDd1nS3S2RyPZw8P9Z1zzJFVKH8z3bGqk3/98Lw7Hw+rKFnKhIA6/H9ZVORKw5OuGC3Ozy6cVbmUn8tuw3sC0NdR7w56dedB+fjJB8od0nahX1Cc6eQQKBgQDckcenslWqjs2PbncwW1wqlw7FdJX9rzJAg7kp9ItpHCoNi/kSgXeLphHXWJmyj7a1BkWynmTGxO48X3dPXUrDPFKJc42fSbxMgAQdtc/A2z+v7Ga/oUpH8jajKfKmcgeRX026R7gd9W0yi0EW+C0WdFhrzNKKY4shvnYy9lc+QwKBgQDB+mHSllqLqYru0bLrtKOKJXaR3N3INxDBZKnRqba4tUKN35IVIexiEMkHmC51jtjoRyA5Y+fc/8P11i9FbuShtRVGHWeyDibKlwff5zrETveSLTpSULBKZ6MsFSm0Fo1krSUC1QTUGG5VX/wwWm9AB2UKJqG5cMDd3i3RiPeDSQKBgBs1ED+rS83iF5Eduy4H1vKZ94R7wRSty7ERjoGSXK/2fWl2Xp7dwXVEYucBUtQnzg2+XFKQHzY1jH19+SWdCF/UzQmPa2S+n6+ACwHvL1VGtjBpJLN2nccKJZsyzW+imTRhYSEdP6TSZUnay4idzFH8v/tsJHxVkw/ygnn+0PwpAn8uOHsWsrzgioWQYmc/wss1H7ghCX/PNU/IxTOxwb7IRGiXZa5pWqv4sgc0yA5J9L+6mTgUdLnK7ybCbUbWRJY18fAfxOHwi26y10oJEA/wtuBG9H/xHUjkcc1vs5s8TiNi2d73zcpYv3mK3lQ5MVNQ7nIk+Q+QIE3UkBxa0UgpAoGBAMDwg0ebzBEZsV2cr/Er2b25LsXteDJ+V67plBNrv+A1/omA9a52sWek4bY0D+Uu6zPTDaLj9BhHC2wJmThYl0eLRKyDKYQslBR3h253Gsn3If6RH9/tSyDsQ88iAEI1f6QH27bGHL9VDrsLGEFg5E7ZEzFQuJPqoUvBOoURNwa6");
+        merConfig.setRSAPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApyGiKxT+ffKnH/7Nxal8TE461QHr539cOQgDHSanERb9Fr3SxJjUccagGEi5f4kPAMlOMqlcJMGKr5/2hDQYNIkOYeam6MW/E+sZq2S3LZPe04iLglMG3e0OTQRyV8x5WinNadSgb0wiQzMPPrdCYd7AZAb7u5dCj5YhEB7TywQ5Cr8tzQUA+gTMuO5D3q7I0lB+dxwbzaXI3D2RqVF/05i90jZEvfEZKHmxcbqKyuVHWs2Decb2q433GM4koSI1N1iGSW+dgxlMWFk5OrySmayYcOwIViBEKR+6icb5pfwfETEOILh3bad6I8cJBw7WXT1Pa2PIuhB8G2uKjmIKGwIDAQAB");
+        Adapay.publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwN6xgd6Ad8v2hIIsQVnbt8a3JituR8o4Tc3B5WlcFR55bz4OMqrG/356Ur3cPbc2Fe8ArNd/0gZbC9q56Eb16JTkVNA/fye4SXznWxdyBPR7+guuJZHc/VW2fKH2lfZ2P3Tt0QkKZZoawYOGSMdIvO+WqK44updyax0ikK6JlNQIDAQAB";
+        try {
+            Adapay.initWithMerConfig(merConfig);
+        } catch (Exception e) {
+        }
+    }
 
     @Test
     public void testPay() throws BaseAdaPayException {
@@ -36,7 +59,7 @@ public class AdapayServiceTest extends ApplicationTests {
             put("amount", BigDecimal.valueOf(0.05));
         }});
 
-        paymentParams.put("app_id", "app_f8760acc-f4d8-46f6-8f70-d80e36517075");
+        paymentParams.put("app_id", appId);
         paymentParams.put("order_no", "jsdk_payment" + System.currentTimeMillis());
         paymentParams.put("pay_channel", "wx_pub");
         paymentParams.put("pay_amt", "0.10");
@@ -59,34 +82,102 @@ public class AdapayServiceTest extends ApplicationTests {
         params.put("order_no", "host_wx_lite_params_sdk_" + System.currentTimeMillis());
         params.put("adapay_func_code", "wxpay.createOrder");
         params.put("pay_amt", "0.02");
-        params.put("app_id", "app_f8760acc-f4d8-46f6-8f70-d80e36517075");
+        params.put("app_id", appId);
         params.put("currency", "cny");
         params.put("goods_title", "Your goods_title");
         params.put("goods_desc", "Your goods_desc");
         params.put("description", "payment Discription");
-        params.put("callback_url", generalProperties.getHost() + "/9th/orders");
+        params.put("callback_url", "/9th/orders");
         Map<String, Object> response = AdapayCommon.requestAdapayUits(params);
         System.out.println("payment result=" + JSON.toJSONString(response, SerializerFeature.PrettyFormat));
     }
 
-    @Test
-    public void createMember() throws BaseAdaPayException {
-        adapayService.createMember(99999999999999L, "15077886171", "熊竹", "321002199408304614");
+    @Data
+    public static class RefundOrder {
+        @ExcelProperty("交易时间")
+        private LocalDateTime time;
+
+        @ExcelProperty("订单号")
+        private String id;
+
+        @ExcelProperty("支付流水号")
+        private String serial;
+
+        @ExcelProperty("第三方订单号")
+        private String thirdId;
+
+        @ExcelProperty("支付宝/微信订单号")
+        private String txId;
+
+        @ExcelProperty("交易金额")
+        private String amount;
+
+        private String refundId;
     }
 
     @Test
-    public void createSettleAccount() throws BaseAdaPayException {
-        adapayService.createSettleAccount("99999999999999", "熊竹", "321002199408304614",
-                "15077886171", "6222024301070380163");
+    public void refund() throws BaseAdaPayException {
+        List<RefundOrder> orders = EasyExcel.read("/Users/drew/Downloads/merTransDetail_0284905900625472_20211201_20211215_1639557451.xlsx")
+                .head(RefundOrder.class)
+                .registerConverter(new LocalDateConverter())
+                .registerConverter(new LocalDateTimeConverter())
+                .registerConverter(new BigIntegerConverter())
+                .sheet().doReadSync();
+        System.out.println(orders.size());
+        for (RefundOrder order : orders) {
+            String refundId = new SnowflakeIdWorker(0, 0).nextId() + "";
+            Map<String, Object> refundParams = new HashMap<>();
+            refundParams.put("refund_amt", order.getAmount());
+            refundParams.put("refund_order_no", new SnowflakeIdWorker(0, 0).nextId() + "");
+            Map<String, Object> response = Refund.create(order.getId(), refundParams);
+            order.setRefundId(refundId);
+        }
+        EasyExcel.write("/Users/drew/Desktop/refund.xlsx", RefundOrder.class).sheet("sheet")
+                .registerConverter(new LocalDateConverter())
+                .registerConverter(new LocalDateTimeConverter())
+                .registerConverter(new BigIntegerConverter())
+                .doWrite(orders);
     }
 
+
     @Test
-    public void delSettleAccount() throws BaseAdaPayException {
-        adapayService.delSettleAccount("1110", "0288514678171392");
+    public void queryrefund() throws BaseAdaPayException {
+        List<RefundOrder> orders = EasyExcel.read("/Users/drew/Desktop/refund.xlsx")
+                .head(RefundOrder.class)
+                .registerConverter(new LocalDateConverter())
+                .registerConverter(new LocalDateTimeConverter())
+                .registerConverter(new BigIntegerConverter())
+                .sheet().doReadSync();
+        System.out.println(orders.size());
+        List<String> success = new ArrayList<>();
+        List<String> fail = new ArrayList<>();
+        for (RefundOrder order : orders) {
+            Map<String, Object> refundParams = new HashMap<>();
+            refundParams.put("refund_order_no", order.getRefundId());
+            Map<String, Object> refund = Refund.query(refundParams);
+            System.out.println(refund.get("refunds"));
+            try {
+                if (((JSONArray) refund.get("refunds")).getJSONObject(0).getString("trans_status").equals("S")) {
+                    success.add(order.getId());
+                } else {
+                    fail.add(order.getId());
+                }
+            } catch (Exception e) {
+                fail.add(order.getId());
+            }
+        }
+        System.out.println("success:" + success.size());
+        System.out.println("fail:" + fail.size());
+        System.out.println(StringUtils.join(fail, ","));
     }
 
     @Test
-    public void queryBalance() throws BaseAdaPayException {
-        adapayService.queryBalance("1110", "0288514678171392");
+    public void queryList() throws BaseAdaPayException {
+        Map<String, Object> paymentParams = new HashMap<>();
+        paymentParams.put("app_id", appId);
+        paymentParams.put("page_index", "1");
+        paymentParams.put("page_size", "10");
+        paymentParams.put("order_no", "928303191131422720");
+        Map<String, Object> paymentList = Payment.queryList(paymentParams);
     }
 }

+ 0 - 6
src/test/java/com/izouma/nineth/service/AssetServiceTest.java

@@ -57,12 +57,6 @@ class AssetServiceTest extends ApplicationTests {
         assetService.createAsset(blindBoxItem, user, order.getId(), order.getPrice(), "出售", 1);
     }
 
-    @Test
-    public void mint() {
-        Asset asset = assetRepo.findById(4622L).get();
-        assetMintService.mint(asset, 1L);
-    }
-
     @Test
     public void setHistory() {
         assetService.setHistory();

+ 0 - 3
src/test/java/com/izouma/nineth/service/NFTServiceTest.java

@@ -19,9 +19,6 @@ public class NFTServiceTest extends ApplicationTests {
 
     @Test
     public void createToken() throws Exception {
-        for (int i = 0; i < 10; i++) {
-            nftService.createToken("raex_official");
-        }
     }
 
     @Test