package com.izouma.nineth.service; import com.izouma.nineth.TokenHistory; import com.izouma.nineth.domain.*; import com.izouma.nineth.dto.PageQuery; import com.izouma.nineth.enums.AssetStatus; import com.izouma.nineth.enums.CollectionSource; import com.izouma.nineth.enums.CollectionType; import com.izouma.nineth.enums.OrderStatus; import com.izouma.nineth.event.TransferAssetEvent; import com.izouma.nineth.exception.BusinessException; import com.izouma.nineth.lock.RedisLockable; import com.izouma.nineth.repo.*; import com.izouma.nineth.utils.JpaUtils; import com.izouma.nineth.utils.SecurityUtils; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.context.ApplicationContext; import org.springframework.data.domain.Page; 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.util.ArrayList; import java.util.List; import java.util.concurrent.Future; @Service @AllArgsConstructor @Slf4j public class AssetService { private AssetRepo assetRepo; private UserRepo userRepo; private CollectionRepo collectionRepo; private ApplicationContext applicationContext; private OrderRepo orderRepo; private TokenHistoryRepo tokenHistoryRepo; private AssetMintService assetMintService; public Page all(PageQuery pageQuery) { return assetRepo.findAll(JpaUtils.toSpecification(pageQuery, Asset.class), JpaUtils.toPageRequest(pageQuery)); } @Async public Future createAsset(Collection collection, User user, Long orderId, BigDecimal price, String type, Integer number) { Asset asset = Asset.create(collection, user); asset.setOrderId(orderId); asset.setPrice(price); asset.setIpfsUrl(assetMintService.ipfsUpload(collection.getPic().get(0).getUrl())); assetRepo.save(asset); TokenHistory tokenHistory = tokenHistoryRepo.save(TokenHistory.builder() .tokenId(asset.getTokenId()) .fromUser(collection.getMinter()) .fromUserId(collection.getMinterId()) .toUser(user.getNickname()) .toUserId(user.getId()) .operation(type) .price(price) .build()); assetMintService.mint(asset, tokenHistory.getId()); return new AsyncResult<>(asset); } @Async public Future createAsset(BlindBoxItem winItem, User user, Long orderId, BigDecimal price, String type, Integer number) { Asset asset = Asset.create(winItem, user); asset.setOrderId(orderId); asset.setPrice(price); asset.setIpfsUrl(assetMintService.ipfsUpload(winItem.getPic().get(0).getUrl())); assetRepo.save(asset); TokenHistory tokenHistory = tokenHistoryRepo.save(TokenHistory.builder() .tokenId(asset.getTokenId()) .fromUser(winItem.getMinter()) .fromUserId(winItem.getMinterId()) .toUser(user.getNickname()) .toUserId(user.getId()) .operation(type) .price(price) .build()); assetMintService.mint(asset, tokenHistory.getId()); return new AsyncResult<>(asset); } public void publicShow(Long id) { Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录")); if (asset.isPublicShow()) { return; } if (asset.getStatus() != AssetStatus.NORMAL) { throw new BusinessException("当前状态不可展示"); } User owner = userRepo.findById(asset.getUserId()).orElseThrow(new BusinessException("用户不存在")); Collection collection = Collection.builder() .name(asset.getName()) .pic(asset.getPic()) .minter(asset.getMinter()) .minterId(asset.getMinterId()) .minterAvatar(asset.getMinterAvatar()) .owner(owner.getNickname()) .ownerId(owner.getId()) .ownerAvatar(owner.getAvatar()) .detail(asset.getDetail()) .type(CollectionType.DEFAULT) .source(CollectionSource.TRANSFER) .sale(0) .stock(1) .total(1) .onShelf(true) .salable(false) .price(BigDecimal.valueOf(0)) .properties(asset.getProperties()) .canResale(asset.isCanResale()) .royalties(asset.getRoyalties()) .serviceCharge(asset.getServiceCharge()) .assetId(id) .number(asset.getNumber()) .build(); collectionRepo.save(collection); asset.setPublicShow(true); asset.setPublicCollectionId(collection.getId()); assetRepo.save(asset); } public void consignment(Long id, BigDecimal price) { Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录")); if (asset.isConsignment()) { throw new BusinessException("已寄售,请勿重新操作"); } if (asset.getStatus() != AssetStatus.NORMAL) { throw new BusinessException("当前状态不可寄售"); } if (asset.isPublicShow()) { cancelPublic(asset); } User owner = userRepo.findById(asset.getUserId()).orElseThrow(new BusinessException("用户不存在")); Collection collection = Collection.builder() .name(asset.getName()) .pic(asset.getPic()) .minter(asset.getMinter()) .minterId(asset.getMinterId()) .minterAvatar(asset.getMinterAvatar()) .owner(owner.getNickname()) .ownerId(owner.getId()) .ownerAvatar(owner.getAvatar()) .detail(asset.getDetail()) .type(CollectionType.DEFAULT) .source(CollectionSource.TRANSFER) .sale(0) .stock(1) .total(1) .onShelf(true) .salable(true) .price(price) .properties(asset.getProperties()) .canResale(asset.isCanResale()) .royalties(asset.getRoyalties()) .serviceCharge(asset.getServiceCharge()) .assetId(id) .number(asset.getNumber()) .build(); collectionRepo.save(collection); asset.setPublicShow(true); asset.setConsignment(true); asset.setPublicCollectionId(collection.getId()); asset.setSellPrice(price); assetRepo.save(asset); } public void cancelConsignment(Long id) { Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录")); cancelConsignment(asset); } public void cancelConsignment(Asset asset) { if (asset.getPublicCollectionId() != null) { List orders = orderRepo.findByCollectionId(asset.getPublicCollectionId()); if (orders.stream().anyMatch(o -> o.getStatus() != OrderStatus.CANCELLED)) { throw new BusinessException("已有订单不可取消"); } collectionRepo.findById(asset.getPublicCollectionId()) .ifPresent(collection -> { collection.setSalable(false); collectionRepo.save(collection); }); } asset.setConsignment(false); assetRepo.save(asset); } public void cancelPublic(Long id) { Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录")); cancelPublic(asset); } public void cancelPublic(Asset asset) { if (!asset.isPublicShow()) { return; } if (asset.isConsignment()) { cancelConsignment(asset); } Collection collection = collectionRepo.findById(asset.getPublicCollectionId()) .orElseThrow(new BusinessException("无展示记录")); collectionRepo.delete(collection); asset.setPublicShow(false); asset.setCollectionId(null); assetRepo.save(asset); } public void usePrivilege(Long assetId, Long privilegeId) { Asset asset = assetRepo.findById(assetId).orElseThrow(new BusinessException("无记录")); asset.getPrivileges().stream().filter(p -> p.getId().equals(privilegeId)).forEach(p -> { p.setOpened(true); p.setOpenTime(LocalDateTime.now()); p.setOpenedBy(SecurityUtils.getAuthenticatedUser().getId()); }); assetRepo.save(asset); } @Async public void transfer(Asset asset, BigDecimal price, User toUser, String reason, Long orderId) { Asset newAsset = new Asset(); BeanUtils.copyProperties(asset, newAsset); newAsset.setId(null); newAsset.setUserId(toUser.getId()); newAsset.setOwner(toUser.getNickname()); newAsset.setOwnerId(toUser.getId()); newAsset.setOwnerAvatar(toUser.getAvatar()); newAsset.setPublicShow(false); newAsset.setConsignment(false); newAsset.setPublicCollectionId(null); newAsset.setStatus(AssetStatus.NORMAL); newAsset.setPrice(price); newAsset.setSellPrice(null); newAsset.setOrderId(orderId); assetRepo.save(newAsset); asset.setPublicShow(false); asset.setConsignment(false); asset.setPublicCollectionId(null); asset.setStatus(AssetStatus.GIFTED); asset.setOwner(toUser.getNickname()); asset.setOwnerId(toUser.getId()); asset.setOwnerAvatar(toUser.getAvatar()); assetRepo.save(asset); tokenHistoryRepo.save(TokenHistory.builder() .tokenId(asset.getTokenId()) .fromUser(asset.getOwner()) .fromUserId(asset.getOwnerId()) .toUser(toUser.getNickname()) .toUserId(toUser.getId()) .operation(reason) .build()); if (orderId != null) { applicationContext.publishEvent(new TransferAssetEvent(this, true, newAsset)); } } public List tokenHistory(String tokenId, Long assetId) { if (tokenId == null) { if (assetId == null) return new ArrayList<>(); tokenId = assetRepo.findById(assetId).map(Asset::getTokenId).orElse(null); } if (tokenId == null) return new ArrayList<>(); return tokenHistoryRepo.findByTokenIdOrderByCreatedAtDesc(tokenId); } @RedisLockable(key = "#id", expiration = 60, isWaiting = true) public void testLock(String id, String i) throws InterruptedException { Thread.sleep(1000); log.info("" + i); } }