feat(crm): 集成回款功能

- 新增回款相关的 API 接口和实现类
- 在 AchievementService 和 CrmIndexService 中添加回款统计逻辑
- 修改 CrmCustomerApi,增加获取客户信息的接口- 更新 RpcConfiguration,添加 BpmOAReceiptApi 的配置
This commit is contained in:
furongxin 2024-12-20 15:35:23 +08:00
parent be9085e3ac
commit af22e311ec
8 changed files with 96 additions and 122 deletions

View File

@ -4,10 +4,13 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.hrm.api.crmcustomer.dto.CrmCustomerDTO;
import cn.iocoder.yudao.module.hrm.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Tag(name = "RPC 服务 - 流程实例")
@ -18,4 +21,9 @@ public interface CrmCustomerApi {
@PostMapping(PREFIX + "/update")
@Operation(summary = "更新客户信息")
CommonResult<Boolean> updateCustomerPurchaseTotal(@RequestBody CrmCustomerDTO updateReqVO);
@GetMapping(PREFIX + "/get")
@Operation(summary = "获得客户信息")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
CommonResult<CrmCustomerDTO> getCustomer(@RequestParam("id") Long id);
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.crm.api.crmcustomer;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CrmCustomerSaveReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
import cn.iocoder.yudao.module.crm.service.crmcustomer.CrmCustomerService;
import cn.iocoder.yudao.module.hrm.api.crmcustomer.CrmCustomerApi;
import cn.iocoder.yudao.module.hrm.api.crmcustomer.dto.CrmCustomerDTO;
@ -28,4 +29,10 @@ public class CrmCustomerApiImpl implements CrmCustomerApi {
customerService.updateCustomerPurchaseTotal(BeanUtils.toBean(updateReqVO, CrmCustomerSaveReqVO.class));
return success(true);
}
@Override
public CommonResult<CrmCustomerDTO> getCustomer(Long id) {
CrmCustomerDO customerDO = customerService.getCustomer(id);
return success(BeanUtils.toBean(customerDO, CrmCustomerDTO.class));
}
}

View File

@ -10,7 +10,6 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontractreceivables.CrmCont
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@ -46,9 +45,5 @@ public interface CrmContractReceivablesMapper extends BaseMapperX<CrmContractRec
.orderByDesc(CrmContractReceivablesDO::getId));
}
@Select("select any_value(t.id) as id,COUNT(t.id) AS count,SUM(t.money) AS money,t1.nickname AS nickname from crm_contract_receivables t " +
"LEFT JOIN system_users t1 ON (t1.id = t.order_admin_id) " +
"where t.deleted=0 GROUP BY t.order_admin_id ORDER BY any_value(money) DESC limit 10")
List<ContractVO> selectReceivablesTop();
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.crm.framework.rpc.config;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReceiptApi;
import cn.iocoder.yudao.module.product.api.storeproduct.StoreProductApi;
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.StoreProductAttrValueApi;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
@ -14,6 +15,6 @@ import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@EnableFeignClients(clients = { DeptApi.class, DictDataApi.class, AdminUserApi.class, StoreProductApi.class, StoreProductAttrValueApi.class, SmsSendApi.class, MailSendApi.class, NoticeApi.class,
BpmOAContractApi.class})
BpmOAContractApi.class, BpmOAReceiptApi.class})
public class RpcConfiguration {
}

View File

