package com.sky.service.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.github.xiaoymin.knife4j.core.util.CollectionUtils; import com.sky.constant.MessageConstant; import com.sky.context.BaseContext; import com.sky.dto.*; import com.sky.entity.*; import com.sky.exception.AddressBookBusinessException; import com.sky.exception.OrderBusinessException; import com.sky.exception.ShoppingCartBusinessException; import com.sky.mapper.*; import com.sky.result.PageResult; import com.sky.service.OrderService; import com.sky.utils.HttpClientUtil; import com.sky.utils.WeChatPayUtil; import com.sky.vo.OrderPaymentVO; import com.sky.vo.OrderStatisticsVO; import com.sky.vo.OrderSubmitVO; import com.sky.vo.OrderVO; import com.sky.websocket.WebSocketServer; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; @Service @Slf4j public class OrderServiceImpl implements OrderService { @Resource private OrderMapper orderMapper; @Resource private OrderDetailMapper orderDetailMapper; @Resource private AddressBookMapper addressBookMapper; @Resource private ShoppingCartMapper shoppingCartMapper; @Resource private UserMapper userMapper; @Resource private WeChatPayUtil weChatPayUtil; @Resource private WebSocketServer webSocketServer; @Value("${sky.shop.address}") private String shopAddress; @Value("${sky.baidu.ak}") private String ak; /** * 用户下单 * * @param ordersSubmitDTO 用户下单请求数据 * @return OrderSubmitVO */ @Override @Transactional public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) { // 处理各种异常 (地址簿为空,购物车为空) AddressBook addressBook = addressBookMapper.getById(ordersSubmitDTO.getAddressBookId()); if (addressBook == null) { // 抛出异常,购物车为空 throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL); } checkOutOfRange(addressBook.getCityName() + addressBook.getDistrictName() + addressBook.getDetail()); // 1. 查询当前用户的购物车数据 ShoppingCart shoppingCart = new ShoppingCart(); Long currentId = BaseContext.getCurrentId(); shoppingCart.setUserId(currentId); List shoppingCartList = shoppingCartMapper.list(shoppingCart); if (shoppingCartList == null || shoppingCartList.isEmpty()) { throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL); } // 2. 向订单中插入1条数据 Orders orders = new Orders(); String address = addressBook.getProvinceName() + addressBook.getCityName() + addressBook.getDistrictName() + addressBook.getDetail(); BeanUtils.copyProperties(ordersSubmitDTO, orders); orders.setOrderTime(LocalDateTime.now()); orders.setPayStatus(Orders.UN_PAID); orders.setStatus(Orders.PENDING_PAYMENT); orders.setNumber(String.valueOf(System.currentTimeMillis())); orders.setPhone(addressBook.getPhone()); orders.setAddress(address); orders.setUserName(addressBook.getConsignee()); orders.setUserId(currentId); String sex = addressBook.getSex();// 性别 String consignee = addressBook.getConsignee().substring(0, 1);// 姓 if (sex.equals("1")) { orders.setConsignee(consignee + "女士"); } else { orders.setConsignee(consignee + "先生"); } orderMapper.insert(orders); ArrayList orderDetailArrayList = new ArrayList<>(); // 3. 向订单数据插入n条数据 for (ShoppingCart cart : shoppingCartList) { OrderDetail orderDetail = new OrderDetail(); BeanUtils.copyProperties(cart, orderDetail); orderDetail.setOrderId(orders.getId()); orderDetailArrayList.add(orderDetail); } orderDetailMapper.insertBatch(orderDetailArrayList); // 4. 清空当前用户购物车数据 shoppingCartMapper.deleteByUserId(currentId); // 5. 封装返回结果 return OrderSubmitVO.builder().id(orders.getId()).orderTime(orders.getOrderTime()).orderNumber(orders.getNumber()).orderAmount(orders.getAmount()).build(); } /** * 订单支付 * * @param ordersPaymentDTO OrdersPaymentDTO * @return OrderPaymentVO */ public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception { // 当前登录用户id Long userId = BaseContext.getCurrentId(); User user = userMapper.getById(userId); // TODO 跳过微信支付 调用微信支付接口,生成预支付交易单 /* JSONObject jsonObject = weChatPayUtil.pay(ordersPaymentDTO.getOrderNumber(), // 商户订单号 new BigDecimal("0.01"), // 支付金额,单位 元 "苍穹外卖订单", // 商品描述 user.getOpenid() // 微信用户的openid ); */ // TODO 跳过微信支付 JSONObject jsonObject = new JSONObject(); if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) { throw new OrderBusinessException("该订单已支付"); } OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class); vo.setPackageStr(jsonObject.getString("package")); return vo; } /** * 支付成功,修改订单状态 * * @param outTradeNo String */ public void paySuccess(String outTradeNo) { // 根据订单号查询订单 Orders ordersDB = orderMapper.getByNumber(outTradeNo); // 根据订单id更新订单的状态、支付方式、支付状态、结账时间 Orders orders = Orders.builder().id(ordersDB.getId()).status(Orders.TO_BE_CONFIRMED).payStatus(Orders.PAID).checkoutTime(LocalDateTime.now()).build(); orderMapper.update(orders); HashMap map = new HashMap<>(); map.put("type", 1); map.put("orderId", ordersDB.getId()); map.put("content", "订单号" + outTradeNo); String jsonString = JSONObject.toJSONString(map); webSocketServer.sendToAllClient(jsonString); } /** * 客户催单 * * @param id Long */ @Override public void reminder(Long id) { Orders orderDB = orderMapper.getById(id); if (orderDB == null) { throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR); } // 通过websocket 催单 Map map = new HashMap<>(); map.put("type", 2); map.put("orderId", id); map.put("content", "订单号" + orderDB.getNumber()); webSocketServer.sendToAllClient(JSONObject.toJSONString(map)); } /** * 用户端订单分页查询 * * @param pageNum 当前页 * @param pageSize 每页显示条数 * @param status 状态 * @return PageResult */ @Override public PageResult pageQuery4User(int pageNum, int pageSize, Integer status) { // 设置分页大小和每页条数 PageHelper.startPage(pageNum, pageSize); // 封装查询条件 OrdersPageQueryDTO ordersPageQueryDTO = new OrdersPageQueryDTO(); ordersPageQueryDTO.setUserId(BaseContext.getCurrentId()); ordersPageQueryDTO.setStatus(status); // 分页条件查询 Page page = orderMapper.pageQuery(ordersPageQueryDTO); ArrayList list = new ArrayList<>(); // 查询订单明细,并封装入orderMapper进行响应 if (page != null && page.getTotal() > 0) { for (Orders orders : page) { Long id = orders.getId(); // 查询订单明细 List orderDetails = orderDetailMapper.getByOrderId(id); OrderVO orderVO = new OrderVO(); BeanUtils.copyProperties(orders, orderVO); orderVO.setOrderDetailList(orderDetails); list.add(orderVO); } } assert page != null; return new PageResult(page.getTotal(), list); } /** * 查询订单详情 * * @param id 查询订单id * @return OrderVO */ @Override public OrderVO detail(Long id) { // 根据id查询订单 Orders orders = orderMapper.getById(id); // 查询该订单对应的菜品/套餐明细 List orderDetailList = orderDetailMapper.getByOrderId(orders.getId()); // 将该订单及其详情封装到OrderVO并返回 OrderVO orderVO = new OrderVO(); BeanUtils.copyProperties(orders, orderVO); orderVO.setOrderDetailList(orderDetailList); return orderVO; } /** * 取消订单 * * @param id 订单id */ @Override public void userCancelById(Long id) { // 根据id查询订单 Orders ordersDB = orderMapper.getById(id); // 如果查询到的订单为空 if (ordersDB == null) { throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND); } // 订单状态 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消 if (ordersDB.getStatus() > 2) { throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR); } Orders orders = new Orders(); orders.setId(ordersDB.getId()); // 订单处于待接单状态下取消,需要进行退款 if (ordersDB.getStatus().equals(Orders.TO_BE_CONFIRMED)) { log.info("订单需要退款。。。。。。。"); orders.setPayStatus(Orders.REFUND); } // 更新订单状态、取消原因、取消时间 orders.setStatus(Orders.CANCELLED); orders.setCancelReason("用户取消"); orders.setCancelTime(LocalDateTime.now()); orderMapper.update(orders); } /** * 再来一单 * * @param id 订单id */ @Override public void repetition(Long id) { // 查询当前用户id Long userId = BaseContext.getCurrentId(); // 根据订单id查询当前订单详情 List orderDetailList = orderDetailMapper.getByOrderId(id); // 将订单详情对象转换为购物车对象 List shoppingCartList = orderDetailList.stream().map(x -> { ShoppingCart shoppingCart = new ShoppingCart(); // 将原订单详情里面的菜品信息重新复制到购物车对象中 BeanUtils.copyProperties(x, shoppingCart, "id"); shoppingCart.setUserId(userId); shoppingCart.setCreateTime(LocalDateTime.now()); return shoppingCart; }).collect(Collectors.toList()); // 将购物车对象批量添加到数据库 shoppingCartMapper.insertBatch(shoppingCartList); } /** * 条件搜索订单 * * @param ordersPageQueryDTO OrdersPageQueryDTO * @return PageResult */ public PageResult conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO) { PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize()); Page page = orderMapper.pageQuery(ordersPageQueryDTO); // 部分订单状态,需要额外返回订单菜品信息,将Orders转化为OrderVO List orderVOList = getOrderVOList(page); return new PageResult(page.getTotal(), orderVOList); } private List getOrderVOList(Page page) { // 需要返回订单菜品信息,自定义OrderVO响应结果 List orderVOList = new ArrayList<>(); List ordersList = page.getResult(); if (!CollectionUtils.isEmpty(ordersList)) { for (Orders orders : ordersList) { // 将共同字段复制到OrderVO OrderVO orderVO = new OrderVO(); BeanUtils.copyProperties(orders, orderVO); String orderDishes = getOrderDishesStr(orders); // 将订单菜品信息封装到orderVO中,并添加到orderVOList orderVO.setOrderDishes(orderDishes); orderVOList.add(orderVO); } } return orderVOList; } /** * 根据订单id获取菜品信息字符串 * * @param orders Orders * @return String */ private String getOrderDishesStr(Orders orders) { // 查询订单菜品详情信息(订单中的菜品和数量) List orderDetailList = orderDetailMapper.getByOrderId(orders.getId()); // 将每一条订单菜品信息拼接为字符串(格式:宫保鸡丁*3;) List orderDishList = orderDetailList.stream().map(x -> { return x.getName() + "*" + x.getNumber() + ";"; }).collect(Collectors.toList()); // 将该订单对应的所有菜品信息拼接在一起 return String.join("", orderDishList); } /** * 各个状态的订单数量统计 * * @return */ public OrderStatisticsVO statistics() { // 根据状态,分别查询出待接单、待派送、派送中的订单数量 Integer toBeConfirmed = orderMapper.countStatus(Orders.TO_BE_CONFIRMED); Integer confirmed = orderMapper.countStatus(Orders.CONFIRMED); Integer deliveryInProgress = orderMapper.countStatus(Orders.DELIVERY_IN_PROGRESS); // 将查询出的数据封装到orderStatisticsVO中响应 OrderStatisticsVO orderStatisticsVO = new OrderStatisticsVO(); orderStatisticsVO.setToBeConfirmed(toBeConfirmed); orderStatisticsVO.setConfirmed(confirmed); orderStatisticsVO.setDeliveryInProgress(deliveryInProgress); return orderStatisticsVO; } /** * 接单 * * @param ordersConfirmDTO */ public void confirm(OrdersConfirmDTO ordersConfirmDTO) { Orders orders = Orders.builder() .id(ordersConfirmDTO.getId()) .status(Orders.CONFIRMED) .build(); orderMapper.update(orders); } /** * 拒单 * * @param ordersRejectionDTO */ public void rejection(OrdersRejectionDTO ordersRejectionDTO) throws Exception { // 根据id查询订单 Orders ordersDB = orderMapper.getById(ordersRejectionDTO.getId()); // 订单只有存在且状态为2(待接单)才可以拒单 if (ordersDB == null || !ordersDB.getStatus().equals(Orders.TO_BE_CONFIRMED)) { throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR); } // 支付状态 Integer payStatus = ordersDB.getPayStatus(); if (Objects.equals(payStatus, Orders.PAID)) { // 用户已支付,需要退款 String refund = "dasda"; log.info("申请退款:{}", refund); } // 拒单需要退款,根据订单id更新订单状态、拒单原因、取消时间 Orders orders = new Orders(); orders.setId(ordersDB.getId()); orders.setStatus(Orders.CANCELLED); orders.setRejectionReason(ordersRejectionDTO.getRejectionReason()); orders.setCancelTime(LocalDateTime.now()); orderMapper.update(orders); } /** * 取消订单 * * @param ordersCancelDTO */ public void cancel(OrdersCancelDTO ordersCancelDTO) throws Exception { // 根据id查询订单 Orders ordersDB = orderMapper.getById(ordersCancelDTO.getId()); // 支付状态 Integer payStatus = ordersDB.getPayStatus(); if (payStatus == 1) { // 用户已支付,需要退款 String refund = weChatPayUtil.refund( ordersDB.getNumber(), ordersDB.getNumber(), new BigDecimal("0.01"), new BigDecimal("0.01")); log.info("申请退款:{}", refund); } // 管理端取消订单需要退款,根据订单id更新订单状态、取消原因、取消时间 Orders orders = new Orders(); orders.setId(ordersCancelDTO.getId()); orders.setStatus(Orders.CANCELLED); orders.setCancelReason(ordersCancelDTO.getCancelReason()); orders.setCancelTime(LocalDateTime.now()); orderMapper.update(orders); } /** * 派送订单 * * @param id */ public void delivery(Long id) { // 根据id查询订单 Orders ordersDB = orderMapper.getById(id); // 校验订单是否存在,并且状态为3 if (ordersDB == null || !ordersDB.getStatus().equals(Orders.CONFIRMED)) { throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR); } Orders orders = new Orders(); orders.setId(ordersDB.getId()); // 更新订单状态,状态转为派送中 orders.setStatus(Orders.DELIVERY_IN_PROGRESS); orderMapper.update(orders); } /** * 完成订单 * * @param id */ public void complete(Long id) { // 根据id查询订单 Orders ordersDB = orderMapper.getById(id); // 校验订单是否存在,并且状态为4 if (ordersDB == null || !ordersDB.getStatus().equals(Orders.DELIVERY_IN_PROGRESS)) { throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR); } Orders orders = new Orders(); orders.setId(ordersDB.getId()); // 更新订单状态,状态转为完成 orders.setStatus(Orders.COMPLETED); orders.setDeliveryTime(LocalDateTime.now()); orderMapper.update(orders); } /** * 检查客户的收货地址是否超出配送范围 * * @param address */ private void checkOutOfRange(String address) { Map map = new HashMap(); map.put("address", shopAddress); map.put("output", "json"); map.put("ak", ak); // 获取店铺的经纬度坐标 String shopCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map); JSONObject jsonObject = JSON.parseObject(shopCoordinate); if (!jsonObject.getString("status").equals("0")) { throw new OrderBusinessException("店铺地址解析失败"); } // 数据解析 JSONObject location = jsonObject.getJSONObject("result").getJSONObject("location"); String lat = location.getString("lat"); String lng = location.getString("lng"); // 店铺经纬度坐标 String shopLngLat = lat + "," + lng; map.put("address", address); // 获取用户收货地址的经纬度坐标 String userCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map); jsonObject = JSON.parseObject(userCoordinate); if (!jsonObject.getString("status").equals("0")) { throw new OrderBusinessException("收货地址解析失败"); } // 数据解析 location = jsonObject.getJSONObject("result").getJSONObject("location"); lat = location.getString("lat"); lng = location.getString("lng"); // 用户收货地址经纬度坐标 String userLngLat = lat + "," + lng; map.put("origin", shopLngLat); map.put("destination", userLngLat); map.put("steps_info", "0"); // 路线规划 String json = HttpClientUtil.doGet("https://api.map.baidu.com/directionlite/v1/driving", map); jsonObject = JSON.parseObject(json); if (!jsonObject.getString("status").equals("0")) { throw new OrderBusinessException("配送路线规划失败"); } // 数据解析 JSONObject result = jsonObject.getJSONObject("result"); JSONArray jsonArray = (JSONArray) result.get("routes"); Integer distance = (Integer) ((JSONObject) jsonArray.get(0)).get("distance"); if (distance > 5000) { // 配送距离超过5000米 throw new OrderBusinessException("超出配送范围"); } } }