package com.izouma.nineth.service; import com.izouma.nineth.config.GeneralProperties; import com.izouma.nineth.config.RedisKeys; import com.izouma.nineth.domain.TradeAuction; import com.izouma.nineth.domain.TradeAuctionOrder; import com.izouma.nineth.domain.TradeAuctionRecord; import com.izouma.nineth.dto.PageQuery; import com.izouma.nineth.enums.AuctionOrderStatus; import com.izouma.nineth.enums.TradeAuctionStatus; import com.izouma.nineth.exception.BusinessException; import com.izouma.nineth.repo.TradeAuctionOrderRepo; import com.izouma.nineth.repo.TradeAuctionRepo; import com.izouma.nineth.utils.JpaUtils; import com.izouma.nineth.utils.ObjUtils; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.data.domain.Page; import org.springframework.data.redis.core.BoundValueOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; import java.security.PrivateKey; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.TimeUnit; @Service @AllArgsConstructor @Slf4j public class TradeAuctionService { private TradeAuctionRepo tradeAuctionRepo; private RedisTemplate redisTemplate; private RocketMQTemplate rocketMQTemplate; private GeneralProperties generalProperties; private TradeAuctionOrderRepo tradeAuctionOrderRepo; private SysConfigService sysConfigService; public Page all(PageQuery pageQuery) { return tradeAuctionRepo .findAll(JpaUtils.toSpecification(pageQuery, TradeAuction.class), JpaUtils.toPageRequest(pageQuery)); } public TradeAuction save(TradeAuction record) { if (record.getId() != null) { TradeAuction orig = tradeAuctionRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录")); ObjUtils.merge(orig, record); return tradeAuctionRepo.save(orig); } // if (record.getAuctionType() == 1) { // record.setStartTime(LocalDate.now().atTime(8, 0)); // } else if (record.getAuctionType() == 2) { // record.setStartTime(LocalDate.now().atTime(11, 0)); // } else { // throw new BusinessException("未填写时间码"); // } if (record.getStartTime().getHour() != 20 & record.getStartTime().getHour() != 11) { throw new BusinessException("开始时间不是11点或20点,请修改!"); } record.setCurrentEndTime(record.getStartTime().plusHours(24)); record.setIncreasePer(6); record.setRoyalties(10); record.setCurrentStartTime(record.getStartTime()); record.setCurrentPrice(record.getPrice()); record.setStatus(TradeAuctionStatus.WAITING); BigDecimal result = record.getCurrentPrice().multiply(BigDecimal.valueOf(record.getIncreasePer())) .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP); record.setNextPrice(result.add(record.getPrice())); record.setEarning(record.getNextPrice().subtract(record.getPrice())); record.setFixedPrice(record.getPrice().multiply(BigDecimal.valueOf(150)) .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP)); BigDecimal serviceCharge = (BigDecimal.valueOf(0.03).multiply(record.getNextPrice())) .add(record.getCurrentPrice().subtract(record.getPrice())); // record.setEarning(result.subtract(record.getPrice())); record.setCommission(serviceCharge); record.setStock(1L); record.setSale(0L); return tradeAuctionRepo.save(record); } // public void transfer(Long id) { // TradeAuctionRecord tradeAuctionRecord = new TradeAuctionRecord(); // TradeAuction tradeAuction = tradeAuctionRepo.findById(id).orElseThrow(new BusinessException("暂无")); // tradeAuction.setStatus(TradeAuctionStatus.WAITING); // increaseSale(tr) // } public synchronized Long increaseStock(Long id, int number) { BoundValueOperations ops = redisTemplate.boundValueOps(RedisKeys.AUCTION_STOCK + id); if (ops.get() == null) { Boolean success = ops.setIfAbsent(Optional.ofNullable(tradeAuctionRepo.getStock(id)) .orElse(0), 7, TimeUnit.DAYS); log.info("创建redis库存:{}", success); } Long stock = ops.increment(number); redisTemplate.opsForHash().increment(RedisKeys.UPDATE_STOCK, id.toString(), 1); return stock; } public synchronized Integer getStock(Long id) { BoundValueOperations ops = redisTemplate.boundValueOps(RedisKeys.AUCTION_STOCK + id); Integer stock = (Integer) ops.get(); if (stock == null) { Boolean success = ops.setIfAbsent(Optional.ofNullable(tradeAuctionRepo.getStock(id)) .orElse(0), 7, TimeUnit.DAYS); log.info("创建redis库存:{}", success); return (Integer) ops.get(); } else { return stock; } } public synchronized Long decreaseStock(Long id, int number) { return increaseStock(id, -number); } public synchronized Long increaseSale(Long id, int number) { BoundValueOperations ops = redisTemplate.boundValueOps(RedisKeys.COLLECTION_SALE + id); if (ops.get() == null) { Boolean success = ops.setIfAbsent(Optional.ofNullable(tradeAuctionRepo.getSale(id)) .orElse(0), 7, TimeUnit.DAYS); log.info("创建redis销量:{}", success); } Long sale = ops.increment(number); redisTemplate.opsForHash().increment(RedisKeys.UPDATE_SALE, id.toString(), 1); // rocketMQTemplate.convertAndSend(generalProperties.getUpdateSaleTopic(), id); return sale; } public synchronized Long decreaseSale(Long id, int number) { return increaseSale(id, -number); } // @Debounce(key = "#id", delay = 500) public void syncStock(Long id) { Integer stock = (Integer) redisTemplate.opsForValue().get(RedisKeys.COLLECTION_STOCK + id); if (stock != null) { log.info("同步库存信息{}", id); tradeAuctionRepo.updateStock(id, stock); // cacheService.clearCollection(id); } } // @Debounce(key = "#id", delay = 500) public void syncSale(Long id) { Integer sale = (Integer) redisTemplate.opsForValue().get(RedisKeys.COLLECTION_SALE + id); if (sale != null) { log.info("同步销量信息{}", id); tradeAuctionRepo.updateSale(id, sale); // cacheService.clearCollection(id); } } @Scheduled(fixedRate = 6000) public void batchStartAuction() { List tradeAuctionStatuses = new ArrayList<>(); tradeAuctionStatuses.add(TradeAuctionStatus.WAITING); tradeAuctionStatuses.add(TradeAuctionStatus.NOTSTARTED); List tradeAuctions = tradeAuctionRepo .findByStatusInAndCurrentStartTimeBefore(tradeAuctionStatuses, LocalDateTime.now().plusSeconds(5)); tradeAuctions.parallelStream().forEach(o -> { try { TradeAuction auction = tradeAuctionRepo.findById(o.getId()) .orElseThrow(new BusinessException("订单不存在")); if (auction.getStatus() == TradeAuctionStatus.WAITING || auction .getStatus() == TradeAuctionStatus.NOTSTARTED) { start(auction); } } catch (Exception e) { log.error("取消易拍订单错误 " + o.getId(), e); } }); } public void start(TradeAuction tradeAuction) { tradeAuction.setStatus(TradeAuctionStatus.ONGOING); tradeAuction.setStock(1L); tradeAuctionRepo.save(tradeAuction); increaseStock(tradeAuction.getId(), 1); } @Scheduled(fixedRate = 6000) public void batchPurchaseAuction() { List tradeAuctionStatuses = new ArrayList<>(); tradeAuctionStatuses.add(TradeAuctionStatus.ONGOING); List tradeAuctions = tradeAuctionRepo .findByStatusInAndCurrentEndTimeBefore(tradeAuctionStatuses, LocalDateTime.now().plusSeconds(5)); tradeAuctions.parallelStream().forEach(o -> { try { TradeAuction auction = tradeAuctionRepo.findById(o.getId()) .orElseThrow(new BusinessException("订单不存在")); if (auction.getStatus() == TradeAuctionStatus.ONGOING) { purchase(auction); } } catch (Exception e) { log.error("取消易拍订单错误 " + o.getId(), e); } }); } public void purchase(TradeAuction tradeAuction) { if (tradeAuction.getCurrentOrderId() == null) { pass(tradeAuction); } else { TradeAuctionOrder tradeAuctionOrder = tradeAuctionOrderRepo.findById(tradeAuction.getCurrentOrderId()) .orElseThrow(new BusinessException("暂无")); tradeAuction.setStatus(TradeAuctionStatus.PURCHASED); tradeAuction.setPurchasedPrice(tradeAuction.getCurrentPrice()); // int time = sysConfigService.getInt("auction_cancel_time"); tradeAuction.setCurrentEndTime(LocalDateTime.now().plusHours(48)); tradeAuctionRepo.save(tradeAuction); tradeAuctionOrder.setTradeAuctionStatus(tradeAuction.getStatus()); tradeAuctionOrder.setCurrentPrice(tradeAuctionOrder.getPrice()); tradeAuctionOrderRepo.save(tradeAuctionOrder); decreaseStock(tradeAuction.getId(), 1); } } @Scheduled(fixedRate = 6000) public void batchPassAuction() { List tradeAuctionStatuses = new ArrayList<>(); tradeAuctionStatuses.add(TradeAuctionStatus.PURCHASED); List tradeAuctions = tradeAuctionRepo .findByStatusInAndCurrentEndTimeBefore(tradeAuctionStatuses, LocalDateTime.now().plusSeconds(5)); tradeAuctions.parallelStream().forEach(o -> { try { TradeAuction auction = tradeAuctionRepo.findById(o.getId()) .orElseThrow(new BusinessException("订单不存在")); if (auction.getStatus() == TradeAuctionStatus.PURCHASED) { pass(auction); } } catch (Exception e) { log.error("取消易拍订单错误 " + o.getId(), e); } }); } public void pass(TradeAuction tradeAuction) { tradeAuction.setStatus(TradeAuctionStatus.PASS); tradeAuctionRepo.save(tradeAuction); if (tradeAuction.getCurrentOrderId() != null) { TradeAuctionOrder tradeAuctionOrder = tradeAuctionOrderRepo.findById(tradeAuction.getCurrentOrderId()) .orElseThrow(new BusinessException("暂无订单")); tradeAuctionOrder.setStatus(AuctionOrderStatus.PASS); tradeAuctionOrder.setTradeAuctionStatus(tradeAuction.getStatus()); tradeAuctionOrderRepo.save(tradeAuctionOrder); } decreaseStock(tradeAuction.getId(), 1); } }