# Coverage Summary for Class: BuyerService (cn.edu.ecnu.stu.bookstore.service.impl)

Class | Method, % | Line, %
--- | --- | ---
BuyerService | 100% (10/10) | 85.1% (63/74)
BuyerService$$EnhancerBySpringCGLIB$$7b9f9cbc
BuyerService$$EnhancerBySpringCGLIB$$7b9f9cbc$$FastClassBySpringCGLIB$$3da5d183
BuyerService$$EnhancerBySpringCGLIB$$ed30e237
BuyerService$$EnhancerBySpringCGLIB$$ed30e237$$FastClassBySpringCGLIB$$44c591ad
BuyerService$$FastClassBySpringCGLIB$$f1ad8679
Total | 100% (10/10) | 85.1% (63/74)

     package cn.edu.ecnu.stu.bookstore.service.impl;

     import cn.edu.ecnu.stu.bookstore.component.AppException;
     import cn.edu.ecnu.stu.bookstore.component.Constants;
     import cn.edu.ecnu.stu.bookstore.config.RabbitMqConfig;
     import cn.edu.ecnu.stu.bookstore.mapper.BookMapper;
     import cn.edu.ecnu.stu.bookstore.mapper.OrderMapper;
     import cn.edu.ecnu.stu.bookstore.mapper.StoreMapper;
     import cn.edu.ecnu.stu.bookstore.mapper.UserMapper;
     import cn.edu.ecnu.stu.bookstore.pojo.*;
     import cn.edu.ecnu.stu.bookstore.pojo.vo.NewOrderVO;
     import org.springframework.amqp.rabbit.core.RabbitTemplate;
     import org.springframework.beans.factory.annotation.Autowired;
     import org.springframework.context.annotation.Lazy;
     import org.springframework.security.core.context.SecurityContextHolder;
     import org.springframework.security.crypto.password.PasswordEncoder;
     import org.springframework.stereotype.Service;
     import org.springframework.transaction.annotation.Transactional;

     import java.math.BigDecimal;
     import java.util.*;
     import java.util.stream.Collectors;

     @Service
     public class BuyerService {

         @Autowired
         private BookMapper bookMapper;

         @Autowired
         private OrderMapper orderMapper;

         @Autowired
         private UserMapper userMapper;

         @Autowired
         private StoreMapper storeMapper;

         @Autowired
         private PasswordEncoder encoder;

         @Autowired
         @Lazy
         private BuyerService buyerService;

         @Autowired
         private RabbitTemplate rabbitTemplate;

         public void newOrder(NewOrderVO newOrderVO) {
             List<Map<String, Object>> bookList = newOrderVO.getBooks();
             if(bookList.size() < 1)
                 throw new AppException(Constants.CLIENT_ERROR, Constants.ORDER_IS_NULL_ERROR);
             HashMap<String, Integer> bookMap = new HashMap<>();
             for(Map<String, Object> map : bookList) {
                 bookMap.put((String) map.get("id"), (Integer) map.get("count"));
             }
             String storeId = newOrderVO.getStoreId();
             Store store = storeMapper.getStoreById(storeId);
             if(store == null)
                 throw new AppException(Constants.CLIENT_ERROR, Constants.STORE_NON_EXIST_ERROR);

             buyerService.insertOrder(store, bookMap, bookList);
         }

         @Transactional
         public void insertOrder(Store store, HashMap<String, Integer> bookMap, List<Map<String, Object>> bookList) {
             String storeId = store.getStoreId();
             List<Book> books = bookMapper.batchSelect(storeId, bookMap.keySet());
             if(books.size() != bookList.size())
                 throw new AppException(Constants.CLIENT_ERROR, Constants.BOOK_ERROR);
             List<Map<String, Object>> list = books.stream().map(book -> {
                 int count = bookMap.get(book.getBookId());
                 if(count > book.getStockLevel())
                     throw new AppException(Constants.CLIENT_ERROR, Constants.STOCK_LEVEL_ERROR);
                 Map<String, Object> map = new HashMap<>();
                 map.put("count", count);
                 map.put("book", book);
                 return map;
             }).collect(Collectors.toList());
             BigDecimal sum = new BigDecimal(0);
             for(Book book : books) {
                 sum = sum.add(book.getPrice().multiply(BigDecimal.valueOf(bookMap.get(book.getBookId()))));
             }
             User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
             String orderId = UUID.randomUUID().toString();
             Order order = Order.builder().orderId(orderId).buyerId(user.getId()).storeId(storeId)
                             .price(sum).status(OrderStatus.WAIT_PAYMENT)
                             .build();
             orderMapper.insert(order);
             orderMapper.insertOrderBook(orderId, list);
             for (Map<String, Object> map : list) {
                 Book book = (Book)map.get("book");
                 bookMapper.minusStockLevel(book.getBookId(), (int)map.get("count"));
             }
             rabbitTemplate.convertAndSend(RabbitMqConfig.EXPIRED_ORDER_EXCHANGE, RabbitMqConfig.EXPIRED_ORDER_ROUTING_KEY,
                     orderId, message -> {
                         message.getMessageProperties().setDelay(10000);
                         return message;
                     });
         }

         public void payment(Integer userId, String orderId, String password) {
             User user = userMapper.selectOneById(userId);
             if(!encoder.matches(password, user.getPassword()))
                 throw new AppException(Constants.CLIENT_ERROR, Constants.PASSWORD_ERROR);
             Order order = orderMapper.selectById(orderId);
             if(order == null)
                 throw new AppException(Constants.CLIENT_ERROR, Constants.ORDER_NON_EXIST_ERROR);
             if(!order.getStatus().equals(OrderStatus.WAIT_PAYMENT))
                 throw new AppException(Constants.CLIENT_ERROR, Constants.ORDER_HAS_PAID_ERROR);
             if(order.getPrice().compareTo(user.getBalance()) > 0)
                 throw new AppException(Constants.CLIENT_ERROR, Constants.BALANCE_ERROR);
             buyerService.updateBalanceAndOrder(storeMapper.getStoreById(order.getStoreId()).getSellerId(), order);
         }

         @Transactional
         public void updateBalanceAndOrder(Integer sellerId, Order order) {
             orderMapper.updateOrderStatus(order.getOrderId(), OrderStatus.WAIT_SEND);
             BigDecimal price = order.getPrice();
             userMapper.minusBalance(order.getBuyerId(), price);
             userMapper.addBalance(sellerId, price);
         }

         public void addFunds(String username, String password, BigDecimal addValue) {
             User user = userMapper.selectOneByName(username);
             if(!encoder.matches(password, user.getPassword()))
                 throw new AppException(Constants.CLIENT_ERROR, Constants.PASSWORD_ERROR);
             userMapper.addBalance(user.getId(), addValue);

         }

         public List<Order> getOrderList() {
             User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
             return orderMapper.select(user.getId(), OrderStatus.WAIT_PAYMENT);

         }

         public void takeDelivery(String orderId) {
             Order order = orderMapper.selectById(orderId);
             if(order == null)
                 throw new AppException(Constants.CLIENT_ERROR, Constants.ORDER_NON_EXIST_ERROR);
             User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
             if(!order.getBuyerId().equals(user.getId()))
                 throw new AppException(Constants.CLIENT_ERROR, Constants.AUTHORITY_ERROR);
             if(!order.getStatus().equals(OrderStatus.WAIT_RECEIVE))
                 throw new AppException(Constants.CLIENT_ERROR, Constants.STATUS_ERROR);
             orderMapper.updateOrderStatus(orderId, OrderStatus.COMPLETED);

         }
     }