package com.example.building.service.impl; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.example.building.dto.CreateOrderRequest; import com.example.building.entity.*; import com.example.building.mapper.*; import com.example.building.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; /** * 订单服务实现类 * 核心业务逻辑: * 1. 订单原价(total_amount) = Σ(item.price × item.quantity) * 2. 优惠金额(discount_amount) = total_amount × (100 - discount_rate) / 100 * 3. 实付金额(actual_amount) = total_amount - discount_amount */ @Service public class OrderServiceImpl implements OrderService { @Autowired private OrderMapper orderMapper; @Autowired private OrderItemMapper orderItemMapper; @Autowired private ProductMapper productMapper; @Autowired private StockMapper stockMapper; @Autowired private StockFlowMapper stockFlowMapper; @Autowired private CustomerMapper customerMapper; /** * 创建订单 * 核心:价格计算、库存扣减、客户累计消费更新 */ @Override @Transactional public Order createOrder(CreateOrderRequest request, String operatorId, String operatorName) { // 1. 准备订单数据 Order order = new Order(); order.setOrderId(UUID.randomUUID().toString()); order.setOrderNo(generateOrderNo()); order.setOperatorId(operatorId); order.setOperatorName(operatorName); order.setDiscountRate(request.getDiscountRate() != null ? request.getDiscountRate() : new BigDecimal("100")); order.setRemark(request.getRemark()); order.setPaymentMethod(request.getPaymentMethod()); order.setStatus(0); // 未完成 order.setDeleted(0); // 未删除 // 2. 查询客户信息(如果指定了客户) if (request.getCustomerId() != null) { Customer customer = customerMapper.selectById(request.getCustomerId()); if (customer != null) { order.setCustomerId(customer.getCustomerId()); order.setCustomerName(customer.getName()); order.setCustomerPhone(customer.getPhone()); order.setCustomerWechat(customer.getWechatOpenid()); } } // 3. 计算订单金额 BigDecimal totalAmount = BigDecimal.ZERO; // 原价 List orderItems = new ArrayList<>(); for (CreateOrderRequest.OrderItemDTO itemDTO : request.getItems()) { // 查询商品信息 Product product = productMapper.selectById(itemDTO.getProductId()); if (product == null) { throw new RuntimeException("商品不存在: " + itemDTO.getProductId()); } // 使用用户指定价格或商品标价 BigDecimal price = itemDTO.getPrice() != null ? itemDTO.getPrice() : product.getPrice(); // 计算小计 BigDecimal subtotal = price.multiply(new BigDecimal(itemDTO.getQuantity())) .setScale(2, RoundingMode.HALF_UP); // 累加原价 totalAmount = totalAmount.add(subtotal); // 构建订单明细 OrderItem item = new OrderItem(); item.setItemId(UUID.randomUUID().toString()); item.setOrderId(order.getOrderId()); item.setProductId(product.getProductId()); item.setCategoryId(product.getCategoryId()); item.setProductName(product.getName()); item.setProductSpec(product.getSpec()); item.setUnit(product.getUnit()); item.setCostPrice(product.getCostPrice()); item.setImageUrl(product.getImageUrl()); item.setBarcode(product.getBarcode()); item.setStockAlert(product.getStockAlert()); item.setDescription(product.getDescription()); item.setPrice(price); item.setQuantity(itemDTO.getQuantity()); item.setSubtotal(subtotal); orderItems.add(item); // 4. 暂时不扣减库存,等确认完成时再扣减 // decreaseStock(product.getProductId(), itemDTO.getQuantity(), order.getOrderId(), operatorId); } // 设置订单原价 order.setTotalAmount(totalAmount); // 5. 计算优惠金额和实付金额 BigDecimal discountAmount; BigDecimal discountRate = order.getDiscountRate(); BigDecimal discountMoney = request.getDiscountMoney(); // 如果优惠金额大于0,直接使用;否则用折扣率计算 if (discountMoney != null && discountMoney.compareTo(BigDecimal.ZERO) >= 0) { discountAmount = discountMoney; } else { // 折扣率默认100,即不打折 if (discountRate == null) { discountRate = new BigDecimal("100"); } discountAmount = totalAmount.multiply(new BigDecimal("100").subtract(discountRate)) .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP); } BigDecimal actualAmount = totalAmount.subtract(discountAmount); order.setDiscountAmount(discountAmount); order.setActualAmount(actualAmount); // 6. 保存订单 orderMapper.insert(order); // 7. 保存订单明细 for (OrderItem item : orderItems) { orderItemMapper.insert(item); } // 8. 更新客户累计消费金额 if (request.getCustomerId() != null) { Customer customer = customerMapper.selectById(request.getCustomerId()); if (customer != null) { BigDecimal newTotal = customer.getTotalAmount().add(actualAmount); customer.setTotalAmount(newTotal); customerMapper.updateById(customer); } } return order; } /** * 获取订单列表 */ @Override public Page getOrders(String customerId, String customerName, Integer status, String startDate, String endDate, Integer page, Integer pageSize) { Page pageParam = new Page<>(page, pageSize); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); if (customerId != null) { wrapper.eq(Order::getCustomerId, customerId); } if (customerName != null && !customerName.isEmpty()) { wrapper.like(Order::getCustomerName, customerName); } if (status != null) { wrapper.eq(Order::getStatus, status); } if (startDate != null) { wrapper.ge(Order::getCreatedAt, startDate); } if (endDate != null) { wrapper.le(Order::getCreatedAt, endDate); } wrapper.orderByDesc(Order::getCreatedAt); return orderMapper.selectPage(pageParam, wrapper); } /** * 获取订单详情(含明细) * 顾客只能查看自己的订单 */ @Override public Map getOrderDetail(String orderId, String userId, String role) { Order order = orderMapper.selectById(orderId); if (order == null) { throw new RuntimeException("订单不存在"); } // 顾客只能查看自己的订单 if ("customer".equals(role) && !userId.equals(order.getCustomerId())) { throw new RuntimeException("无权查看该订单"); } List items = orderItemMapper.selectList(new LambdaQueryWrapper() .eq(OrderItem::getOrderId, orderId)); Map result = new HashMap<>(); result.put("order", order); result.put("items", items); return result; } /** * 取消订单 */ @Override @Transactional public void cancelOrder(String orderId, String operatorId) { Order order = orderMapper.selectById(orderId); if (order == null) { throw new RuntimeException("订单不存在"); } if (order.getStatus() != 0) { throw new RuntimeException("订单状态不允许取消"); } // 未完成订单没有扣减库存,不需要恢复 // 更新订单状态 order.setStatus(2); // 已取消 orderMapper.updateById(order); } /** * 退款 */ @Override @Transactional public void refundOrder(String orderId, String operatorId) { Order order = orderMapper.selectById(orderId); if (order == null) { throw new RuntimeException("订单不存在"); } if (order.getStatus() != 1) { throw new RuntimeException("订单状态不允许退款"); } // 恢复库存 List items = orderItemMapper.selectList(new LambdaQueryWrapper() .eq(OrderItem::getOrderId, orderId)); for (OrderItem item : items) { increaseStock(item.getProductId(), item.getQuantity(), orderId, operatorId); } // 更新订单状态 order.setStatus(4); // 已退款 orderMapper.updateById(order); } /** * 更新订单状态(确认完成/取消) */ @Override @Transactional public void updateOrderStatus(String orderId, Integer status, String operatorId) { Order order = orderMapper.selectById(orderId); if (order == null) { throw new RuntimeException("订单不存在"); } // 只有未完成状态可以操作 if (order.getStatus() == null || order.getStatus() != 0) { throw new RuntimeException("订单状态不允许操作"); } if (status == 1) { // 确认完成:扣减库存 List items = orderItemMapper.selectList(new LambdaQueryWrapper() .eq(OrderItem::getOrderId, orderId)); for (OrderItem item : items) { decreaseStock(item.getProductId(), item.getQuantity(), orderId, operatorId); } } // 取消不需要恢复库存(因为创建时没扣减) order.setStatus(status); orderMapper.updateById(order); } /** * 更新订单(编辑) */ @Override @Transactional public Order updateOrder(String orderId, CreateOrderRequest request, String operatorId) { Order order = orderMapper.selectById(orderId); if (order == null) { throw new RuntimeException("订单不存在"); } // 只有未完成状态可以编辑 if (order.getStatus() == null || order.getStatus() != 0) { throw new RuntimeException("订单状态不允许编辑"); } // 更新客户信息 if (request.getCustomerId() != null) { Customer customer = customerMapper.selectById(request.getCustomerId()); if (customer != null) { order.setCustomerId(customer.getCustomerId()); order.setCustomerName(customer.getName()); order.setCustomerPhone(customer.getPhone()); order.setCustomerWechat(customer.getWechatOpenid()); } } else { order.setCustomerId(null); order.setCustomerName(null); order.setCustomerPhone(null); order.setCustomerWechat(null); } // 更新折扣和备注 order.setDiscountRate(request.getDiscountRate() != null ? request.getDiscountRate() : new BigDecimal("100")); order.setDiscountMoney(request.getDiscountMoney() != null ? request.getDiscountMoney() : BigDecimal.ZERO); order.setRemark(request.getRemark()); order.setPaymentMethod(request.getPaymentMethod()); // 重新计算金额 BigDecimal totalAmount = BigDecimal.ZERO; // 删除旧的订单明细 orderItemMapper.delete(new LambdaQueryWrapper().eq(OrderItem::getOrderId, orderId)); // 重新创建订单明细 List orderItems = new ArrayList<>(); for (CreateOrderRequest.OrderItemDTO itemDTO : request.getItems()) { Product product = productMapper.selectById(itemDTO.getProductId()); if (product == null) { throw new RuntimeException("商品不存在: " + itemDTO.getProductId()); } BigDecimal price = itemDTO.getPrice() != null ? itemDTO.getPrice() : product.getPrice(); BigDecimal subtotal = price.multiply(new BigDecimal(itemDTO.getQuantity())) .setScale(2, RoundingMode.HALF_UP); totalAmount = totalAmount.add(subtotal); OrderItem item = new OrderItem(); item.setItemId(UUID.randomUUID().toString()); item.setOrderId(orderId); item.setProductId(product.getProductId()); item.setCategoryId(product.getCategoryId()); item.setProductName(product.getName()); item.setProductSpec(product.getSpec()); item.setUnit(product.getUnit()); item.setCostPrice(product.getCostPrice()); item.setImageUrl(product.getImageUrl()); item.setBarcode(product.getBarcode()); item.setStockAlert(product.getStockAlert()); item.setDescription(product.getDescription()); item.setPrice(price); item.setQuantity(itemDTO.getQuantity()); item.setSubtotal(subtotal); orderItems.add(item); orderItemMapper.insert(item); } order.setTotalAmount(totalAmount); BigDecimal discountAmount; BigDecimal discountRate = order.getDiscountRate(); BigDecimal discountMoney = order.getDiscountMoney(); // 如果优惠金额大于等于0,直接使用;否则用折扣率计算 if (discountMoney != null && discountMoney.compareTo(BigDecimal.ZERO) >= 0) { discountAmount = discountMoney; } else { if (discountRate == null) { discountRate = new BigDecimal("100"); } discountAmount = totalAmount.multiply(new BigDecimal("100").subtract(discountRate)) .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP); } BigDecimal actualAmount = totalAmount.subtract(discountAmount); order.setDiscountAmount(discountAmount); order.setActualAmount(actualAmount); orderMapper.updateById(order); return order; } /** * 订单统计 */ @Override public Map getStatistics(String startDate, String endDate) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Order::getStatus, 1); if (startDate != null && !startDate.isEmpty()) { LocalDateTime start = LocalDate.parse(startDate, DateTimeFormatter.ISO_LOCAL_DATE).atStartOfDay(); wrapper.ge(Order::getCreatedAt, start); } if (endDate != null && !endDate.isEmpty()) { LocalDateTime end = LocalDate.parse(endDate, DateTimeFormatter.ISO_LOCAL_DATE).atTime(23, 59, 59); wrapper.le(Order::getCreatedAt, end); } List orders = orderMapper.selectList(wrapper); BigDecimal totalAmount = BigDecimal.ZERO; // 原价合计 BigDecimal actualAmount = BigDecimal.ZERO; // 实付合计 for (Order order : orders) { totalAmount = totalAmount.add(order.getTotalAmount()); actualAmount = actualAmount.add(order.getActualAmount()); } Map result = new HashMap<>(); result.put("orderCount", orders.size()); result.put("totalAmount", totalAmount); result.put("actualAmount", actualAmount); result.put("discountAmount", totalAmount.subtract(actualAmount)); return result; } /** * 生成订单编号 * 规则: ORD + 年月日 + 6位序号 */ private String generateOrderNo() { String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); String key = "order:no:" + date; // 这里简化处理,实际应使用Redis自增 int seq = (int) (Math.random() * 1000000); return "ORD" + date + String.format("%06d", seq); } /** * 扣减库存 */ private void decreaseStock(String productId, Integer quantity, String relatedId, String operatorId) { Stock stock = stockMapper.selectOne(new LambdaQueryWrapper() .eq(Stock::getProductId, productId)); if (stock == null) { throw new RuntimeException("库存记录不存在"); } if (stock.getQuantity() < quantity) { throw new RuntimeException("库存不足"); } int beforeQty = stock.getQuantity(); stock.setQuantity(beforeQty - quantity); stockMapper.updateById(stock); // 记录库存流水 saveStockFlow(productId, 2, -quantity, beforeQty, beforeQty - quantity, relatedId, "sale", operatorId); } /** * 增加库存 */ private void increaseStock(String productId, Integer quantity, String relatedId, String operatorId) { Stock stock = stockMapper.selectOne(new LambdaQueryWrapper() .eq(Stock::getProductId, productId)); if (stock == null) { stock = new Stock(); stock.setStockId(UUID.randomUUID().toString()); stock.setProductId(productId); stock.setQuantity(0); stock.setLockedQuantity(0); stockMapper.insert(stock); } int beforeQty = stock.getQuantity(); stock.setQuantity(beforeQty + quantity); stockMapper.updateById(stock); // 记录库存流水 saveStockFlow(productId, 1, quantity, beforeQty, beforeQty + quantity, relatedId, "cancel", operatorId); } /** * 保存库存流水 */ private void saveStockFlow(String productId, Integer type, Integer quantity, Integer beforeQty, Integer afterQty, String relatedId, String relatedType, String operatorId) { StockFlow flow = new StockFlow(); flow.setFlowId(UUID.randomUUID().toString()); flow.setProductId(productId); flow.setType(type); flow.setQuantity(quantity); flow.setBeforeQuantity(beforeQty); flow.setAfterQuantity(afterQty); flow.setRelatedId(relatedId); flow.setRelatedType(relatedType); flow.setOperatorId(operatorId); stockFlowMapper.insert(flow); } }