feat(statistics): 添加营业概览统计功能
- 新增营业概览、收款构成、营业构成等统计接口和页面 - 实现订单数、营业额、优惠金额等统计指标 - 添加虚拟发货的物流方式 - 优化订单和充值相关查询方法
This commit is contained in:
@@ -19,7 +19,11 @@ public enum DeliveryMethodEnum {
|
||||
/**
|
||||
* "物流"
|
||||
*/
|
||||
LOGISTICS("物流");
|
||||
LOGISTICS("物流"),
|
||||
/**
|
||||
* 虚拟发货
|
||||
*/
|
||||
VIRTUAL("虚拟发货");
|
||||
|
||||
private final String description;
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package cn.lili.modules.statistics.entity.vo;
|
||||
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 营业构成VO
|
||||
* @author Bulbasaur
|
||||
* @since 2025/08/25 7:07 下午
|
||||
*/
|
||||
@Data
|
||||
public class BusinessCompositionDataVO {
|
||||
|
||||
//订单分类构成
|
||||
@ApiModelProperty(value = "到店自提")
|
||||
private Double storeSelf;
|
||||
@ApiModelProperty(value = "快递发货")
|
||||
private Double express;
|
||||
@ApiModelProperty(value = "线上无需配送")
|
||||
private Double online;
|
||||
|
||||
//营业收入
|
||||
@ApiModelProperty(value = "商品销售")
|
||||
private Double income;
|
||||
@ApiModelProperty(value = "运费")
|
||||
private Double freight;
|
||||
@ApiModelProperty(value = "商品返现(分销返佣)")
|
||||
private Double incomeBack;
|
||||
@ApiModelProperty(value = "商品销售+费用构成")
|
||||
private Double incomeComposition;
|
||||
|
||||
//退款统计
|
||||
@ApiModelProperty(value = "退款订单笔数")
|
||||
private Long refundOrderNum;
|
||||
@ApiModelProperty(value = "退款金额")
|
||||
private Double refund;
|
||||
@ApiModelProperty(value = "退款率")
|
||||
private Double refundRate;
|
||||
|
||||
//消费指标
|
||||
@ApiModelProperty(value = "支付金额")
|
||||
private Double pay;
|
||||
@ApiModelProperty(value = "折后笔单价")
|
||||
private Double price;
|
||||
@ApiModelProperty(value = "支付人数")
|
||||
private Long payNum;
|
||||
@ApiModelProperty(value = "折后客单价")
|
||||
private Double priceNum;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package cn.lili.modules.statistics.entity.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 概览数据
|
||||
* @author Bulbasaur
|
||||
* @since 2025/08/25 7:07 下午
|
||||
*/
|
||||
@Data
|
||||
public class OverViewDataVO {
|
||||
|
||||
|
||||
@ApiModelProperty(value = "营业额")
|
||||
private Double turnover;
|
||||
@ApiModelProperty(value = "优惠金额")
|
||||
private Double discount;
|
||||
@ApiModelProperty(value = "营业收入不含数值储值金额")
|
||||
private Double incomeNoStoreValue;
|
||||
@ApiModelProperty(value = "支付订单数")
|
||||
private Long payOrderNum;
|
||||
@ApiModelProperty(value = "新增充值金额")
|
||||
private Double recharge;
|
||||
@ApiModelProperty(value = "使用充值金额")
|
||||
private Long rechargeUse;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.lili.modules.statistics.entity.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 收款构成
|
||||
*
|
||||
* @author Bulbasaur
|
||||
* @since 2025/08/25 7:07 下午
|
||||
*/
|
||||
@Data
|
||||
public class SourceDataVO {
|
||||
|
||||
@ApiModelProperty(value = "支付方式")
|
||||
private String payType;
|
||||
@ApiModelProperty(value = "收款合计")
|
||||
private Double total;
|
||||
@ApiModelProperty(value = "营业收入")
|
||||
private Double income;
|
||||
@ApiModelProperty(value = "新增储值金额")
|
||||
private Double recharge;
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package cn.lili.modules.statistics.mapper;
|
||||
|
||||
import cn.lili.modules.order.order.entity.dos.Order;
|
||||
import cn.lili.modules.order.order.entity.dos.OrderItem;
|
||||
import cn.lili.modules.order.order.entity.vo.OrderSimpleVO;
|
||||
import cn.lili.modules.statistics.entity.vo.OrderStatisticsDataVO;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
@@ -60,4 +61,24 @@ public interface OrderStatisticsMapper extends BaseMapper<Order> {
|
||||
" FROM li_order o INNER JOIN li_order_item AS oi on o.sn = oi.order_sn ${ew.customSqlSegment} ")
|
||||
IPage<OrderSimpleVO> queryByParams(IPage<OrderSimpleVO> page, @Param(Constants.WRAPPER) Wrapper<OrderSimpleVO> queryWrapper);
|
||||
|
||||
|
||||
/**
|
||||
* 查询已付款未全部退款的订单数量
|
||||
*/
|
||||
@Select("SELECT COALESCE(COUNT(DISTINCT order_sn), 0) FROM li_order_item ${ew.customSqlSegment} ")
|
||||
Long getPayOrderNum(@Param(Constants.WRAPPER) Wrapper<OrderItem> queryWrapper);
|
||||
/**
|
||||
* 查询已付款未全部退款的订单金额
|
||||
*/
|
||||
@Select("SELECT COALESCE(SUM( oi.flow_price )- SUM( oi.refund_price ), 0) FROM li_order_item oi INNER JOIN li_order o ON o.sn=oi.order_sn ${ew.customSqlSegment} ")
|
||||
Double getPayOrderPrice(@Param(Constants.WRAPPER) Wrapper<OrderItem> queryWrapper);
|
||||
|
||||
/**
|
||||
* 查询商品价格
|
||||
*/
|
||||
@Select("SELECT COALESCE(SUM(goods_price), 0) FROM li_order_item ${ew.customSqlSegment} ")
|
||||
Double getGoodsPrice(@Param(Constants.WRAPPER) Wrapper<OrderItem> queryWrapper);
|
||||
|
||||
@Select("SELECT COALESCE(SUM( oi.refund_price ), 0) FROM li_order_item oi INNER JOIN li_order o ON o.sn=oi.order_sn ${ew.customSqlSegment} ")
|
||||
Double getRefundPrice(@Param(Constants.WRAPPER) Wrapper<OrderItem> queryWrapper);
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
package cn.lili.modules.statistics.service;
|
||||
|
||||
import cn.lili.common.vo.PageVO;
|
||||
import cn.lili.modules.order.cart.entity.enums.DeliveryMethodEnum;
|
||||
import cn.lili.modules.order.order.entity.dos.Order;
|
||||
import cn.lili.modules.order.order.entity.vo.OrderSimpleVO;
|
||||
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
|
||||
import cn.lili.modules.statistics.entity.dto.StatisticsQueryParam;
|
||||
import cn.lili.modules.statistics.entity.vo.OrderOverviewVO;
|
||||
import cn.lili.modules.statistics.entity.vo.OrderStatisticsDataVO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -34,6 +37,22 @@ public interface OrderStatisticsService extends IService<Order> {
|
||||
* @return 订单总数量
|
||||
*/
|
||||
long orderNum(String orderStatus);
|
||||
/**
|
||||
* 获取订单总数量
|
||||
*
|
||||
* @param paymentMethod 支付方式
|
||||
* @param dates 时间
|
||||
*
|
||||
* @return 订单总数量
|
||||
*/
|
||||
long orderNum(String paymentMethod, Date[] dates);
|
||||
|
||||
/**
|
||||
* 获取所有优惠金额去除退款金额
|
||||
* @param dates
|
||||
* @return
|
||||
*/
|
||||
Double getDiscountPrice(Date[] dates);
|
||||
|
||||
/**
|
||||
* 图表统计
|
||||
@@ -51,4 +70,64 @@ public interface OrderStatisticsService extends IService<Order> {
|
||||
* @return
|
||||
*/
|
||||
IPage<OrderSimpleVO> getStatistics(StatisticsQueryParam statisticsQueryParam, PageVO pageVO);
|
||||
|
||||
/**
|
||||
* 获取付款订单数量 不含全部退款
|
||||
*
|
||||
* @param dates 时间
|
||||
* @return 付款订单数量
|
||||
*/
|
||||
long getPayOrderNum(Date[] dates);
|
||||
|
||||
/**
|
||||
* 获取付款订单金额去除退款金额
|
||||
*
|
||||
* @param dates 时间
|
||||
* @param paymentMethodEnum 支付方式
|
||||
* @param deliveryMethodEnum 配送方式
|
||||
* @return 付款订单金额
|
||||
*/
|
||||
Double getPayOrderPrice(Date[] dates, PaymentMethodEnum paymentMethodEnum, DeliveryMethodEnum deliveryMethodEnum);
|
||||
|
||||
/**
|
||||
* 获取商品价格
|
||||
* @param dates 时间
|
||||
* @return
|
||||
*/
|
||||
Double getGoodsPrice(Date[] dates);
|
||||
|
||||
/**
|
||||
* 获取运费
|
||||
* @param dates 时间
|
||||
* @return
|
||||
*/
|
||||
Double getFreight(Date[] dates);
|
||||
|
||||
/**
|
||||
* 获取分销返佣
|
||||
* @param dates
|
||||
* @return
|
||||
*/
|
||||
Double getDistribution(Date[] dates);
|
||||
|
||||
/**
|
||||
* 获取退款订单数
|
||||
* @param dates
|
||||
* @return
|
||||
*/
|
||||
Long getRefundNum(Date[] dates);
|
||||
|
||||
/**
|
||||
* 获取退款金额
|
||||
* @param dates
|
||||
* @return
|
||||
*/
|
||||
Double getRefundPrice(Date[] dates);
|
||||
|
||||
/**
|
||||
* 获取退款率
|
||||
* @param dates
|
||||
* @return
|
||||
*/
|
||||
Double getRefundRate(Date[] dates);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package cn.lili.modules.statistics.service;
|
||||
|
||||
import cn.lili.modules.statistics.entity.dto.StatisticsQueryParam;
|
||||
import cn.lili.modules.statistics.entity.vo.BusinessCompositionDataVO;
|
||||
import cn.lili.modules.statistics.entity.vo.OrderOverviewVO;
|
||||
import cn.lili.modules.statistics.entity.vo.OverViewDataVO;
|
||||
import cn.lili.modules.statistics.entity.vo.SourceDataVO;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 营业概览统计
|
||||
*
|
||||
* @author Bulbasaur
|
||||
* @since 2025/08/25 7:31 下午
|
||||
*/
|
||||
public interface OverViewStatisticsService {
|
||||
|
||||
|
||||
/**
|
||||
* 获取营业概览统计
|
||||
*
|
||||
* @param statisticsQueryParam 统计参数
|
||||
* @return 营业概览统计
|
||||
*/
|
||||
OverViewDataVO getOverViewDataVO(StatisticsQueryParam statisticsQueryParam);
|
||||
|
||||
|
||||
/**
|
||||
* 获取收款构成列表
|
||||
*
|
||||
* @param statisticsQueryParam 统计参数
|
||||
* @return 收款构成列表
|
||||
*/
|
||||
List<SourceDataVO> getSourceDataVOList(StatisticsQueryParam statisticsQueryParam);
|
||||
|
||||
/**
|
||||
* 获取营业构成列表
|
||||
*
|
||||
* @param statisticsQueryParam 统计参数
|
||||
* @return 营业构成列表
|
||||
*/
|
||||
BusinessCompositionDataVO businessCompositionDataVO(StatisticsQueryParam statisticsQueryParam);
|
||||
|
||||
|
||||
}
|
||||
@@ -6,10 +6,17 @@ import cn.lili.common.security.enums.UserEnums;
|
||||
import cn.lili.common.utils.CurrencyUtil;
|
||||
import cn.lili.common.utils.StringUtils;
|
||||
import cn.lili.common.vo.PageVO;
|
||||
import cn.lili.modules.order.cart.entity.enums.DeliveryMethodEnum;
|
||||
import cn.lili.modules.order.order.entity.dos.Order;
|
||||
import cn.lili.modules.order.order.entity.dos.OrderItem;
|
||||
import cn.lili.modules.order.order.entity.dto.PriceDetailDTO;
|
||||
import cn.lili.modules.order.order.entity.enums.FlowTypeEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.OrderTypeEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.PayStatusEnum;
|
||||
import cn.lili.modules.order.order.entity.enums.RefundStatusEnum;
|
||||
import cn.lili.modules.order.order.entity.vo.OrderSimpleVO;
|
||||
import cn.lili.modules.order.order.service.OrderItemService;
|
||||
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
|
||||
import cn.lili.modules.statistics.entity.dto.StatisticsQueryParam;
|
||||
import cn.lili.modules.statistics.entity.vo.OrderOverviewVO;
|
||||
import cn.lili.modules.statistics.entity.vo.OrderStatisticsDataVO;
|
||||
@@ -38,6 +45,8 @@ import java.util.*;
|
||||
@Service
|
||||
public class OrderStatisticsServiceImpl extends ServiceImpl<OrderStatisticsMapper, Order> implements OrderStatisticsService {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 平台PV统计
|
||||
*/
|
||||
@@ -46,6 +55,8 @@ public class OrderStatisticsServiceImpl extends ServiceImpl<OrderStatisticsMappe
|
||||
|
||||
@Autowired
|
||||
private StoreFlowStatisticsService storeFlowStatisticsService;
|
||||
@Autowired
|
||||
private OrderItemService orderItemService;
|
||||
|
||||
@Override
|
||||
public OrderOverviewVO overview(StatisticsQueryParam statisticsQueryParam) {
|
||||
@@ -104,6 +115,197 @@ public class OrderStatisticsServiceImpl extends ServiceImpl<OrderStatisticsMappe
|
||||
return this.count(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long orderNum(String paymentMethod, Date[] dates) {
|
||||
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(CharSequenceUtil.isNotEmpty(paymentMethod), Order::getPaymentMethod, paymentMethod);
|
||||
queryWrapper.between(Order::getCreateTime, dates[0], dates[1]);
|
||||
return this.count(queryWrapper);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Double getDiscountPrice(Date[] dates) {
|
||||
// 参数校验
|
||||
if (dates == null || dates.length < 2) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// 构建查询条件:按时间范围过滤,排除全部退款的订单项
|
||||
LambdaQueryWrapper<OrderItem> queryWrapper = new LambdaQueryWrapper<OrderItem>()
|
||||
.ne(OrderItem::getIsRefund, RefundStatusEnum.ALL_REFUND.name())
|
||||
.between(OrderItem::getCreateTime, dates[0], dates[1]);
|
||||
|
||||
List<OrderItem> orderItems = orderItemService.list(queryWrapper);
|
||||
|
||||
if (orderItems.isEmpty()) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
Double totalDiscountPrice = 0.0;
|
||||
|
||||
for (OrderItem orderItem : orderItems) {
|
||||
PriceDetailDTO priceDetailDTO = orderItem.getPriceDetailDTO();
|
||||
if (priceDetailDTO == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Double itemDiscountPrice = calculateItemDiscountPrice(priceDetailDTO);
|
||||
|
||||
if (RefundStatusEnum.NO_REFUND.name().equals(orderItem.getIsRefund())) {
|
||||
// 未退款:计算全部优惠金额
|
||||
totalDiscountPrice = CurrencyUtil.add(totalDiscountPrice, itemDiscountPrice);
|
||||
} else {
|
||||
// 部分退款:按比例计算剩余优惠金额
|
||||
Double remainingDiscountPrice = calculateRemainingDiscountPrice(
|
||||
itemDiscountPrice, orderItem.getNum(), orderItem.getReturnGoodsNumber());
|
||||
totalDiscountPrice = CurrencyUtil.add(totalDiscountPrice, remainingDiscountPrice);
|
||||
}
|
||||
}
|
||||
|
||||
return totalDiscountPrice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPayOrderNum(Date[] dates) {
|
||||
|
||||
LambdaQueryWrapper<OrderItem> orderItemLambdaQueryWrapper=new LambdaQueryWrapper<>();
|
||||
|
||||
orderItemLambdaQueryWrapper.between(OrderItem::getCreateTime,dates[0], dates[1]);
|
||||
orderItemLambdaQueryWrapper.ne(OrderItem::getIsRefund,RefundStatusEnum.ALL_REFUND.name());
|
||||
|
||||
return this.baseMapper.getPayOrderNum(orderItemLambdaQueryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getPayOrderPrice(Date[] dates, PaymentMethodEnum paymentMethodEnum, DeliveryMethodEnum deliveryMethodEnum) {
|
||||
|
||||
//查看付款金额
|
||||
QueryWrapper queryWrapper = Wrappers.query();
|
||||
|
||||
queryWrapper.between("oi.create_time", dates[0], dates[1]);
|
||||
queryWrapper.ne("oi.is_refund", RefundStatusEnum.ALL_REFUND.name());
|
||||
|
||||
if(paymentMethodEnum!=null){
|
||||
queryWrapper.eq("o.payment_method",paymentMethodEnum.name());
|
||||
}
|
||||
if(deliveryMethodEnum!=null){
|
||||
if(DeliveryMethodEnum.VIRTUAL.equals(deliveryMethodEnum)){
|
||||
queryWrapper.eq("o.order_type", OrderTypeEnum.VIRTUAL.name());
|
||||
}else{
|
||||
queryWrapper.eq("o.delivery_method",deliveryMethodEnum.name());
|
||||
}
|
||||
|
||||
}
|
||||
return this.baseMapper.getPayOrderPrice(queryWrapper);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getGoodsPrice(Date[] dates) {
|
||||
LambdaQueryWrapper<OrderItem> orderItemLambdaQueryWrapper=new LambdaQueryWrapper<>();
|
||||
|
||||
orderItemLambdaQueryWrapper.between(OrderItem::getCreateTime,dates[0], dates[1]);
|
||||
orderItemLambdaQueryWrapper.ne(OrderItem::getIsRefund,RefundStatusEnum.ALL_REFUND.name());
|
||||
|
||||
return this.baseMapper.getGoodsPrice(orderItemLambdaQueryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getFreight(Date[] dates) {
|
||||
|
||||
LambdaQueryWrapper<OrderItem> orderItemLambdaQueryWrapper=new LambdaQueryWrapper<>();
|
||||
|
||||
orderItemLambdaQueryWrapper.between(OrderItem::getCreateTime,dates[0], dates[1]);
|
||||
orderItemLambdaQueryWrapper.ne(OrderItem::getIsRefund,RefundStatusEnum.ALL_REFUND.name());
|
||||
|
||||
List<OrderItem> orderItems=orderItemService.list(orderItemLambdaQueryWrapper);
|
||||
Double freight=0D;
|
||||
for (OrderItem orderItem:orderItems){
|
||||
PriceDetailDTO priceDetailDTO=orderItem.getPriceDetailDTO();
|
||||
freight=CurrencyUtil.add(freight,priceDetailDTO.getFreightPrice());
|
||||
}
|
||||
return freight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getDistribution(Date[] dates) {
|
||||
LambdaQueryWrapper<OrderItem> orderItemLambdaQueryWrapper=new LambdaQueryWrapper<>();
|
||||
|
||||
orderItemLambdaQueryWrapper.between(OrderItem::getCreateTime,dates[0], dates[1]);
|
||||
orderItemLambdaQueryWrapper.ne(OrderItem::getIsRefund,RefundStatusEnum.ALL_REFUND.name());
|
||||
|
||||
List<OrderItem> orderItems=orderItemService.list(orderItemLambdaQueryWrapper);
|
||||
Double distributionCommission=0D;
|
||||
for (OrderItem orderItem:orderItems){
|
||||
PriceDetailDTO priceDetailDTO=orderItem.getPriceDetailDTO();
|
||||
distributionCommission=CurrencyUtil.add(distributionCommission,priceDetailDTO.getDistributionCommission());
|
||||
}
|
||||
return distributionCommission;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getRefundNum(Date[] dates) {
|
||||
LambdaQueryWrapper<OrderItem> orderItemLambdaQueryWrapper=new LambdaQueryWrapper<>();
|
||||
|
||||
orderItemLambdaQueryWrapper.between(OrderItem::getCreateTime,dates[0], dates[1]);
|
||||
orderItemLambdaQueryWrapper.eq(OrderItem::getIsRefund,RefundStatusEnum.ALL_REFUND.name());
|
||||
|
||||
return this.baseMapper.getPayOrderNum(orderItemLambdaQueryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRefundPrice(Date[] dates) {
|
||||
|
||||
QueryWrapper queryWrapper = Wrappers.query();
|
||||
|
||||
queryWrapper.between("oi.create_time", dates[0], dates[1]);
|
||||
queryWrapper.eq("oi.is_refund", RefundStatusEnum.ALL_REFUND.name());
|
||||
|
||||
|
||||
return this.baseMapper.getRefundPrice(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRefundRate(Date[] dates) {
|
||||
|
||||
QueryWrapper queryWrapper = Wrappers.query();
|
||||
|
||||
queryWrapper.between("create_time", dates[0], dates[1]);
|
||||
|
||||
|
||||
Long orderNum= this.baseMapper.getPayOrderNum(queryWrapper);
|
||||
return CurrencyUtil.mul(CurrencyUtil.div(this.getRefundNum(dates),orderNum),100);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算订单项的优惠金额
|
||||
*/
|
||||
private Double calculateItemDiscountPrice(PriceDetailDTO priceDetailDTO) {
|
||||
Double discountPrice = priceDetailDTO.getDiscountPrice() != null ? priceDetailDTO.getDiscountPrice() : 0.0;
|
||||
Double couponPrice = priceDetailDTO.getCouponPrice() != null ? priceDetailDTO.getCouponPrice() : 0.0;
|
||||
return CurrencyUtil.add(discountPrice, couponPrice);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算部分退款后的剩余优惠金额
|
||||
*/
|
||||
private Double calculateRemainingDiscountPrice(Double totalDiscountPrice, Integer totalNum, Integer returnNum) {
|
||||
if (totalNum == null || totalNum <= 0 || returnNum == null || returnNum < 0) {
|
||||
return totalDiscountPrice;
|
||||
}
|
||||
|
||||
Integer remainingNum = totalNum - returnNum;
|
||||
if (remainingNum <= 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// 按剩余数量比例计算优惠金额
|
||||
Double ratio = CurrencyUtil.div(remainingNum.doubleValue(), totalNum.doubleValue(), 4);
|
||||
return CurrencyUtil.mul(totalDiscountPrice, ratio);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<OrderStatisticsDataVO> statisticsChart(StatisticsQueryParam statisticsQueryParam) {
|
||||
Date[] dates = StatisticsDateUtil.getDateArray(statisticsQueryParam);
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
package cn.lili.modules.statistics.serviceimpl;
|
||||
|
||||
import cn.lili.common.utils.CurrencyUtil;
|
||||
import cn.lili.modules.order.cart.entity.enums.DeliveryMethodEnum;
|
||||
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
|
||||
import cn.lili.modules.statistics.entity.dto.StatisticsQueryParam;
|
||||
import cn.lili.modules.statistics.entity.vo.BusinessCompositionDataVO;
|
||||
import cn.lili.modules.statistics.entity.vo.OrderOverviewVO;
|
||||
import cn.lili.modules.statistics.entity.vo.OverViewDataVO;
|
||||
import cn.lili.modules.statistics.entity.vo.SourceDataVO;
|
||||
import cn.lili.modules.statistics.service.OrderStatisticsService;
|
||||
import cn.lili.modules.statistics.service.OverViewStatisticsService;
|
||||
import cn.lili.modules.statistics.util.StatisticsDateUtil;
|
||||
import cn.lili.modules.wallet.service.RechargeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Bulbasaur
|
||||
* @since 2025/08/25 7:07 下午
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
public class OverViewStatisticsServiceImpl implements OverViewStatisticsService {
|
||||
|
||||
@Autowired
|
||||
private RechargeService rechargeService;
|
||||
@Autowired
|
||||
private OrderStatisticsService orderStatisticsService;
|
||||
@Override
|
||||
public OverViewDataVO getOverViewDataVO(StatisticsQueryParam statisticsQueryParam) {
|
||||
Date[] dates = StatisticsDateUtil.getDateArray(statisticsQueryParam);
|
||||
|
||||
OverViewDataVO overViewDataVO = new OverViewDataVO();
|
||||
//营业收入不含数值储值金额.订单扣除退款折扣后金额(不含储值充值)
|
||||
overViewDataVO.setIncomeNoStoreValue(orderStatisticsService.getPayOrderPrice(dates,null,null));
|
||||
//优惠金额.订单的优惠金额(扣除退款,不含储值充值)
|
||||
overViewDataVO.setDiscount(orderStatisticsService.getDiscountPrice( dates));
|
||||
//营业额.营业额=营业收入+优惠金额,订单扣除退款折扣前金额(不含储值充值)
|
||||
overViewDataVO.setTurnover(CurrencyUtil.add(overViewDataVO.getIncomeNoStoreValue(), overViewDataVO.getDiscount()));
|
||||
//支付订单数.按客户支付完成时间统计的成功付款的订单数(不含退款、储值充值)
|
||||
overViewDataVO.setPayOrderNum(orderStatisticsService.getPayOrderNum(dates));
|
||||
//新增充值金额.按客户支付完成时间统计的客户储值充值本金金额
|
||||
overViewDataVO.setRecharge(rechargeService.getRecharge(dates,null));
|
||||
//使用充值金额.使用储值支付本金金额:统计时间范围内,支付和退款成功的订单中,使用储值支付且扣除退款的金额
|
||||
overViewDataVO.setRechargeUse(orderStatisticsService.orderNum(PaymentMethodEnum.WALLET.name(), dates));
|
||||
|
||||
return overViewDataVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SourceDataVO> getSourceDataVOList(StatisticsQueryParam statisticsQueryParam) {
|
||||
Date[] dates = StatisticsDateUtil.getDateArray(statisticsQueryParam);
|
||||
List<SourceDataVO> sourceDataVOList=new ArrayList<>();
|
||||
//微信
|
||||
SourceDataVO sourceDataVO=new SourceDataVO();
|
||||
sourceDataVO.setPayType(PaymentMethodEnum.WECHAT.paymentName());
|
||||
|
||||
sourceDataVO.setIncome(orderStatisticsService.getPayOrderPrice(dates,PaymentMethodEnum.WECHAT,null));
|
||||
sourceDataVO.setRecharge(rechargeService.getRecharge(dates,PaymentMethodEnum.WECHAT));
|
||||
sourceDataVO.setTotal(CurrencyUtil.add(sourceDataVO.getIncome(),sourceDataVO.getRecharge()));
|
||||
sourceDataVOList.add(sourceDataVO);
|
||||
|
||||
//支付宝
|
||||
SourceDataVO zhifubao=new SourceDataVO();
|
||||
zhifubao.setPayType(PaymentMethodEnum.ALIPAY.paymentName());
|
||||
zhifubao.setIncome(orderStatisticsService.getPayOrderPrice(dates,PaymentMethodEnum.ALIPAY,null));
|
||||
zhifubao.setRecharge(rechargeService.getRecharge(dates,PaymentMethodEnum.ALIPAY));
|
||||
zhifubao.setTotal(CurrencyUtil.add(zhifubao.getIncome(),zhifubao.getRecharge()));
|
||||
sourceDataVOList.add(zhifubao);
|
||||
|
||||
//线下支付
|
||||
SourceDataVO bankTransfer=new SourceDataVO();
|
||||
bankTransfer.setPayType(PaymentMethodEnum.BANK_TRANSFER.paymentName());
|
||||
bankTransfer.setIncome(orderStatisticsService.getPayOrderPrice(dates,PaymentMethodEnum.BANK_TRANSFER,null));
|
||||
bankTransfer.setRecharge(rechargeService.getRecharge(dates,PaymentMethodEnum.BANK_TRANSFER));
|
||||
bankTransfer.setTotal(CurrencyUtil.add(bankTransfer.getIncome(),bankTransfer.getRecharge()));
|
||||
sourceDataVOList.add(bankTransfer);
|
||||
|
||||
//余额
|
||||
SourceDataVO wallet=new SourceDataVO();
|
||||
wallet.setPayType(PaymentMethodEnum.WALLET.paymentName());
|
||||
wallet.setIncome(orderStatisticsService.getPayOrderPrice(dates,PaymentMethodEnum.WALLET,null));
|
||||
wallet.setRecharge(rechargeService.getRecharge(dates,PaymentMethodEnum.WALLET));
|
||||
wallet.setTotal(CurrencyUtil.add(wallet.getIncome(),wallet.getRecharge()));
|
||||
sourceDataVOList.add(wallet);
|
||||
return sourceDataVOList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BusinessCompositionDataVO businessCompositionDataVO(StatisticsQueryParam statisticsQueryParam) {
|
||||
Date[] dates = StatisticsDateUtil.getDateArray(statisticsQueryParam);
|
||||
BusinessCompositionDataVO businessCompositionDataVO=new BusinessCompositionDataVO();
|
||||
//-----订单分类构成-----
|
||||
|
||||
businessCompositionDataVO.setStoreSelf(orderStatisticsService.getPayOrderPrice(dates,null, DeliveryMethodEnum.SELF_PICK_UP));
|
||||
businessCompositionDataVO.setExpress(orderStatisticsService.getPayOrderPrice(dates,null, DeliveryMethodEnum.LOGISTICS));
|
||||
businessCompositionDataVO.setOnline(orderStatisticsService.getPayOrderPrice(dates,null, DeliveryMethodEnum.VIRTUAL));
|
||||
|
||||
//-----营业收入-----
|
||||
//商品销售
|
||||
businessCompositionDataVO.setIncome(orderStatisticsService.getGoodsPrice(dates));
|
||||
//运费
|
||||
businessCompositionDataVO.setFreight(orderStatisticsService.getFreight(dates));
|
||||
//商品返现(分销返佣)
|
||||
businessCompositionDataVO.setIncomeBack(orderStatisticsService.getDistribution(dates));
|
||||
//商品销售+费用构成
|
||||
businessCompositionDataVO.setIncomeComposition(
|
||||
CurrencyUtil.sub(CurrencyUtil.add(businessCompositionDataVO.getIncome(), businessCompositionDataVO.getFreight()),
|
||||
businessCompositionDataVO.getIncomeBack()));
|
||||
|
||||
//-----退款统计-----
|
||||
//退款订单笔数
|
||||
businessCompositionDataVO.setRefundOrderNum(orderStatisticsService.getRefundNum(dates));
|
||||
//退款金额
|
||||
businessCompositionDataVO.setRefund(orderStatisticsService.getRefundPrice(dates));
|
||||
//退款率
|
||||
businessCompositionDataVO.setRefundRate(orderStatisticsService.getRefundRate(dates));
|
||||
|
||||
//-----消费指标-----
|
||||
//支付金额
|
||||
OrderOverviewVO overview=orderStatisticsService.overview(statisticsQueryParam);
|
||||
businessCompositionDataVO.setPay(overview.getPaymentAmount());
|
||||
//折后笔单价
|
||||
businessCompositionDataVO.setPrice(CurrencyUtil.div(overview.getPaymentAmount(),overview.getPaymentOrderNum()));
|
||||
//支付人数
|
||||
businessCompositionDataVO.setPayNum(overview.getPaymentsNum());
|
||||
//折后客单价
|
||||
businessCompositionDataVO.setPriceNum(CurrencyUtil.div(overview.getPaymentAmount(),overview.getPaymentsNum()));
|
||||
|
||||
return businessCompositionDataVO;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
package cn.lili.modules.wallet.mapper;
|
||||
|
||||
import cn.lili.modules.order.order.entity.vo.PaymentLog;
|
||||
import cn.lili.modules.wallet.entity.dos.Recharge;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
/**
|
||||
* 预存款充值记录数据处理层
|
||||
@@ -11,4 +16,13 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
*/
|
||||
public interface RechargeMapper extends BaseMapper<Recharge> {
|
||||
|
||||
|
||||
/**
|
||||
* 获取会员预存款
|
||||
*
|
||||
* @return 会员预存款
|
||||
*/
|
||||
@Select("SELECT COALESCE(SUM(recharge_money), 0) FROM li_recharge ${ew.customSqlSegment}")
|
||||
Double getRecharge(@Param(Constants.WRAPPER) Wrapper<Recharge> queryWrapper);
|
||||
|
||||
}
|
||||
@@ -2,10 +2,13 @@ package cn.lili.modules.wallet.service;
|
||||
|
||||
import cn.lili.common.vo.PageVO;
|
||||
import cn.lili.modules.order.trade.entity.vo.RechargeQueryVO;
|
||||
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
|
||||
import cn.lili.modules.wallet.entity.dos.Recharge;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 预存款充值业务层
|
||||
*
|
||||
@@ -56,4 +59,10 @@ public interface RechargeService extends IService<Recharge> {
|
||||
*/
|
||||
void rechargeOrderCancel(String sn);
|
||||
|
||||
/**
|
||||
* 获取周期内的充值金额
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Double getRecharge(Date[] dates, PaymentMethodEnum paymentMethodEnum);
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import cn.lili.common.utils.SnowFlake;
|
||||
import cn.lili.common.vo.PageVO;
|
||||
import cn.lili.modules.order.order.entity.enums.PayStatusEnum;
|
||||
import cn.lili.modules.order.trade.entity.vo.RechargeQueryVO;
|
||||
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
|
||||
import cn.lili.modules.wallet.entity.dos.Recharge;
|
||||
import cn.lili.modules.wallet.entity.dto.MemberWalletUpdateDTO;
|
||||
import cn.lili.modules.wallet.entity.enums.DepositServiceTypeEnum;
|
||||
@@ -17,6 +18,7 @@ import cn.lili.modules.wallet.mapper.RechargeMapper;
|
||||
import cn.lili.modules.wallet.service.MemberWalletService;
|
||||
import cn.lili.modules.wallet.service.RechargeService;
|
||||
import cn.lili.mybatis.util.PageUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
@@ -116,4 +118,15 @@ public class RechargeServiceImpl extends ServiceImpl<RechargeMapper, Recharge> i
|
||||
this.updateById(recharge);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getRecharge(Date[] dates, PaymentMethodEnum paymentMethodEnum) {
|
||||
LambdaQueryWrapper<Recharge> queryWrapper = new LambdaQueryWrapper<Recharge>();
|
||||
queryWrapper.eq(Recharge::getPayStatus, PayStatusEnum.PAID.name());
|
||||
queryWrapper.between(Recharge::getPayTime, dates[0], dates[1]);
|
||||
if(paymentMethodEnum!=null){
|
||||
queryWrapper.eq(Recharge::getRechargeWay,paymentMethodEnum.name());
|
||||
}
|
||||
return this.baseMapper.getRecharge(queryWrapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cn.lili.controller.statistics;
|
||||
|
||||
import cn.lili.common.enums.ResultUtil;
|
||||
import cn.lili.common.vo.ResultMessage;
|
||||
import cn.lili.modules.statistics.entity.dto.StatisticsQueryParam;
|
||||
import cn.lili.modules.statistics.entity.vo.BusinessCompositionDataVO;
|
||||
import cn.lili.modules.statistics.entity.vo.OverViewDataVO;
|
||||
import cn.lili.modules.statistics.entity.vo.SourceDataVO;
|
||||
import cn.lili.modules.statistics.service.OverViewStatisticsService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 管理端,营业概览接口
|
||||
*
|
||||
* @author Bulbasaur
|
||||
* @since 2025/08/25 7:31 下午
|
||||
*/
|
||||
@Slf4j
|
||||
@Api(tags = "管理端,营业概览接口")
|
||||
@RestController
|
||||
@RequestMapping("/manager/statistics/overview")
|
||||
public class OverViewStatisticsManagerController {
|
||||
|
||||
@Autowired
|
||||
private OverViewStatisticsService overViewStatisticsService;
|
||||
|
||||
@ApiOperation(value = "获取营业概览统计")
|
||||
@GetMapping
|
||||
public ResultMessage<OverViewDataVO> overViewDataVO(StatisticsQueryParam statisticsQueryParam) {
|
||||
try {
|
||||
return ResultUtil.data(overViewStatisticsService.getOverViewDataVO(statisticsQueryParam));
|
||||
} catch (Exception e) {
|
||||
log.error("获取营业概览统计错误",e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ApiOperation(value = "收款构成列表")
|
||||
@GetMapping("/source")
|
||||
public ResultMessage<List<SourceDataVO>> sourceDataVOList(StatisticsQueryParam statisticsQueryParam) {
|
||||
try {
|
||||
return ResultUtil.data(overViewStatisticsService.getSourceDataVOList(statisticsQueryParam));
|
||||
} catch (Exception e) {
|
||||
log.error("收款构成列表错误",e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ApiOperation(value = "营业构成信息")
|
||||
@GetMapping("/businessComposition")
|
||||
public ResultMessage<BusinessCompositionDataVO> businessCompositionDataVO(StatisticsQueryParam statisticsQueryParam) {
|
||||
try {
|
||||
return ResultUtil.data(overViewStatisticsService.businessCompositionDataVO(statisticsQueryParam));
|
||||
} catch (Exception e) {
|
||||
log.error("营业构成信息",e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user