Explorar el Código

saas费用计算

yh hace 2 semanas
padre
commit
809b172f3f

+ 199 - 0
fs-admin/src/main/java/com/fs/tenant/task/TenantBillTask.java

@@ -0,0 +1,199 @@
+package com.fs.tenant.task;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fs.billing.domain.BillingDetail;
+import com.fs.billing.domain.FeePlanItem;
+import com.fs.billing.domain.TenantWallet;
+import com.fs.billing.domain.UsageEvent;
+import com.fs.billing.mapper.BillingDetailMapper;
+import com.fs.billing.mapper.TenantWalletMapper;
+import com.fs.billing.mapper.UsageEventMapper;
+import com.fs.common.enums.DataSourceType;
+import com.fs.common.utils.DateUtils;
+import com.fs.framework.datasource.DynamicDataSourceContextHolder;
+import com.fs.framework.datasource.TenantDataSourceManager;
+import com.fs.tenant.domain.TenantInfo;
+import com.fs.tenant.enums.FeeItemEnum;
+import com.fs.tenant.service.TenantInfoService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+@Slf4j
+@Component("tenantBillTask")
+public class TenantBillTask {
+
+    @Autowired
+    private TenantInfoService tenantInfoService;
+
+    @Autowired
+    private TenantDataSourceManager tenantDataSourceManager;
+
+    @Autowired
+    private TenantWalletMapper tenantWalletMapper;
+
+    @Autowired
+    private UsageEventMapper usageEventMapper;
+    @Autowired
+    private BillingDetailMapper billingDetailMapper;
+
+    /**
+     * 租户费用结算 (每日01:00执行)
+     */
+    public void tenantFeeSettlementTask() {
+        List<TenantInfo> tenants = getValidTenants();
+
+        for (TenantInfo tenant : tenants) {
+            try {
+                processTenant(tenant);
+            } catch (Exception e) {
+                log.error("租户结算失败 tenantId={}", tenant.getId(), e);
+            } finally {
+                tenantDataSourceManager.clear();
+            }
+        }
+    }
+
+    /**
+     * 查询有效租户
+     */
+    private List<TenantInfo> getValidTenants() {
+        LambdaQueryWrapper<TenantInfo> query = new LambdaQueryWrapper<>();
+        query.eq(TenantInfo::getStatus, 1)
+                .gt(TenantInfo::getExpireTime, DateUtils.getNowDate());
+
+        return tenantInfoService.list(query);
+    }
+
+    /**
+     * 处理单个租户
+     */
+    private void processTenant(TenantInfo tenant) {
+        if (StringUtils.isBlank(tenant.getFeePlanCode())) {
+            return;
+        }
+
+        List<FeePlanItem> items = tenantInfoService.selectFeeItem(tenant.getFeePlanCode());
+        if (items.isEmpty()) {
+            return;
+        }
+
+        DateTime start = DateUtil.beginOfDay(DateUtil.yesterday());
+        DateTime end = DateUtil.endOfDay(DateUtil.yesterday());
+
+        BigDecimal aiCallFee = getAiCallFee(items);
+        BigDecimal totalFee = BigDecimal.ZERO;
+
+        for (FeePlanItem item : items) {
+            // 切租户库
+            tenantDataSourceManager.switchTenant(tenant);
+            BigDecimal fee = handleFeeItem(item, start, end, aiCallFee,tenant);
+            totalFee = totalFee.add(fee);
+        }
+
+        // 回主库
+        DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
+        if (totalFee.compareTo(BigDecimal.ZERO) <= 0) {
+            return;
+        }
+        // 费用扣减
+        tenantWalletMapper.deduct(tenant.getId(), totalFee);
+        // 查询租户钱包
+        TenantWallet tenantWallet = tenantWalletMapper.selectByTenantId(tenant.getId());
+        log.info("租户={} 总费用={} 余额={}", tenant.getTenantName(), totalFee, tenantWallet.getBalanceAmount());
+    }
+
+    /**
+     * 费用项处理分发
+     */
+    private BigDecimal handleFeeItem(FeePlanItem item, DateTime start, DateTime end, BigDecimal aiCallFee,TenantInfo tenant) {
+        String code = item.getItemCode();
+
+        switch (FeeItemEnum.valueOf(code)) {
+            case FLOW_POSTPAID:
+                Map<String, Object> traffic = tenantInfoService.getYesterDayTraffic(start, end, item, tenant);
+                return processResult(traffic, item, tenant);
+
+            case CALL_OUT:
+                Map<String, Object> callOut = tenantInfoService.getYesterCallOut(start, end, item, aiCallFee, tenant);
+                return processResult(callOut, item, tenant);
+
+            case ADD_WECHAT:
+                Map<String, Object> addWechat = tenantInfoService.getYesterAddWechat(start, end, item, tenant);
+                return processResult(addWechat, item, tenant);
+
+            case AI_REPLY_TOKEN:
+                Map<String, Object> aiReply = tenantInfoService.getYesterAiReplyToken(start, end, item, tenant);
+                return processResult(aiReply, item, tenant);
+
+            case SOP_TOKEN:
+                Map<String, Object> sopToken = tenantInfoService.getYesterSopToken(start, end, item, tenant);
+                return processResult(sopToken, item, tenant);
+
+            default:
+                return BigDecimal.ZERO;
+        }
+    }
+
+    private BigDecimal processResult(Map<String,Object> map,FeePlanItem item,TenantInfo tenant){
+        BigDecimal fee = new BigDecimal(map.get("price").toString());
+        String usage = map.get("usage").toString();
+        boolean isLeZero = new BigDecimal(usage).compareTo(BigDecimal.ZERO) <= 0;
+        // 没有产生费用 直接返回
+        if (fee.compareTo(BigDecimal.ZERO) <= 0 && isLeZero) {
+            return fee;
+        }
+        saveUsageEventAndBill(usage, item, tenant,fee);
+        return fee;
+    }
+
+    private void saveUsageEventAndBill(String value,FeePlanItem item,TenantInfo tenant,BigDecimal fee){
+        // 切换到主库
+        DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
+        log.info("【当前已切换到数据源】:{}", DynamicDataSourceContextHolder.getDataSourceType());
+        String eventID = "EVT_" + DateUtil.current();
+        UsageEvent event = new UsageEvent();
+        event.setTenantId(tenant.getId());
+        event.setEventId(eventID);
+        event.setEventType(item.getItemCode());
+        event.setUsageValue(new BigDecimal(value));
+        event.setUsageUnit(item.getUnit());
+        event.setCreateTime(DateUtils.getNowDate());
+        event.setOccurredAt(DateUtils.getNowDate());
+        usageEventMapper.insert(event);
+
+        BillingDetail billingDetail = new BillingDetail();
+        billingDetail.setTenantId(tenant.getId());
+        billingDetail.setEventId(eventID);
+        billingDetail.setEventType(item.getItemCode());
+        billingDetail.setPlanCode(item.getPlanCode());
+        billingDetail.setPlanVersion(item.getVersion());
+        billingDetail.setUnitPrice(item.getUnitPrice());
+        billingDetail.setUsageValue(new BigDecimal(value));
+        billingDetail.setChargeValue(new BigDecimal(value));
+        billingDetail.setAmount(fee);
+        billingDetail.setBillingMode(tenant.getBillingMode());
+        billingDetail.setCreateTime(DateUtils.getNowDate());
+        billingDetail.setOccurredAt(DateUtils.getNowDate());
+        billingDetailMapper.insert(billingDetail);
+    }
+
+    /**
+     * 获取 AI 外呼费用
+     */
+    private BigDecimal getAiCallFee(List<FeePlanItem> items) {
+        return items.stream()
+                .filter(e -> Objects.equals(e.getItemCode(), FeeItemEnum.AI_CALL.name()))
+                .map(FeePlanItem::getUnitPrice)
+                .findFirst()
+                .orElse(BigDecimal.ZERO);
+    }
+}

