ソースを参照

智能柜项目提交

skyline 2 ヶ月 前
コミット
9be9dd6f6c

+ 4 - 3
haha-common/src/main/java/com/haha/common/vo/OrderVO.java

@@ -1,11 +1,12 @@
 package com.haha.common.vo;
 
 import lombok.Data;
+import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.List;
 
 /**
- * 璁㈠崟璇︽儏灞曠ず瀵硅薄
+ * 订单详情展示对象
  */
 @Data
 public class OrderVO {
@@ -14,13 +15,13 @@ public class OrderVO {
     private String outTradeNo;
     private String hahaOrderNo;
     private String deviceId;
-    private Double totalAmount;
+    private BigDecimal totalAmount;
     private Integer payStatus;
     private Integer status;
     private String statusText;
     private LocalDateTime createTime;
     private LocalDateTime payTime;
     private String videoUrl;
-    private Double confidence;
+    private BigDecimal confidence;
     private List<OrderItemVO> products;
 }

+ 3 - 3
haha-entity/src/main/java/com/haha/entity/Order.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.time.LocalDateTime;
 
 @Data
@@ -27,13 +28,13 @@ public class Order implements Serializable {
 
     private String deviceId;
 
-    private Double totalAmount;
+    private BigDecimal totalAmount;
 
     private String payStatus;
 
     private String videoUrl;
 
-    private Double confidence;
+    private BigDecimal confidence;
 
     private String items;
 
@@ -43,7 +44,6 @@ public class Order implements Serializable {
 
     private Integer status;
 
-    // 非数据库字段 - 用于前端展示
     @TableField(exist = false)
     private String statusLabel;
 

+ 3 - 2
haha-mapper/src/main/java/com/haha/mapper/OrderMapper.java

@@ -5,10 +5,11 @@ import com.haha.entity.Order;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
+import java.math.BigDecimal;
 import java.time.LocalDateTime;
 
 public interface OrderMapper extends BaseMapper<Order> {
-    
+
     /**
      * 统计已完成订单的销售总额
      * 
@@ -22,5 +23,5 @@ public interface OrderMapper extends BaseMapper<Order> {
             "AND create_time &gt;= #{startDate} " +
             "</if>" +
             "</script>")
-    Double sumCompletedOrderAmount(@Param("startDate") LocalDateTime startDate);
+    BigDecimal sumCompletedOrderAmount(@Param("startDate") LocalDateTime startDate);
 }

+ 0 - 50
haha-miniapp/src/main/java/com/haha/common/constant/OrderConstants.java

@@ -1,50 +0,0 @@
-package com.haha.common.constant;
-
-/**
- * 订单相关常量
- */
-public class OrderConstants {
-
-    /**
-     * 订单状态
-     */
-    public static final int STATUS_PENDING_PAYMENT = 0; // 待支付
-    public static final int STATUS_COMPLETED = 1; // 已完成
-    public static final int STATUS_CANCELLED = 2; // 已取消
-    
-    /**
-     * 支付状态
-     */
-    public static final int PAY_STATUS_UNPAID = 0; // 未支付
-    public static final int PAY_STATUS_PAID = 1; // 已支付
-    public static final int PAY_STATUS_REFUNDED = 2; // 已退款
-    
-    /**
-     * 订单类型
-     */
-    public static final int ORDER_TYPE_CONSUME = 1; // 消费订单
-    public static final int ORDER_TYPE_REPLENISH = 2; // 补货订单
-    
-    /**
-     * 订单操作
-     */
-    public static final int OPERATION_CREATE = 1; // 创建
-    public static final int OPERATION_PAY = 2; // 支付
-    public static final int OPERATION_CANCEL = 3; // 取消
-    public static final int OPERATION_REFUND = 4; // 退款
-    
-    /**
-     * 订单号前缀
-     */
-    public static final String ORDER_NO_PREFIX = "ORDER";
-    public static final String OUT_TRADE_NO_PREFIX = "OUT";
-    
-    /**
-     * 订单相关消息
-     */
-    public static final String MESSAGE_ORDER_CREATED = "订单创建成功";
-    public static final String MESSAGE_ORDER_PAID = "订单支付成功";
-    public static final String MESSAGE_ORDER_CANCELLED = "订单已取消";
-    public static final String MESSAGE_ORDER_REFUNDED = "订单已退款";
-    public static final String MESSAGE_ORDER_FAILED = "订单处理失败";
-}

+ 55 - 4
haha-miniapp/src/main/java/com/haha/miniapp/controller/CallbackController.java

@@ -18,13 +18,14 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import jakarta.servlet.http.HttpServletRequest;
 import java.io.BufferedReader;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDateTime;
 import java.util.HashMap;
 import java.util.Map;
@@ -351,17 +352,67 @@ public class CallbackController {
             }
 
             // 解析resource_info获取视频URL
+            String videoUrl = null;
             if (resourceInfoStr != null && !resourceInfoStr.isEmpty()) {
                 JSONObject resourceInfo = JSON.parseObject(resourceInfoStr);
-                String videoUrl = resourceInfo.getString("video_url");
+                videoUrl = resourceInfo.getString("video_url");
                 log.info("视频URL: {}", videoUrl);
             }
 
-            // TODO: 根据识别结果进行后续处理
             // 1. 计算订单金额
+            BigDecimal totalAmount = BigDecimal.ZERO;
+            JSONArray skuList = null;
+            if (skuListStr != null && !skuListStr.isEmpty()) {
+                skuList = JSON.parseArray(skuListStr);
+                if (skuList != null) {
+                    for (int i = 0; i < skuList.size(); i++) {
+                        JSONObject sku = skuList.getJSONObject(i);
+                        BigDecimal price = sku.getBigDecimal("price");
+                        Integer quantity = sku.getInteger("quantity");
+                        if (price != null && quantity != null) {
+                            totalAmount = totalAmount.add(price.multiply(BigDecimal.valueOf(quantity)));
+                        }
+                    }
+                    totalAmount = totalAmount.setScale(2, RoundingMode.HALF_UP);
+                    log.info("订单金额计算完成: {}, 商品数量: {}", totalAmount, skuList.size());
+                }
+            }
+
             // 2. 生成订单记录
+            if (userId != null && deviceId != null && totalAmount.compareTo(BigDecimal.ZERO) > 0) {
+                Order order = new Order();
+                order.setActivityId(activityId);
+                order.setUserId(Long.parseLong(userId));
+                order.setDeviceId(deviceId);
+                order.setTotalAmount(totalAmount);
+                order.setItems(skuListStr);
+                order.setStatus(OrderConstants.STATUS_PENDING_PAYMENT);
+                order.setPayStatus(OrderConstants.PAY_STATUS_UNPAID);
+                order.setCreateTime(LocalDateTime.now());
+                if (videoUrl != null) {
+                    order.setVideoUrl(videoUrl);
+                }
+                if (params.get("confidence") != null) {
+                    try {
+                        order.setConfidence(new BigDecimal(params.get("confidence").toString()));
+                    } catch (NumberFormatException ignored) {}
+                }
+
+                boolean saved = orderService.save(order);
+                if (saved) {
+                    log.info("订单创建成功 - 订单ID: {}, 用户: {}, 金额: {}", order.getId(), userId, totalAmount);
+                } else {
+                    log.error("订单创建失败 - 用户: {}, 设备: {}", userId, deviceId);
+                }
+            } else {
+                log.warn("订单创建跳过 - 缺少必要参数: userId={}, deviceId={}, amount={}", userId, deviceId, totalAmount);
+            }
+
             // 3. 优惠信息处理
+            // TODO: 根据业务需求处理优惠券、折扣等
+
             // 4. 触发支付流程
+            // TODO: 根据业务需求触发支付
 
         } catch (Exception e) {
             log.error("处理AI识别结果通知失败", e);
@@ -432,7 +483,7 @@ public class CallbackController {
 
             // 设置订单金额
             if (orderMoney != null) {
-                localOrder.setTotalAmount(Double.parseDouble(orderMoney.toString()));
+                localOrder.setTotalAmount(new BigDecimal(orderMoney.toString()));
             }
 
             boolean updated = orderService.updateById(localOrder);

+ 68 - 69
haha-service/src/main/java/com/haha/service/impl/DashboardServiceImpl.java

@@ -57,24 +57,20 @@ public class DashboardServiceImpl implements DashboardService {
                      .le(Order::getPayTime, todayEnd);
         
         List<Order> todayOrders = orderService.list(todayWrapper);
-        
-        // 今日销售额
-        double todaySales = todayOrders.stream()
-                .mapToDouble(o -> o.getTotalAmount() != null ? o.getTotalAmount() : 0)
-                .sum();
-        result.put("todaySales", String.format("%.2f", todaySales));
 
-        // 今日订单量
+        BigDecimal todaySales = todayOrders.stream()
+                .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+        result.put("todaySales", todaySales.setScale(2, RoundingMode.HALF_UP).toString());
+
         int todayOrderCount = todayOrders.size();
         result.put("todayOrders", todayOrderCount);
 
-        // 今日客单价
         String todayAvgPrice = todayOrderCount > 0 
-                ? String.format("%.2f", todaySales / todayOrderCount) 
+                ? todaySales.divide(BigDecimal.valueOf(todayOrderCount), 2, RoundingMode.HALF_UP).toString() 
                 : "0.00";
         result.put("todayAvgPrice", todayAvgPrice);
 
-        // 昨日同时段销售额和订单量
         LambdaQueryWrapper<Order> yesterdayWrapper = new LambdaQueryWrapper<>();
         yesterdayWrapper.eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
                         .ge(Order::getPayTime, yesterdayStart)
@@ -82,17 +78,20 @@ public class DashboardServiceImpl implements DashboardService {
         
         List<Order> yesterdayOrders = orderService.list(yesterdayWrapper);
         
-        double yesterdaySales = yesterdayOrders.stream()
-                .mapToDouble(o -> o.getTotalAmount() != null ? o.getTotalAmount() : 0)
-                .sum();
+        BigDecimal yesterdaySales = yesterdayOrders.stream()
+                .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
         int yesterdayOrderCount = yesterdayOrders.size();
-        double yesterdayAvgPrice = yesterdayOrderCount > 0 ? yesterdaySales / yesterdayOrderCount : 0;
+        BigDecimal yesterdayAvgPrice = yesterdayOrderCount > 0 
+                ? yesterdaySales.divide(BigDecimal.valueOf(yesterdayOrderCount), 2, RoundingMode.HALF_UP) 
+                : BigDecimal.ZERO;
 
-        // 与昨日同时段对比
-        result.put("todaySalesCompare", formatCompare(todaySales - yesterdaySales));
+        result.put("todaySalesCompare", formatCompare(todaySales.subtract(yesterdaySales)));
         result.put("todayOrdersCompare", formatCompare(todayOrderCount - yesterdayOrderCount));
-        result.put("todayAvgPriceCompare", formatCompare(todayOrderCount > 0 ? 
-                (todaySales / todayOrderCount) - yesterdayAvgPrice : 0));
+        BigDecimal todayAvg = todayOrderCount > 0 
+                ? todaySales.divide(BigDecimal.valueOf(todayOrderCount), 2, RoundingMode.HALF_UP) 
+                : BigDecimal.ZERO;
+        result.put("todayAvgPriceCompare", formatCompare(todayAvg.subtract(yesterdayAvgPrice)));
 
         // 设备状态统计
         long totalDevices = deviceService.count();
@@ -168,21 +167,19 @@ public class DashboardServiceImpl implements DashboardService {
         
         List<Order> orders = orderService.list(wrapper);
 
-        // 销售额
-        double totalSales = orders.stream()
-                .mapToDouble(o -> o.getTotalAmount() != null ? o.getTotalAmount() : 0)
-                .sum();
-        result.put("totalSales", String.format("%.2f", totalSales));
+        BigDecimal totalSales = orders.stream()
+                .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+        result.put("totalSales", totalSales.setScale(2, RoundingMode.HALF_UP).toString());
 
-        // 订单量
         int totalOrders = orders.size();
         result.put("totalOrders", totalOrders);
 
-        // 单均价
-        double avgOrderPrice = totalOrders > 0 ? totalSales / totalOrders : 0;
-        result.put("avgOrderPrice", String.format("%.2f", avgOrderPrice));
+        BigDecimal avgOrderPrice = totalOrders > 0 
+                ? totalSales.divide(BigDecimal.valueOf(totalOrders), 2, RoundingMode.HALF_UP) 
+                : BigDecimal.ZERO;
+        result.put("avgOrderPrice", avgOrderPrice.toString());
 
-        // 查询对比期数据
         LambdaQueryWrapper<Order> compareWrapper = new LambdaQueryWrapper<>();
         compareWrapper.eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
                       .ge(Order::getPayTime, compareStartTime)
@@ -190,26 +187,28 @@ public class DashboardServiceImpl implements DashboardService {
         
         List<Order> compareOrders = orderService.list(compareWrapper);
         
-        double compareSales = compareOrders.stream()
-                .mapToDouble(o -> o.getTotalAmount() != null ? o.getTotalAmount() : 0)
-                .sum();
+        BigDecimal compareSales = compareOrders.stream()
+                .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
         int compareOrderCount = compareOrders.size();
-        double compareAvgPrice = compareOrderCount > 0 ? compareSales / compareOrderCount : 0;
+        BigDecimal compareAvgPrice = compareOrderCount > 0 
+                ? compareSales.divide(BigDecimal.valueOf(compareOrderCount), 2, RoundingMode.HALF_UP) 
+                : BigDecimal.ZERO;
 
-        // 环比增长率
         result.put("salesGrowth", formatGrowth(totalSales, compareSales));
         result.put("ordersGrowth", formatGrowth(totalOrders, compareOrderCount));
         result.put("avgOrderGrowth", formatGrowth(avgOrderPrice, compareAvgPrice));
 
-        // 毛利和毛利率(假设毛利为销售额的30%,实际应从成本数据计算)
-        double grossProfit = totalSales * 0.3;
-        double profitMargin = totalSales > 0 ? (grossProfit / totalSales) * 100 : 0;
-        double compareGrossProfit = compareSales * 0.3;
+        BigDecimal grossProfit = totalSales.multiply(new BigDecimal("0.3"));
+        BigDecimal profitMargin = totalSales.compareTo(BigDecimal.ZERO) > 0 
+                ? grossProfit.divide(totalSales, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100"))
+                : BigDecimal.ZERO;
+        BigDecimal compareGrossProfit = compareSales.multiply(new BigDecimal("0.3"));
         
-        result.put("grossProfit", String.format("%.2f", grossProfit));
-        result.put("profitMargin", String.format("%.0f", profitMargin) + "%");
+        result.put("grossProfit", grossProfit.setScale(2, RoundingMode.HALF_UP).toString());
+        result.put("profitMargin", profitMargin.setScale(1, RoundingMode.HALF_UP).toString() + "%");
         result.put("profitGrowth", formatGrowth(grossProfit, compareGrossProfit));
-        result.put("marginGrowth", "+0%"); // 毛利率变化
+        result.put("marginGrowth", "+0%");
 
         // 用户统计
         // 新增用户数
@@ -228,11 +227,11 @@ public class DashboardServiceImpl implements DashboardService {
         }
         result.put("transactUsers", transactUserIds.size());
 
-        // 客单价(已付款用户的人均消费)
-        double customerPrice = transactUserIds.size() > 0 ? totalSales / transactUserIds.size() : 0;
-        result.put("customerPrice", String.format("%.2f", customerPrice));
+        BigDecimal customerPrice = transactUserIds.size() > 0 
+                ? totalSales.divide(BigDecimal.valueOf(transactUserIds.size()), 2, RoundingMode.HALF_UP) 
+                : BigDecimal.ZERO;
+        result.put("customerPrice", customerPrice.toString());
 
-        // 对比期用户统计
         long compareNewUsers = userService.lambdaQuery()
                 .ge(User::getCreateTime, compareStartTime)
                 .le(User::getCreateTime, compareEndTime)
@@ -244,16 +243,16 @@ public class DashboardServiceImpl implements DashboardService {
                 compareTransactUserIds.add(order.getUserId());
             }
         }
-        double compareCustomerPrice = compareTransactUserIds.size() > 0 
-                ? compareSales / compareTransactUserIds.size() : 0;
+        BigDecimal compareCustomerPrice = compareTransactUserIds.size() > 0 
+                ? compareSales.divide(BigDecimal.valueOf(compareTransactUserIds.size()), 2, RoundingMode.HALF_UP) 
+                : BigDecimal.ZERO;
 
         result.put("newUsersGrowth", formatGrowth(newUsers, compareNewUsers));
         result.put("transactGrowth", formatGrowth(transactUserIds.size(), compareTransactUserIds.size()));
         result.put("customerGrowth", formatGrowth(customerPrice, compareCustomerPrice));
 
-        // 图表数据
         List<String> dates = new ArrayList<>();
-        List<Double> salesData = new ArrayList<>();
+        List<BigDecimal> salesData = new ArrayList<>();
         List<Integer> ordersData = new ArrayList<>();
 
         DateTimeFormatter formatter = type.equals("yesterday") 
@@ -261,7 +260,6 @@ public class DashboardServiceImpl implements DashboardService {
                 : DateTimeFormatter.ofPattern("MM-dd");
 
         if ("yesterday".equals(type)) {
-            // 按小时统计
             for (int i = 0; i < 24; i++) {
                 LocalDateTime hourStart = startTime.withHour(i);
                 LocalDateTime hourEnd = hourStart.withMinute(59).withSecond(59);
@@ -269,10 +267,10 @@ public class DashboardServiceImpl implements DashboardService {
                 dates.add(String.format("%d:00", i));
                 
                 final int hour = i;
-                double hourSales = orders.stream()
+                BigDecimal hourSales = orders.stream()
                         .filter(o -> o.getPayTime() != null && o.getPayTime().getHour() == hour)
-                        .mapToDouble(o -> o.getTotalAmount() != null ? o.getTotalAmount() : 0)
-                        .sum();
+                        .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                 long hourOrders = orders.stream()
                         .filter(o -> o.getPayTime() != null && o.getPayTime().getHour() == hour)
                         .count();
@@ -281,7 +279,6 @@ public class DashboardServiceImpl implements DashboardService {
                 ordersData.add((int) hourOrders);
             }
         } else {
-            // 按天统计
             for (int i = 0; i < days; i++) {
                 LocalDate date = startTime.toLocalDate().plusDays(i);
                 LocalDateTime dayStart = date.atStartOfDay();
@@ -289,12 +286,12 @@ public class DashboardServiceImpl implements DashboardService {
                 
                 dates.add(date.format(DateTimeFormatter.ofPattern("MM-dd")));
                 
-                double daySales = orders.stream()
+                BigDecimal daySales = orders.stream()
                         .filter(o -> o.getPayTime() != null 
                                 && !o.getPayTime().isBefore(dayStart) 
                                 && !o.getPayTime().isAfter(dayEnd))
-                        .mapToDouble(o -> o.getTotalAmount() != null ? o.getTotalAmount() : 0)
-                        .sum();
+                        .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                 long dayOrders = orders.stream()
                         .filter(o -> o.getPayTime() != null 
                                 && !o.getPayTime().isBefore(dayStart) 
@@ -382,11 +379,11 @@ public class DashboardServiceImpl implements DashboardService {
     /**
      * 格式化对比数值(正负号)
      */
-    private String formatCompare(double value) {
-        if (value > 0) {
-            return "+" + String.format("%.2f", value);
-        } else if (value < 0) {
-            return String.format("%.2f", value);
+    private String formatCompare(BigDecimal value) {
+        if (value.compareTo(BigDecimal.ZERO) > 0) {
+            return "+" + value.setScale(2, RoundingMode.HALF_UP).toString();
+        } else if (value.compareTo(BigDecimal.ZERO) < 0) {
+            return value.setScale(2, RoundingMode.HALF_UP).toString();
         }
         return "+0.00";
     }
@@ -406,15 +403,17 @@ public class DashboardServiceImpl implements DashboardService {
     /**
      * 格式化增长率
      */
-    private String formatGrowth(double current, double previous) {
-        if (previous == 0) {
-            return current > 0 ? "+100%" : "+0%";
+    private String formatGrowth(BigDecimal current, BigDecimal previous) {
+        if (previous.compareTo(BigDecimal.ZERO) == 0) {
+            return current.compareTo(BigDecimal.ZERO) > 0 ? "+100%" : "+0%";
         }
-        double growth = ((current - previous) / previous) * 100;
-        if (growth > 0) {
-            return "+" + String.format("%.0f", growth) + "%";
-        } else if (growth < 0) {
-            return String.format("%.0f", growth) + "%";
+        BigDecimal growth = current.subtract(previous)
+                .divide(previous, 4, RoundingMode.HALF_UP)
+                .multiply(new BigDecimal("100"));
+        if (growth.compareTo(BigDecimal.ZERO) > 0) {
+            return "+" + growth.setScale(1, RoundingMode.HALF_UP) + "%";
+        } else if (growth.compareTo(BigDecimal.ZERO) < 0) {
+            return growth.setScale(1, RoundingMode.HALF_UP) + "%";
         }
         return "+0%";
     }

+ 10 - 6
haha-service/src/main/java/com/haha/service/impl/OrderServiceImpl.java

@@ -16,6 +16,8 @@ import lombok.extern.slf4j.Slf4j;
 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.LocalTime;
@@ -108,16 +110,18 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
         statistics.put("refundOrders", refundOrders);
 
         // 总销售额(使用SQL聚合优化性能)
-        Double totalAmount = baseMapper.sumCompletedOrderAmount(null);
-        statistics.put("totalAmount", String.format("%.2f", totalAmount != null ? totalAmount : 0));
+        BigDecimal totalAmount = baseMapper.sumCompletedOrderAmount(null);
+        statistics.put("totalAmount", totalAmount != null ? totalAmount.setScale(2, RoundingMode.HALF_UP).toString() : "0.00");
 
         // 今日销售额
-        Double todayAmount = baseMapper.sumCompletedOrderAmount(todayStart);
-        statistics.put("todayAmount", String.format("%.2f", todayAmount != null ? todayAmount : 0));
+        BigDecimal todayAmount = baseMapper.sumCompletedOrderAmount(todayStart);
+        statistics.put("todayAmount", todayAmount != null ? todayAmount.setScale(2, RoundingMode.HALF_UP).toString() : "0.00");
 
         // 平均订单金额
-        double averageAmount = completedOrders > 0 ? (totalAmount != null ? totalAmount : 0) / completedOrders : 0;
-        statistics.put("averageAmount", String.format("%.2f", averageAmount));
+        BigDecimal averageAmount = completedOrders > 0 && totalAmount != null 
+            ? totalAmount.divide(BigDecimal.valueOf(completedOrders), 2, RoundingMode.HALF_UP) 
+            : BigDecimal.ZERO;
+        statistics.put("averageAmount", averageAmount.toString());
 
         return statistics;
     }