@ -12,13 +12,14 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReceiptApi;
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.BpmOAContractDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.BpmOAContractVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmachievement.vo.*;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmachievement.CrmAchievementDO;
import cn.iocoder.yudao.module.crm.dal.mysql.crmachievement.CrmAchievementMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontract.CrmContractMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontractreceivables.CrmContractReceivablesMapper;
import cn.iocoder.yudao.module.hrm.enums.FlowStepEnum;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
@ -54,16 +55,16 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
private CrmAchievementMapper achievementMapper;
@Resource
private DeptApi deptApi;
@Resource
private CrmContractMapper contractMapper;
@Resource
private CrmContractReceivablesMapper contractReceivablesMapper;
@Resource
private AdminUserApi adminUserApi;
@Resource
private BpmOAContractApi contractApi;
@Resource
private BpmOAReceiptApi receiptApi;
@Override
public void createAchievement(DeptAchieveSaveVO createReqVO) {
@ -331,10 +332,6 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
.setStarTime(starTime)
.setEndTime(endTime)).getCheckedData();
// List<CrmContractDO> crmContractDOS = contractMapper.selectList(new LambdaQueryWrapperX<CrmContractDO>()
// .in(CrmContractDO::getOwnerUserId, userIds)
// .eq(CrmContractDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
// .between(CrmContractDO::getOrderTime, starTime, endTime));
BigDecimal contractSuccessMoney = BigDecimal.ZERO;
if (CollectionUtil.isNotEmpty(contractDTOS)) {
// 累加合同金额
@ -343,18 +340,24 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
// 获取回款信息
List<BpmOAReceiptDTO> receiptDTOS = receiptApi.getReceiptList(new BpmOAReceiptVO()
.setUserId(userIds)
.setStarTime(starTime)
.setEndTime(endTime)).getCheckedData();
// List<CrmContractReceivablesDO> crmContractReceivablesDOS = contractReceivablesMapper
// .selectList(new LambdaQueryWrapper<CrmContractReceivablesDO>()
// .in(CrmContractReceivablesDO::getOwnerUserId, userIds)
// .eq(CrmContractReceivablesDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
// .between(CrmContractReceivablesDO::getReturnTime, starTime, endTime));
BigDecimal receivablesSuccessMoney = BigDecimal.ZERO;
// if (!crmContractReceivablesDOS.isEmpty()) {
// receivablesSuccessMoney = crmContractReceivablesDOS
// .stream()
// .map(CrmContractReceivablesDO::getMoney)
// .reduce(BigDecimal.ZERO, BigDecimal::add);
// }
if (CollectionUtil.isNotEmpty(receiptDTOS)) {
receivablesSuccessMoney = receiptDTOS
.stream()
.map(BpmOAReceiptDTO::getMoney)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
BigDecimal contractMoney = BigDecimal.ZERO;
BigDecimal receivablesMoney = BigDecimal.ZERO;

View File

@ -10,7 +10,9 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReceiptApi;
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.ContractStatisticsDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.*;
import cn.iocoder.yudao.module.crm.controller.admin.crmclues.vo.CrmCluesStatisticsRespVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmachievement.CrmAchievementDO;
@ -80,6 +82,9 @@ public class AchievementServiceImpl implements AchievementService {
@Resource
private CrmCluesService cluesService;
@Resource
private BpmOAReceiptApi receiptApi;
@Override
public PageResult<UserAchieveVO> getAchievementPage(AchievementPageReqVO pageReqVO) {
@ -102,6 +107,10 @@ public class AchievementServiceImpl implements AchievementService {
List<ContractStatisticsDTO> contractStatisticsDTOS = contractApi.getContractStatistics(userIds, pageReqVO.getCreateTime()).getCheckedData();
Map<Long, ContractStatisticsDTO> contractMap = convertMap(contractStatisticsDTOS, ContractStatisticsDTO::getUserId);
// 获取所有用户的回款统计列表
List<ReceiptStatisticsDTO> receiptStatisticsDTOS = receiptApi.getContractStatistics(userIds, pageReqVO.getCreateTime()).getCheckedData();
Map<Long, ReceiptStatisticsDTO> receiptMap = convertMap(receiptStatisticsDTOS, ReceiptStatisticsDTO::getUserId);
// 获取所有用户的线索统计列表
List<CrmCluesStatisticsRespVO> cluesStatisticsRespVOS = cluesService.getCluesStatisticsByUserIds(userIds, pageReqVO.getCreateTime());
Map<Long, CrmCluesStatisticsRespVO> clusesMap = convertMap(cluesStatisticsRespVOS, CrmCluesStatisticsRespVO::getOwnerUserId);
@ -109,38 +118,22 @@ public class AchievementServiceImpl implements AchievementService {
pageResult1.getList().forEach(v -> {
String per = "0";
if (contractMap.get(v.getId()) == null) {
// 设置合同数量
v.setContractCount(0L);
v.setContractCount(contractMap.get(v.getId()) != null ? Long.valueOf(contractMap.get(v.getId()).getCount()) : 0L);
// 设置合同金额
v.setContractMoney(BigDecimal.ZERO);
v.setContractMoney(contractMap.get(v.getId()) != null ? contractMap.get(v.getId()).getMoney() : BigDecimal.ZERO);
// 设置回款金额
v.setReceivablesMoney(BigDecimal.ZERO);
v.setReceivablesMoney(receiptMap.get(v.getId()) != null ? receiptMap.get(v.getId()).getMoney() : BigDecimal.ZERO);
// 设置线索数量
v.setCluesCount(0L);
v.setCluesCount(clusesMap.get(v.getId()) != null ? Long.valueOf(clusesMap.get(v.getId()).getCount()) : 0L);
// 设置转客数量
v.setCluesToCustomerCount(0L);
v.setCluesToCustomerPer(per);
}else {
// 设置合同数量
v.setContractCount(Long.valueOf(contractMap.get(v.getId()).getCount()));
// 设置合同金额
v.setContractMoney(contractMap.get(v.getId()).getMoney());
// 设置回款金额
v.setReceivablesMoney(BigDecimal.ZERO);
// 设置线索数量
v.setCluesCount(Long.valueOf(clusesMap.get(v.getId()).getCount()));
// 设置转客数量
v.setCluesToCustomerCount(Long.valueOf(clusesMap.get(v.getId()).getSuccessCount()));
v.setCluesToCustomerCount(clusesMap.get(v.getId()) != null ? Long.valueOf(clusesMap.get(v.getId()).getSuccessCount()) : 0L);
// 设置转客比率
if (v.getCluesCount() > 0) {
per = NumberUtil.round(NumberUtil.div(v.getCluesToCustomerCount(), v.getCluesCount()), 2)
.multiply(new BigDecimal("100")).toString();
}
v.setCluesToCustomerPer(per);
}
});
}

View File

@ -6,7 +6,9 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReceiptApi;
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.ContractStatisticsDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
import cn.iocoder.yudao.module.crm.controller.admin.crmindex.vo.BrieCountVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmindex.vo.CrmIndexRespVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessDO;
@ -16,8 +18,6 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomercontacts.CrmCustome
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecord.CrmRecordDO;
import cn.iocoder.yudao.module.crm.dal.mysql.crmbusiness.CrmBusinessMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmclues.CrmCluesMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontract.CrmContractMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontractreceivables.CrmContractReceivablesMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmcustomer.CrmCustomerMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmcustomercontacts.CrmCustomerContactsMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecord.CrmRecordMapper;
@ -50,10 +50,7 @@ public class CrmIndexServiceImpl implements CrmIndexService {
private CrmCustomerMapper customerMapper;
@Resource
private CrmCluesMapper crmCluesMapper;
@Resource
private CrmContractMapper contractMapper;
@Resource
private CrmContractReceivablesMapper contractReceivablesMapper;
@Resource
private CrmRecordMapper crmRecordMapper;
@Resource
@ -66,6 +63,9 @@ public class CrmIndexServiceImpl implements CrmIndexService {
@Resource
private BpmOAContractApi bpmOAContractApi;
@Resource
private BpmOAReceiptApi receiptApi;
@Override
public CrmIndexRespVO getIndexCount(String relation) {
@ -112,7 +112,6 @@ public class CrmIndexServiceImpl implements CrmIndexService {
.build();
}
/**
* 统计当天
*
@ -197,66 +196,14 @@ public class CrmIndexServiceImpl implements CrmIndexService {
// 设置较昨日比率
String per006 = contractStatisticsDTO.getMoneyPercentage().toString();
// Long count05 = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
// .in(!ids.isEmpty(), CrmContractDO::getOwnerUserId, ids)
// .between(CrmContractDO::getCreateTime, todayStart, todayEnd));
// Long count005 = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
// .in(!ids.isEmpty(), CrmContractDO::getOwnerUserId, ids)
// .between(CrmContractDO::getCreateTime, yesterdayStart, yesterdayEnd));
// String per005 = "0";
// if (count005 > 0) {
// per005 = NumberUtil.div(NumberUtil.sub(count05, count005), count005, 2)
// .multiply(new BigDecimal("100")).toString();
// }
// QueryWrapper<CrmContractDO> queryWrapper06 = new QueryWrapper<>();
// queryWrapper06.select("sum(money) as count06");
// queryWrapper06.eq("to_days(create_time)", "to_days(now())");
// queryWrapper06.in(!ids.isEmpty(), "owner_user_id", ids);
// CrmContractDO crmContractDO = contractMapper.selectOne(queryWrapper06);
// BigDecimal count06 = BigDecimal.ZERO;
// if (crmContractDO != null) {
// count06 = crmContractDO.getCount06();
// }
//
// QueryWrapper<CrmContractDO> queryWrapper006 = new QueryWrapper<>();
// queryWrapper006.select("sum(money) as count006");
// queryWrapper006.eq("to_days(now())-to_days(create_time)", 1);
// queryWrapper006.in(!ids.isEmpty(), "owner_user_id", ids);
// CrmContractDO crmContractDO006 = contractMapper.selectOne(queryWrapper006);
// BigDecimal count006 = BigDecimal.ZERO;
// if (crmContractDO006 != null) {
// count006 = crmContractDO006.getCount006();
// }
// String per006 = "0";
// if (count006.compareTo(BigDecimal.ZERO) > 0) {
// per006 = NumberUtil.div(NumberUtil.sub(count06, count006), count006, 2)
// .multiply(new BigDecimal("100")).toString();
// }
// QueryWrapper<CrmContractReceivablesDO> queryWrapper07 = new QueryWrapper<>();
// queryWrapper07.select("sum(money) as count07");
// queryWrapper07.eq("to_days(create_time)", "to_days(now())");
// CrmContractReceivablesDO crmContractReceivablesDO = contractReceivablesMapper.selectOne(queryWrapper07);
BigDecimal count07 = BigDecimal.ZERO;
// if (crmContractDO != null) {
// count07 = crmContractReceivablesDO.getCount07();
// }
// QueryWrapper<CrmContractReceivablesDO> queryWrapper007 = new QueryWrapper<>();
// queryWrapper007.select("sum(money) as count007");
// queryWrapper007.eq("to_days(now())-to_days(create_time)", 1);
// CrmContractReceivablesDO crmContractReceivablesDO007 = contractReceivablesMapper.selectOne(queryWrapper007);
BigDecimal count007 = BigDecimal.ZERO;
// if (crmContractReceivablesDO007 != null) {
// count007 = crmContractReceivablesDO007.getCount007();
// }
String per007 = "0";
// if (count007.compareTo(BigDecimal.ZERO) > 0) {
// per007 = NumberUtil.div(NumberUtil.sub(count07, count007), count007, 2)
// .multiply(new BigDecimal("100")).toString();
// }
// 获取今日回款新增金额
ReceiptStatisticsDTO receiptStatisticsDTO = receiptApi.getReceiptCount(relation).getCheckedData();
// 设置今日新增金额
BigDecimal count07 = receiptStatisticsDTO.getTodayAddMoney();
// 设置昨日新增金额
BigDecimal count007 = receiptStatisticsDTO.getYesterdayAddMoney();
// 设置较昨日比率
String per007 = receiptStatisticsDTO.getMoneyPercentage().toString();
Long count08 = customerContactsMapper.selectCount(new LambdaQueryWrapper<CrmCustomerContactsDO>()
.in(!ids.isEmpty(), CrmCustomerContactsDO::getOwnerUserId, ids)

View File

@ -50,9 +50,29 @@
<if test="dto.creatorName != null and dto.creatorName != ''">
and d.nickname like concat('%', #{dto.creatorName}, '%')
</if>
<if test="dto.getIsCheck() != null">
<if test="dto.getIsCheck()">
AND FIND_IN_SET ('${dto.loginAdminId}',a.flow_admin_id)
</if>
</where>
</select>
<select id="selectReceivablesTop" resultType="cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.ContractVO">
SELECT
t.user_id AS id,
COUNT( t.id ) AS count,
SUM( t.money ) AS money,
u.nickname AS nickname
FROM
bpm_oa_receipt t
LEFT JOIN system_users u ON ( u.id = t.user_id )
AND u.deleted = 0
WHERE
t.deleted = 0
AND t.result = 2
GROUP BY
t.user_id
ORDER BY
money DESC
LIMIT 10
</select>
</mapper>