+ 5 - 0
fs-service/src/main/java/com/fs/tenant/domain/TenantInfo.java

@@ -96,4 +96,9 @@ public class TenantInfo {
     private Integer companyNum;
 
     private Integer accountNum;
+
+    private String feePlanCode;
+
+
+    private String billingMode;
 }

+ 9 - 0
fs-service/src/main/java/com/fs/tenant/dto/SopTokenDto.java

@@ -0,0 +1,9 @@
+package com.fs.tenant.dto;
+
+import lombok.Data;
+
+@Data
+public class SopTokenDto {
+    private int type;
+    private int count;
+}

+ 14 - 0
fs-service/src/main/java/com/fs/tenant/dto/TenantBillDto.java

@@ -0,0 +1,14 @@
+package com.fs.tenant.dto;
+
+import com.fs.billing.domain.FeePlanItem;
+import com.fs.tenant.domain.TenantInfo;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class TenantBillDto {
+    private TenantInfo tenantInfo;
+
+    private List<FeePlanItem> feePlanItems;
+}

+ 29 - 0
fs-service/src/main/java/com/fs/tenant/enums/FeeItemEnum.java

@@ -0,0 +1,29 @@
+package com.fs.tenant.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum FeeItemEnum {
+    // 流量类
+    FLOW_POSTPAID("流量后付费"),
+
+    // 通话类
+    CALL_OUT("外呼通话"),
+    CALL_IN("呼入通话"),
+    AI_CALL("AI外呼附加费"),
+
+    // Token类
+    SOP_TOKEN("SOP Token"),
+    AI_REPLY_TOKEN("AI回复Token"),
+
+    // 开户类
+    OPEN_ACCOUNT_NON_AI("开户费-非AI"),
+    OPEN_ACCOUNT_AI("开户费-AI"),
+
+    // 其他
+    ADD_WECHAT("加微数量");
+
+    private final String desc;
+}

