AssetService.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. package com.izouma.nineth.service;
  2. import com.izouma.nineth.TokenHistory;
  3. import com.izouma.nineth.domain.*;
  4. import com.izouma.nineth.dto.PageQuery;
  5. import com.izouma.nineth.dto.UserHistory;
  6. import com.izouma.nineth.enums.AssetStatus;
  7. import com.izouma.nineth.enums.CollectionSource;
  8. import com.izouma.nineth.enums.CollectionType;
  9. import com.izouma.nineth.enums.OrderStatus;
  10. import com.izouma.nineth.event.TransferAssetEvent;
  11. import com.izouma.nineth.exception.BusinessException;
  12. import com.izouma.nineth.lock.RedisLockable;
  13. import com.izouma.nineth.repo.*;
  14. import com.izouma.nineth.utils.JpaUtils;
  15. import com.izouma.nineth.utils.SecurityUtils;
  16. import lombok.AllArgsConstructor;
  17. import lombok.extern.slf4j.Slf4j;
  18. import org.apache.commons.lang3.StringUtils;
  19. import org.springframework.beans.BeanUtils;
  20. import org.springframework.context.ApplicationContext;
  21. import org.springframework.data.domain.Page;
  22. import org.springframework.data.domain.Pageable;
  23. import org.springframework.scheduling.annotation.Async;
  24. import org.springframework.scheduling.annotation.AsyncResult;
  25. import org.springframework.stereotype.Service;
  26. import java.math.BigDecimal;
  27. import java.time.LocalDateTime;
  28. import java.util.ArrayList;
  29. import java.util.List;
  30. import java.util.Optional;
  31. import java.util.Set;
  32. import java.util.concurrent.Future;
  33. import java.util.stream.Collectors;
  34. @Service
  35. @AllArgsConstructor
  36. @Slf4j
  37. public class AssetService {
  38. private AssetRepo assetRepo;
  39. private UserRepo userRepo;
  40. private CollectionRepo collectionRepo;
  41. private ApplicationContext applicationContext;
  42. private OrderRepo orderRepo;
  43. private TokenHistoryRepo tokenHistoryRepo;
  44. private AssetMintService assetMintService;
  45. public Page<Asset> all(PageQuery pageQuery) {
  46. return assetRepo.findAll(JpaUtils.toSpecification(pageQuery, Asset.class), JpaUtils.toPageRequest(pageQuery));
  47. }
  48. @Async
  49. public Future<Asset> createAsset(Collection collection, User user, Long orderId, BigDecimal price, String type, Integer number) {
  50. Asset asset = Asset.create(collection, user);
  51. asset.setNumber(number);
  52. asset.setOrderId(orderId);
  53. asset.setPrice(price);
  54. asset.setIpfsUrl(assetMintService.ipfsUpload(collection.getPic().get(0).getUrl()));
  55. assetRepo.save(asset);
  56. TokenHistory tokenHistory = tokenHistoryRepo.save(TokenHistory.builder()
  57. .tokenId(asset.getTokenId())
  58. .fromUser(collection.getMinter())
  59. .fromUserId(collection.getMinterId())
  60. .fromAvatar(collection.getMinterAvatar())
  61. .toUser(user.getNickname())
  62. .toUserId(user.getId())
  63. .toAvatar(user.getAvatar())
  64. .operation(type)
  65. .price(price)
  66. .build());
  67. assetMintService.mint(asset, tokenHistory.getId());
  68. return new AsyncResult<>(asset);
  69. }
  70. @Async
  71. public Future<Asset> createAsset(BlindBoxItem winItem, User user, Long orderId, BigDecimal price, String type, Integer number) {
  72. Asset asset = Asset.create(winItem, user);
  73. asset.setNumber(number);
  74. asset.setOrderId(orderId);
  75. asset.setPrice(price);
  76. asset.setIpfsUrl(assetMintService.ipfsUpload(winItem.getPic().get(0).getUrl()));
  77. assetRepo.save(asset);
  78. TokenHistory tokenHistory = tokenHistoryRepo.save(TokenHistory.builder()
  79. .tokenId(asset.getTokenId())
  80. .fromUser(winItem.getMinter())
  81. .fromUserId(winItem.getMinterId())
  82. .fromAvatar(winItem.getMinterAvatar())
  83. .toUser(user.getNickname())
  84. .toUserId(user.getId())
  85. .toAvatar(user.getAvatar())
  86. .operation(type)
  87. .price(price)
  88. .build());
  89. assetMintService.mint(asset, tokenHistory.getId());
  90. return new AsyncResult<>(asset);
  91. }
  92. public void publicShow(Long id) {
  93. Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
  94. if (asset.isPublicShow()) {
  95. return;
  96. }
  97. if (asset.getStatus() != AssetStatus.NORMAL) {
  98. throw new BusinessException("当前状态不可展示");
  99. }
  100. User owner = userRepo.findById(asset.getUserId()).orElseThrow(new BusinessException("用户不存在"));
  101. Collection collection = Collection.builder()
  102. .name(asset.getName())
  103. .pic(asset.getPic())
  104. .minter(asset.getMinter())
  105. .minterId(asset.getMinterId())
  106. .minterAvatar(asset.getMinterAvatar())
  107. .owner(owner.getNickname())
  108. .ownerId(owner.getId())
  109. .ownerAvatar(owner.getAvatar())
  110. .detail(asset.getDetail())
  111. .type(CollectionType.DEFAULT)
  112. .source(CollectionSource.TRANSFER)
  113. .sale(0)
  114. .stock(1)
  115. .total(1)
  116. .onShelf(true)
  117. .salable(false)
  118. .price(BigDecimal.valueOf(0))
  119. .properties(asset.getProperties())
  120. .canResale(asset.isCanResale())
  121. .royalties(asset.getRoyalties())
  122. .serviceCharge(asset.getServiceCharge())
  123. .assetId(id)
  124. .number(asset.getNumber())
  125. .build();
  126. collectionRepo.save(collection);
  127. asset.setPublicShow(true);
  128. asset.setPublicCollectionId(collection.getId());
  129. assetRepo.save(asset);
  130. }
  131. public void consignment(Long id, BigDecimal price) {
  132. Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
  133. User owner = userRepo.findById(asset.getUserId()).orElseThrow(new BusinessException("用户不存在"));
  134. if (StringUtils.isBlank(owner.getSettleAccountId())) {
  135. throw new BusinessException("请先绑定银行卡");
  136. }
  137. if (asset.isConsignment()) {
  138. throw new BusinessException("已寄售,请勿重新操作");
  139. }
  140. if (asset.getStatus() != AssetStatus.NORMAL) {
  141. throw new BusinessException("当前状态不可寄售");
  142. }
  143. if (asset.isPublicShow()) {
  144. cancelPublic(asset);
  145. }
  146. Collection collection = Collection.builder()
  147. .name(asset.getName())
  148. .pic(asset.getPic())
  149. .minter(asset.getMinter())
  150. .minterId(asset.getMinterId())
  151. .minterAvatar(asset.getMinterAvatar())
  152. .owner(owner.getNickname())
  153. .ownerId(owner.getId())
  154. .ownerAvatar(owner.getAvatar())
  155. .detail(asset.getDetail())
  156. .type(CollectionType.DEFAULT)
  157. .source(CollectionSource.TRANSFER)
  158. .sale(0)
  159. .stock(1)
  160. .total(1)
  161. .onShelf(true)
  162. .salable(true)
  163. .price(price)
  164. .properties(asset.getProperties())
  165. .canResale(asset.isCanResale())
  166. .royalties(asset.getRoyalties())
  167. .serviceCharge(asset.getServiceCharge())
  168. .assetId(id)
  169. .number(asset.getNumber())
  170. .build();
  171. collectionRepo.save(collection);
  172. asset.setPublicShow(true);
  173. asset.setConsignment(true);
  174. asset.setPublicCollectionId(collection.getId());
  175. asset.setSellPrice(price);
  176. assetRepo.save(asset);
  177. }
  178. public void cancelConsignment(Long id) {
  179. Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
  180. cancelConsignment(asset);
  181. }
  182. public void cancelConsignment(Asset asset) {
  183. if (asset.getPublicCollectionId() != null) {
  184. List<Order> orders = orderRepo.findByCollectionId(asset.getPublicCollectionId());
  185. if (orders.stream().anyMatch(o -> o.getStatus() != OrderStatus.CANCELLED)) {
  186. throw new BusinessException("已有订单不可取消");
  187. }
  188. collectionRepo.findById(asset.getPublicCollectionId())
  189. .ifPresent(collection -> {
  190. collection.setSalable(false);
  191. collectionRepo.save(collection);
  192. });
  193. }
  194. asset.setConsignment(false);
  195. assetRepo.save(asset);
  196. }
  197. public void cancelPublic(Long id) {
  198. Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
  199. cancelPublic(asset);
  200. }
  201. public void cancelPublic(Asset asset) {
  202. if (!asset.isPublicShow()) {
  203. return;
  204. }
  205. if (asset.isConsignment()) {
  206. cancelConsignment(asset);
  207. }
  208. Collection collection = collectionRepo.findById(asset.getPublicCollectionId())
  209. .orElseThrow(new BusinessException("无展示记录"));
  210. collectionRepo.delete(collection);
  211. asset.setPublicShow(false);
  212. asset.setCollectionId(null);
  213. assetRepo.save(asset);
  214. }
  215. public void usePrivilege(Long assetId, Long privilegeId) {
  216. Asset asset = assetRepo.findById(assetId).orElseThrow(new BusinessException("无记录"));
  217. asset.getPrivileges().stream().filter(p -> p.getId().equals(privilegeId)).forEach(p -> {
  218. p.setOpened(true);
  219. p.setOpenTime(LocalDateTime.now());
  220. p.setOpenedBy(SecurityUtils.getAuthenticatedUser().getId());
  221. });
  222. assetRepo.save(asset);
  223. }
  224. @Async
  225. public void transfer(Asset asset, BigDecimal price, User toUser, String reason, Long orderId) {
  226. Asset newAsset = new Asset();
  227. BeanUtils.copyProperties(asset, newAsset);
  228. newAsset.setId(null);
  229. newAsset.setUserId(toUser.getId());
  230. newAsset.setOwner(toUser.getNickname());
  231. newAsset.setOwnerId(toUser.getId());
  232. newAsset.setOwnerAvatar(toUser.getAvatar());
  233. newAsset.setPublicShow(false);
  234. newAsset.setConsignment(false);
  235. newAsset.setPublicCollectionId(null);
  236. newAsset.setStatus(AssetStatus.NORMAL);
  237. newAsset.setPrice(price);
  238. newAsset.setSellPrice(null);
  239. newAsset.setOrderId(orderId);
  240. assetRepo.save(newAsset);
  241. asset.setPublicShow(false);
  242. asset.setConsignment(false);
  243. asset.setPublicCollectionId(null);
  244. asset.setStatus(AssetStatus.GIFTED);
  245. asset.setOwner(toUser.getNickname());
  246. asset.setOwnerId(toUser.getId());
  247. asset.setOwnerAvatar(toUser.getAvatar());
  248. assetRepo.save(asset);
  249. tokenHistoryRepo.save(TokenHistory.builder()
  250. .tokenId(asset.getTokenId())
  251. .fromUser(asset.getOwner())
  252. .fromUserId(asset.getOwnerId())
  253. .fromAvatar(asset.getOwnerAvatar())
  254. .toUser(toUser.getNickname())
  255. .toUserId(toUser.getId())
  256. .toAvatar(toUser.getAvatar())
  257. .operation(reason)
  258. .build());
  259. if (orderId != null) {
  260. applicationContext.publishEvent(new TransferAssetEvent(this, true, newAsset));
  261. }
  262. }
  263. public List<TokenHistory> tokenHistory(String tokenId, Long assetId) {
  264. if (tokenId == null) {
  265. if (assetId == null) return new ArrayList<>();
  266. tokenId = assetRepo.findById(assetId).map(Asset::getTokenId).orElse(null);
  267. }
  268. if (tokenId == null) return new ArrayList<>();
  269. return tokenHistoryRepo.findByTokenIdOrderByCreatedAtDesc(tokenId);
  270. }
  271. @RedisLockable(key = "#id", expiration = 60, isWaiting = true)
  272. public void testLock(String id, String i) throws InterruptedException {
  273. Thread.sleep(1000);
  274. log.info("" + i);
  275. }
  276. public void setHistory() {
  277. List<Asset> assets = assetRepo.findByCreatedAtBefore(LocalDateTime.of(2021, 11, 22, 23, 59, 59));
  278. assets.parallelStream().forEach(asset -> {
  279. try {
  280. User owner = userRepo.findById(asset.getUserId()).orElseThrow(new BusinessException(""));
  281. Order order = orderRepo.findById(asset.getOrderId()).orElseThrow(new BusinessException(""));
  282. TokenHistory t = TokenHistory.builder()
  283. .tokenId(asset.getTokenId())
  284. .fromUser(asset.getMinter())
  285. .fromUserId(asset.getMinterId())
  286. .fromAvatar(asset.getMinterAvatar())
  287. .toUser(owner.getNickname())
  288. .toUserId(owner.getId())
  289. .toAvatar(owner.getAvatar())
  290. .operation("出售")
  291. .price(order.getPrice())
  292. .build();
  293. t.setCreatedAt(asset.getCreatedAt());
  294. tokenHistoryRepo.save(t);
  295. } catch (Exception e) {
  296. }
  297. });
  298. }
  299. public Page<UserHistory> userHistory(Long userId, Pageable pageable) {
  300. Page<TokenHistory> page = tokenHistoryRepo.userHistory(userId, pageable);
  301. Set<String> tokenIds = page.stream().map(TokenHistory::getTokenId).collect(Collectors.toSet());
  302. List<Asset> assets = tokenIds.isEmpty() ? new ArrayList<>() : assetRepo.findByTokenIdIn(tokenIds);
  303. return page.map(tokenHistory -> {
  304. UserHistory userHistory = new UserHistory();
  305. BeanUtils.copyProperties(tokenHistory, userHistory);
  306. Optional<Asset> asset = assets.stream().filter(a -> a.getTokenId().equals(tokenHistory.getTokenId()))
  307. .findAny();
  308. userHistory.setAssetName(asset.map(Asset::getName).orElse(null));
  309. userHistory.setPic(asset.map(Asset::getPic).orElse(new ArrayList<>()));
  310. switch (tokenHistory.getOperation()) {
  311. case "出售":
  312. userHistory.setDescription(tokenHistory.getToUserId().equals(userId) ? "作品交易——买入" : "作品交易——售出");
  313. case "空投":
  314. userHistory.setDescription("空投");
  315. case "转赠":
  316. userHistory.setDescription(tokenHistory.getToUserId().equals(userId) ? "他人赠送" : "作品赠送");
  317. case "转让":
  318. userHistory.setDescription(tokenHistory.getToUserId().equals(userId) ? "作品交易——买入" : "作品交易——售出");
  319. }
  320. return userHistory;
  321. });
  322. }
  323. }