|
|
|
@ -0,0 +1,192 @@
|
|
|
|
|
package com.baiye.modules.settlement.service.impl;
|
|
|
|
|
|
|
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
|
|
import cn.hutool.core.date.DateUtil;
|
|
|
|
|
import cn.hutool.core.util.NumberUtil;
|
|
|
|
|
import com.baiye.constant.DefaultNumberConstants;
|
|
|
|
|
import com.baiye.modules.security.service.OnlineUserService;
|
|
|
|
|
import com.baiye.modules.settlement.dao.CallCostRepository;
|
|
|
|
|
import com.baiye.modules.settlement.entity.CallSettlement;
|
|
|
|
|
import com.baiye.modules.settlement.service.CallCostService;
|
|
|
|
|
|
|
|
|
|
import com.baiye.modules.system.domain.MessageNotification;
|
|
|
|
|
import com.baiye.modules.system.domain.PayTemplate;
|
|
|
|
|
import com.baiye.modules.system.domain.PayTemplateUser;
|
|
|
|
|
import com.baiye.modules.system.domain.User;
|
|
|
|
|
import com.baiye.modules.system.repository.MessageNotificationRepository;
|
|
|
|
|
import com.baiye.modules.system.repository.PayTemplateRepository;
|
|
|
|
|
import com.baiye.modules.system.repository.PayTemplateUserRepository;
|
|
|
|
|
import com.baiye.modules.system.repository.UserRepository;
|
|
|
|
|
import com.baiye.modules.system.service.CompanyService;
|
|
|
|
|
import com.baiye.modules.system.service.UserMessageService;
|
|
|
|
|
import com.baiye.modules.system.service.dto.CompanyDto;
|
|
|
|
|
import com.baiye.modules.telemarkting.dao.AllCallInfoRepository;
|
|
|
|
|
import com.baiye.modules.telemarkting.entity.AllCallInfo;
|
|
|
|
|
import com.baiye.util.DateTimeUtil;
|
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
import org.springframework.scheduling.annotation.Async;
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @author wujingtao
|
|
|
|
|
* @date 2022/06/06
|
|
|
|
|
*/
|
|
|
|
|
@Slf4j
|
|
|
|
|
@Service
|
|
|
|
|
@RequiredArgsConstructor
|
|
|
|
|
public class CallCostServiceImpl implements CallCostService {
|
|
|
|
|
|
|
|
|
|
private final PayTemplateUserRepository payTemplateUserRepository;
|
|
|
|
|
|
|
|
|
|
private final PayTemplateRepository payTemplateRepository;
|
|
|
|
|
private final AllCallInfoRepository allCallInfoRepository;
|
|
|
|
|
private final CallCostRepository callCostRepository;
|
|
|
|
|
private final CompanyService companyService;
|
|
|
|
|
private final UserRepository userRepository;
|
|
|
|
|
private final MessageNotificationRepository messageNotificationRepository;
|
|
|
|
|
private final UserMessageService userMessageService;
|
|
|
|
|
private final OnlineUserService onlineUserService;
|
|
|
|
|
|
|
|
|
|
private final double price = 0.18;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 计算当天的通话时长和费用
|
|
|
|
|
* 1.先统计当天操作过的线索
|
|
|
|
|
* 2.按人员(账号)分组后 统计具体的通话时长
|
|
|
|
|
* 3.超出套餐时长部分 做扣减和欲减
|
|
|
|
|
*/
|
|
|
|
|
@Async
|
|
|
|
|
@Override
|
|
|
|
|
public void callCost() throws Exception {
|
|
|
|
|
//查看这些人员 在套餐时间内 的总时长是否超出 注意套餐 是否已经刷新,重新计算
|
|
|
|
|
//1.查看当前日期是否在套餐时间范围,
|
|
|
|
|
//2.查看前一天扣减表。有数据说明已经超出,做扣减,入库--
|
|
|
|
|
|
|
|
|
|
List<PayTemplateUser> byDay = payTemplateUserRepository.findByDay(DateUtil.today());
|
|
|
|
|
|
|
|
|
|
if (byDay.size() <= 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (PayTemplateUser info : byDay) {
|
|
|
|
|
long userId = info.getUserId();
|
|
|
|
|
Long companyId = userRepository.findUserById(userId).getCompanyId();
|
|
|
|
|
|
|
|
|
|
//查询套餐的时长
|
|
|
|
|
PayTemplate payTemplate = selectCombo(info.getPayTemplateId());
|
|
|
|
|
int callDuration = payTemplate.getCallDuration();
|
|
|
|
|
//查询套餐时间范围内 通话总时长
|
|
|
|
|
List<AllCallInfo> list = allCallInfoRepository.queryAllByTimeAndMemberId(DateUtil.formatDateTime(info.getBeginTime()), DateUtil.formatDateTime(info.getEndTime()), userId);
|
|
|
|
|
if (CollUtil.isEmpty(byDay)) {
|
|
|
|
|
log.info(" 用户 {} ,没有通话记录", userId);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
int duration = list.stream().mapToInt(AllCallInfo::getDuration).sum();
|
|
|
|
|
if (duration > callDuration) {
|
|
|
|
|
//账户余额
|
|
|
|
|
CompanyDto companyById = companyService.findCompanyById(companyId);
|
|
|
|
|
deduction(info, list, companyId, companyById);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 扣减操作
|
|
|
|
|
*
|
|
|
|
|
* @param info
|
|
|
|
|
* @param list
|
|
|
|
|
* @param companyId
|
|
|
|
|
*/
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public void deduction(PayTemplateUser info, List<AllCallInfo> list, Long companyId, CompanyDto companyById) throws Exception {
|
|
|
|
|
long userId = info.getUserId();
|
|
|
|
|
Double userBalance = companyById.getUserBalance();
|
|
|
|
|
//查看时间内 是否有过扣减
|
|
|
|
|
List<CallSettlement> callSettlements = callCostRepository.queryAllByTimeAndMemberId(DateUtil.formatDateTime(info.getBeginTime()), DateUtil.formatDateTime(info.getEndTime()), userId);
|
|
|
|
|
if (callSettlements.size() > 0) {
|
|
|
|
|
//按日期倒序
|
|
|
|
|
List<CallSettlement> callSettlementSort = callSettlements.stream().sorted(Comparator.comparing(CallSettlement::getCreateTime).reversed()).collect(Collectors.toList());
|
|
|
|
|
//最近的一次预扣减金额
|
|
|
|
|
double estimateAmount = callSettlementSort.get(0).getEstimateAmount();
|
|
|
|
|
//今天的通话时长
|
|
|
|
|
List<AllCallInfo> allCallInfos = list.stream().filter(c -> DateTimeUtil.betweenByMonth(c.getCreateTime(), DateUtil.date())).collect(Collectors.toList());
|
|
|
|
|
if (allCallInfos.size() != 1) {
|
|
|
|
|
log.info("当日 {} ,用户 {} ,没有通话记录", DateUtil.today(), userId);
|
|
|
|
|
} else {
|
|
|
|
|
//今日通话时长
|
|
|
|
|
int duration1 = allCallInfos.get(0).getDuration();
|
|
|
|
|
double deductAmount = NumberUtil.mul(duration1, price);
|
|
|
|
|
//今日计算预扣
|
|
|
|
|
double estimateAmountToDay = getEstimateAmount(list);
|
|
|
|
|
|
|
|
|
|
//余额足够
|
|
|
|
|
if (estimateAmount + userBalance > deductAmount + estimateAmountToDay) {
|
|
|
|
|
companyService.updateUserBalanceByCompanyId(deductAmount + estimateAmountToDay - estimateAmount, companyId);
|
|
|
|
|
} else {
|
|
|
|
|
//不够的情况 不加预扣
|
|
|
|
|
if (estimateAmount + userBalance > deductAmount) {
|
|
|
|
|
companyService.updateUserBalanceByCompanyId(deductAmount - estimateAmount, companyId);
|
|
|
|
|
// TODO: 2022/6/8 0008 发送通知
|
|
|
|
|
MessageNotification messageNotification = new MessageNotification();
|
|
|
|
|
messageNotification.setMessageTitle("充值提醒");
|
|
|
|
|
messageNotification.setMessageType(2);
|
|
|
|
|
messageNotification.setUserId(companyById.getUserId());
|
|
|
|
|
messageNotification.setMessageContext("您的账号余额已不足,及时充值");
|
|
|
|
|
MessageNotification notification = messageNotificationRepository.save(messageNotification);
|
|
|
|
|
userMessageService.createUserMessage(Collections.singletonList(companyById.getUserId()), notification, DefaultNumberConstants.TWO_NUMBER);
|
|
|
|
|
} else {
|
|
|
|
|
//不足以扣款
|
|
|
|
|
companyService.updateUserBalanceByCompanyId(deductAmount - estimateAmount, companyId);
|
|
|
|
|
// TODO: 2022/6/8 0008 下线 修改用户状态
|
|
|
|
|
User userById = userRepository.findUserById(userId);
|
|
|
|
|
userRepository.updateStatusById(Boolean.FALSE, userId);
|
|
|
|
|
onlineUserService.kickOutForUsername(userById.getUsername());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 查询用户套餐的信息
|
|
|
|
|
*
|
|
|
|
|
* @param payTemplateId
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
private PayTemplate selectCombo(Long payTemplateId) {
|
|
|
|
|
return payTemplateRepository.findById(payTemplateId).orElseGet(PayTemplate::new);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 今日计算预扣
|
|
|
|
|
*
|
|
|
|
|
* @param list
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
private Double getEstimateAmount(List<AllCallInfo> list) {
|
|
|
|
|
List<AllCallInfo> sortList = list.stream().sorted(Comparator.comparing(AllCallInfo::getCreateTime).reversed()).collect(Collectors.toList());
|
|
|
|
|
//取最近的7天数据 去最大和最小值求平均数
|
|
|
|
|
List<AllCallInfo> list1 = sortList.subList(0, 7);
|
|
|
|
|
List<Integer> collect = list1.stream().map(AllCallInfo::getDuration).sorted().collect(Collectors.toList());
|
|
|
|
|
|
|
|
|
|
int sumScore = 0;
|
|
|
|
|
int sumTimes = 0;
|
|
|
|
|
for (int i = 0; i < collect.size(); i++) {
|
|
|
|
|
if (collect.get(i).equals(collect.get(0)) || collect.get(i).equals(collect.get(collect.size() - 1))) {
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
sumScore += collect.get(i);
|
|
|
|
|
sumTimes++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NumberUtil.mul((double) (sumScore / sumTimes), price);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|