+ 17 - 0
fs-service/src/main/java/com/fs/tenant/mapper/TenantInfoMapper.java

@@ -1,10 +1,15 @@
 package com.fs.tenant.mapper;
 
+import cn.hutool.core.date.DateTime;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.billing.domain.FeePlanItem;
 import com.fs.common.core.domain.entity.SysMenu;
 
 import com.fs.common.core.domain.entity.TenantCompanyMenu;
+import com.fs.company.domain.CompanyVoiceRoboticCallLogCallphone;
+import com.fs.qw.domain.QwRestrictionPushRecord;
 import com.fs.tenant.domain.TenantInfo;
+import com.fs.tenant.dto.SopTokenDto;
 import com.fs.tenant.vo.TenantInfoShowVo;
 import org.apache.ibatis.annotations.Param;
 
@@ -126,6 +131,18 @@ public interface TenantInfoMapper extends BaseMapper<TenantInfo> {
     int addComMenu(List<TenantCompanyMenu> addCompanyMenu);
 
     TenantInfo getTenByCode(String code);
+
+    List<FeePlanItem> selectFeeItem(String feePlanCode);
+
+    String getYesterDayTraffic(@Param("yesterDayBegin") DateTime yesterDayBegin,@Param("yesterdayEnd") DateTime yesterdayEnd);
+
+    List<CompanyVoiceRoboticCallLogCallphone> getYesterCallOut(@Param("yesterDayBegin") DateTime yesterDayBegin,@Param("yesterdayEnd") DateTime yesterdayEnd);
+
+    int getYesterAddWechat(@Param("yesterDayBegin") DateTime yesterDayBegin,@Param("yesterdayEnd") DateTime yesterdayEnd);
+
+    long getYesterAiReplyToken(@Param("yesterDayBegin") DateTime yesterDayBegin,@Param("yesterdayEnd") DateTime yesterdayEnd);
+
+    List<SopTokenDto> getYesterSopToken(@Param("yesterDayBegin") DateTime yesterDayBegin, @Param("yesterdayEnd") DateTime yesterdayEnd);
 }
 
 

+ 16 - 0
fs-service/src/main/java/com/fs/tenant/service/TenantInfoService.java

@@ -1,6 +1,8 @@
 package com.fs.tenant.service;
 
+import cn.hutool.core.date.DateTime;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.billing.domain.FeePlanItem;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.entity.SysMenu;
 ;
@@ -8,7 +10,9 @@ import com.fs.common.core.domain.entity.TenantCompanyMenu;
 import com.fs.tenant.domain.TenantInfo;
 import com.fs.tenant.vo.TenantInfoShowVo;
 
+import java.math.BigDecimal;
 import java.util.List;
+import java.util.Map;
 
 /**
 * @author Administrator
@@ -101,4 +105,16 @@ public interface TenantInfoService extends IService<TenantInfo> {
     boolean hasChildByComMenuId(Long menuId);
 
     int deleteComMenuById(Long menuId);
+
+    List<FeePlanItem> selectFeeItem(String feePlanCode);
+
+    Map<String, Object>  getYesterDayTraffic(DateTime yesterDayBegin, DateTime yesterdayEnd, FeePlanItem item,TenantInfo tenant);
+
+    Map<String, Object> getYesterCallOut(DateTime yesterDayBegin, DateTime yesterdayEnd, FeePlanItem item,BigDecimal aiCallFee,TenantInfo tenant);
+
+    Map<String, Object> getYesterAddWechat(DateTime yesterDayBegin, DateTime yesterdayEnd, FeePlanItem item,TenantInfo tenant);
+
+    Map<String, Object> getYesterAiReplyToken(DateTime yesterDayBegin, DateTime yesterdayEnd, FeePlanItem item, TenantInfo tenant);
+
+    Map<String, Object> getYesterSopToken(DateTime yesterDayBegin, DateTime yesterdayEnd, FeePlanItem item,TenantInfo tenant);
 }

+ 143 - 0
fs-service/src/main/java/com/fs/tenant/service/impl/TenantInfoServiceImpl.java

@@ -1,18 +1,30 @@
 package com.fs.tenant.service.impl;
 
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.billing.domain.BillingDetail;
+import com.fs.billing.domain.FeePlanItem;
+import com.fs.billing.domain.UsageEvent;
+import com.fs.billing.mapper.BillingDetailMapper;
+import com.fs.billing.mapper.UsageEventMapper;
 import com.fs.common.constant.UserConstants;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.TreeSelect;
 import com.fs.common.core.domain.entity.SysMenu;
 import com.fs.common.core.domain.entity.TenantCompanyMenu;
+import com.fs.common.enums.DataSourceType;
 import com.fs.common.exception.CustomException;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 
+import com.fs.company.domain.CompanyVoiceRoboticCallLogCallphone;
+import com.fs.qw.domain.QwRestrictionPushRecord;
 import com.fs.system.service.ISysMenuService;
 import com.fs.tenant.domain.TenantInfo;
+import com.fs.tenant.dto.SopTokenDto;
 import com.fs.tenant.mapper.TenantInfoMapper;
 import com.fs.tenant.service.TenantAsyncService;
 import com.fs.tenant.service.TenantInfoService;
@@ -23,8 +35,10 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 
+import java.math.BigDecimal;
 import java.sql.Connection;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -41,6 +55,10 @@ public class TenantInfoServiceImpl extends ServiceImpl<TenantInfoMapper, TenantI
     private TenantAsyncService tenantAsyncService;
     @Autowired
     private ISysMenuService menuService;
+    @Autowired
+    private UsageEventMapper usageEventMapper;
+    @Autowired
+    private BillingDetailMapper billingDetailMapper;
 
     /**
      * 查询租户基础信息
@@ -389,6 +407,131 @@ public class TenantInfoServiceImpl extends ServiceImpl<TenantInfoMapper, TenantI
     public int deleteComMenuById(Long menuId) {
         return baseMapper.deleteComMenuById(menuId);
     }
+
+    @Override
+    public List<FeePlanItem> selectFeeItem(String feePlanCode) {
+        return baseMapper.selectFeeItem(feePlanCode);
+    }
+
+    @Override
+    public Map<String, Object> getYesterDayTraffic(DateTime yesterDayBegin, DateTime yesterdayEnd, FeePlanItem item, TenantInfo tenant) {
+        // 查询流量
+        String traffic = baseMapper.getYesterDayTraffic(yesterDayBegin, yesterdayEnd);
+
+        BigDecimal trafficB = traffic == null ? BigDecimal.ZERO : new BigDecimal(traffic);
+
+        // 根据计费方案单位,转换成对应单位
+        String unit = item.getUnit();
+        BigDecimal usage = BigDecimal.ZERO;
+
+        switch (unit) {
+            case "MB":
+                usage = trafficB.divide(new BigDecimal("1024"), 6, BigDecimal.ROUND_HALF_UP)
+                        .divide(new BigDecimal("1024"), 6, BigDecimal.ROUND_HALF_UP);
+                break;
+            case "GB":
+                usage = trafficB.divide(new BigDecimal("1024"), 6, BigDecimal.ROUND_HALF_UP)
+                        .divide(new BigDecimal("1024"), 6, BigDecimal.ROUND_HALF_UP)
+                        .divide(new BigDecimal("1024"), 6, BigDecimal.ROUND_HALF_UP);
+                break;
+            default:
+                usage = trafficB.divide(new BigDecimal("1024"), 6, BigDecimal.ROUND_HALF_UP);
+                break;
+        }
+
+        // 计算费用
+        BigDecimal totalPrice = usage.multiply(item.getUnitPrice()).setScale(6, BigDecimal.ROUND_HALF_UP);
+
+        // 返回结果
+        Map<String, Object> map = new HashMap<>();
+        map.put("usage", usage);
+        map.put("price", totalPrice);
+        return map;
+    }
+
+    @Override
+    public Map<String, Object> getYesterCallOut(DateTime yesterDayBegin, DateTime yesterdayEnd, FeePlanItem item,BigDecimal aiCallFee,TenantInfo tenant) {
+        List<CompanyVoiceRoboticCallLogCallphone> list = baseMapper.getYesterCallOut(yesterDayBegin, yesterdayEnd);
+
+        // 初始金额 0
+        BigDecimal totalPrice = BigDecimal.ZERO;
+        long minutes = 0;
+        for (CompanyVoiceRoboticCallLogCallphone c : list) {
+            // 通话时长(不足1分钟按1分钟算)
+            Long callTime = c.getCallTime();
+            if (callTime == null || callTime <= 0) {
+                continue; // 空或0秒跳过
+            }
+            minutes = (callTime + 60 - 1) / 60;
+
+            // 计算单价
+            BigDecimal itemPrice = 2 == c.getCallType() ?
+                    item.getUnitPrice().add(aiCallFee).multiply(new BigDecimal(minutes))
+                    : item.getUnitPrice().multiply(new BigDecimal(minutes));
+
+            totalPrice = totalPrice.add(itemPrice);
+        }
+
+        BigDecimal totalFee = totalPrice.setScale(6, BigDecimal.ROUND_HALF_UP);
+        Map<String, Object> map = new HashMap<>();
+        map.put("usage", minutes);
+        map.put("price", totalFee);
+        return map;
+    }
+
+    @Override
+    public Map<String, Object> getYesterAddWechat(DateTime yesterDayBegin, DateTime yesterdayEnd, FeePlanItem item,TenantInfo tenant) {
+        int count = 0;
+        count = baseMapper.getYesterAddWechat(yesterDayBegin, yesterdayEnd);
+        BigDecimal totalFee = BigDecimal.ZERO;
+        if (count > 0) {
+            totalFee = item.getUnitPrice().multiply(new BigDecimal(count)).setScale(6, BigDecimal.ROUND_HALF_UP);
+        }
+
+        Map<String, Object> map = new HashMap<>();
+        map.put("usage", count);
+        map.put("price", totalFee);
+        return map;
+    }
+
+    @Override
+    public Map<String, Object> getYesterAiReplyToken(DateTime yesterDayBegin, DateTime yesterdayEnd, FeePlanItem item,TenantInfo tenant) {
+        Map<String, Object> map = new HashMap<>();
+        long token = 0L;
+        token = baseMapper.getYesterAiReplyToken(yesterDayBegin, yesterdayEnd);
+        if (BeanUtil.isEmpty(token)) {
+            map.put("usage", token);
+            map.put("price", BigDecimal.ZERO);
+            return map;
+        }
+
+        BigDecimal tokenCount = new BigDecimal(token).divide(new BigDecimal(item.getTokenUnit()), 6, BigDecimal.ROUND_HALF_UP);
+        BigDecimal totalFee = item.getUnitPrice().multiply(tokenCount).setScale(6, BigDecimal.ROUND_HALF_UP);
+        map.put("usage", token);
+        map.put("price", totalFee);
+        return map;
+    }
+
+    @Override
+    public Map<String, Object> getYesterSopToken(DateTime yesterDayBegin, DateTime yesterdayEnd, FeePlanItem item,TenantInfo tenant) {
+        List<SopTokenDto> list = baseMapper.getYesterSopToken(yesterDayBegin, yesterdayEnd);
+        BigDecimal totalToken = BigDecimal.ZERO;
+        for (SopTokenDto sopToken : list) {
+            int type = sopToken.getType();
+            if (type == 7) {
+                totalToken = totalToken.add(new BigDecimal(sopToken.getCount() * 450));
+            } else {
+                totalToken = totalToken.add(new BigDecimal(sopToken.getCount() * 150));
+            }
+        }
+
+        BigDecimal tokenCount = totalToken.divide(new BigDecimal(item.getTokenUnit()), 6, BigDecimal.ROUND_HALF_UP);
+        BigDecimal totalFee = item.getUnitPrice().multiply(tokenCount).setScale(6, BigDecimal.ROUND_HALF_UP);
+        Map<String, Object> map = new HashMap<>();
+        map.put("usage", totalToken);
+        map.put("price", totalFee);
+        return map;
+    }
 }
 
 

+ 53 - 0
fs-service/src/main/resources/mapper/tenant/TenantInfoMapper.xml

@@ -247,6 +247,59 @@
         select * from tenant_info where tenant_code = #{tenantCode}
     </select>
 
+    <select id="selectFeeItem" resultType="com.fs.billing.domain.FeePlanItem">
+        SELECT * FROM `fee_plan_item` WHERE plan_code = #{plan_code} and enabled = 1
+    </select>
+
+    <select id="getYesterDayTraffic" resultType="java.lang.String">
+        SELECT SUM(internet_traffic)
+        FROM `fs_course_traffic_log`
+        WHERE create_time &gt;= #{yesterDayBegin}
+          AND create_time &lt; #{yesterdayEnd}
+    </select>
+
+    <select id="getYesterCallOut" resultType="com.fs.company.domain.CompanyVoiceRoboticCallLogCallphone">
+        SELECT
+            *
+        FROM
+            `company_voice_robotic_call_log_callphone`
+        WHERE
+            STATUS = 2
+          AND run_time &gt;= #{yesterDayBegin}
+          AND run_time &lt; #{yesterdayEnd}
+    </select>
+
+    <select id="getYesterAddWechat" resultType="java.lang.Integer">
+        SELECT
+            count(id)
+        FROM
+            `company_wx_client`
+        WHERE
+            is_add = 1
+          AND success_add_time &gt;= #{yesterDayBegin}
+          AND success_add_time &lt; #{yesterdayEnd}
+    </select>
+
+    <select id="getYesterAiReplyToken" resultType="java.lang.Long">
+        SELECT
+            IFNULL(SUM(token_count), 0)
+        FROM
+            `fastgpt_event_token_log`
+        WHERE
+            create_time &gt;= #{yesterDayBegin}
+          AND create_time &lt; #{yesterdayEnd}
+    </select>
+
+    <select id="getYesterSopToken" resultType="com.fs.tenant.dto.SopTokenDto">
+        SELECT
+            type,
+            count( id ) count
+        FROM `qw_restriction_push_record`
+        WHERE `status` = 1
+          AND create_time &gt;= #{yesterDayBegin}
+          AND create_time &lt; #{yesterdayEnd}
+    </select>
+
 
     <insert id="insertTenantInfo" parameterType="TenantInfo" useGeneratedKeys="true" keyProperty="id">
         insert into tenant_info