(cfeatrm): 新增业绩分析、客户分析和排名分析功能- 新增业绩分析相关VO类和控制器方法

- 新增客户分析相关VO类和控制器方法- 新增排名分析相关VO类和控制器方法
- 修改首页统计接口,增加与昨日数据的对比
- 在合同和回款表中添加昨日数据字段
-优化业绩统计查询SQL
This commit is contained in:
aikai 2024-11-22 09:14:01 +08:00
parent 3f5b1e143b
commit a9b29c5f7a
37 changed files with 1473 additions and 93 deletions

View File

@ -91,8 +91,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
}
// 构建登录用户
return new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes())
.setInfo(accessToken.getUserInfo()); // 额外的用户信息;
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes());
} catch (ServiceException serviceException) {
// 校验 Token 不通过时考虑到一些接口是无需登录的所以直接返回 null 即可
return null;

View File

@ -0,0 +1,62 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmanalysis;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.*;
import cn.iocoder.yudao.module.crm.service.crmanalysis.AchievementService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 业绩分析")
@RestController
@RequestMapping("/crm/analysis-achievement")
@Validated
public class AchievementController {
@Resource
private AchievementService achievementService;
@GetMapping("/depts")
@Operation(summary = "获得部门业绩分析")
public CommonResult<List<DeptAchieveVO>> getDeptsAchievement(@Valid AchievementPageReqVO pageReqVO) {
List<DeptAchieveVO> deptAchieveRespVOS = achievementService.getDeptAchieve(pageReqVO);
return success(deptAchieveRespVOS);
}
@GetMapping("/user")
@Operation(summary = "获得员工业绩分析")
public CommonResult<PageResult<UserAchieveVO>> getAchievementPage(@Valid AchievementPageReqVO pageReqVO) {
return success(achievementService.getAchievementPage(pageReqVO));
}
@GetMapping("/completion")
@Operation(summary = "获得业绩完成度")
public CommonResult<List<CompletionVO>> getAchievementCompletion(@RequestParam(name = "relation",defaultValue = "my",required=false) String relation) {
return success(achievementService.getCompletion(relation));
}
@GetMapping("/sales")
@Operation(summary = "销售简报")
public CommonResult<List<SalesVO>> getSales(@RequestParam(name = "relation",defaultValue = "my",required=false) String relation) {
return success(achievementService.getSales(relation));
}
}

View File

@ -0,0 +1,67 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmanalysis;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.AchievementPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.CustomerLevelVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.UserRecordVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.UserVolumeVO;
import cn.iocoder.yudao.module.crm.service.crmanalysis.CustomerService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 客户分析")
@RestController
@RequestMapping("/crm/analysis-customer")
@Validated
public class CustomerController {
@Resource
private CustomerService customerService;
@GetMapping("/level")
@Operation(summary = "获得客户等级分析")
public CommonResult<CustomerLevelVO> getCustomerLevel() {
return success(customerService.getCustomerLevel());
}
@GetMapping("/source")
@Operation(summary = "获得客户来源分析")
public CommonResult<CustomerLevelVO> getCustomerSource() {
return success(customerService.getCustomerSource());
}
@GetMapping("/industry")
@Operation(summary = "获得客户行业分析")
public CommonResult<CustomerLevelVO> getCustomerIndustry() {
return success(customerService.getCustomerIndustry());
}
@GetMapping("/volume")
@Operation(summary = "获得客户量分析")
public CommonResult<PageResult<UserVolumeVO>> getAchievementPage(@Valid AchievementPageReqVO pageReqVO) {
return success(customerService.getCustomerVolume(pageReqVO));
}
@GetMapping("/record")
@Operation(summary = "获得跟进分析")
public CommonResult<PageResult<UserRecordVO>> getRecord(@Valid AchievementPageReqVO pageReqVO) {
return success(customerService.getRecord(pageReqVO));
}
}

View File

@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmanalysis;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.ContractVO;
import cn.iocoder.yudao.module.crm.service.crmanalysis.RankService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 排名分析")
@RestController
@RequestMapping("/crm/analysis-rank")
@Validated
public class RankController {
@Resource
private RankService rankService;
@GetMapping("/contract")
@Operation(summary = "获得合同排名")
public CommonResult<List<ContractVO>> getContractRank() {
return success(rankService.getContractRank());
}
@GetMapping("/receivables")
@Operation(summary = "获得回款排名")
public CommonResult<List<ContractVO>> getRecevablesRank() {
return success(rankService.getReceivablesRank());
}
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 业绩目标分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class AchievementPageReqVO extends PageParam {
@Schema(description = "名称", example = "赵六")
private String name;
@Schema(description = "添加时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 业绩完成度 Response VO")
@Data
public class CompletionVO {
@Schema(description = "时间")
private String time;
@Schema(description = "目标金额")
private BigDecimal targetPrice;
@Schema(description = "成交金额")
private BigDecimal successPrice;
@Schema(description = "成交数量")
private Long successCount;
@Schema(description = "平均客单价")
private BigDecimal perPrice;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 合同与回款 Response VO")
@Data
public class ContractVO {
@Schema(description = "编号", example = "1024")
private Long id;
@Schema(description = "用户名称")
private String nickname;
@Schema(description = "数量")
private Long count;
@Schema(description = "金额")
private BigDecimal money;
}

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 客户分析 Response VO")
@Data
@Builder
public class CustomerLevelVO {
@Schema(description = "等级")
private List<String> data;
@Schema(description = "所有客户")
private List<Long> allCustomer;
@Schema(description = "成交客户")
private List<Long> dealCustomer;
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 部门业绩信息 Response VO")
@Data
public class DeptAchieveVO {
@Schema(description = "部门编号", example = "1024")
private Long id;
@Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yshop")
private String name;
@Schema(description = "父部门 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long parentId;
@Schema(description = "合同数量")
private Long contractCount;
@Schema(description = "合同金额")
private BigDecimal contractMoney;
@Schema(description = "回款金额")
private BigDecimal receivablesMoney;
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 销售简报 Response VO")
@Data
public class SalesVO {
@Schema(description = "时间")
private String time;
@Schema(description = "新增线索")
private Long cluesCount;
@Schema(description = "新增客户")
private Long customerCount;
@Schema(description = "新增商机")
private Long businessCount;
@Schema(description = "新增合同")
private Long contractCount;
@Schema(description = "新增回款")
private Long receivablesCount;
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 用户业绩分析信息 Response VO")
@Data
public class UserAchieveVO {
@Schema(description = "用户编号", example = "1024")
private Long id;
@Schema(description = "用户名称")
private String nickname;
@Schema(description = "合同数量")
private Long contractCount;
@Schema(description = "合同金额")
private BigDecimal contractMoney;
@Schema(description = "回款金额")
private BigDecimal receivablesMoney;
@Schema(description = "线索数量")
private Long cluesCount;
@Schema(description = "转客数量")
private Long cluesToCustomerCount;
@Schema(description = "转客比率")
private String cluesToCustomerPer;
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 跟进分析信息 Response VO")
@Data
public class UserRecordVO {
@Schema(description = "用户编号", example = "1024")
private Long id;
@Schema(description = "用户名称")
private String nickname;
@Schema(description = "数量")
private Long totalCount;
@Schema(description = "客户数量")
private Long customerCount;
@Schema(description = "商机数量")
private Long businessCount;
@Schema(description = "线索数量")
private Long cluesCount;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 客户量分析信息 Response VO")
@Data
public class UserVolumeVO {
@Schema(description = "用户编号", example = "1024")
private Long id;
@Schema(description = "用户名称")
private String nickname;
@Schema(description = "客户增量")
private Long customerCount;
@Schema(description = "成交数量")
private Long successCount;
@Schema(description = "成交比率")
private String successPer;
}

View File

@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@ -24,8 +25,8 @@ public class CrmIndexController {
@GetMapping("/getCount")
@Operation(summary = "首页统计")
public CommonResult<CrmIndexRespVO> getCount() {
return success(crmIndexService.getIndexCount());
public CommonResult<CrmIndexRespVO> getCount(@RequestParam(name = "relation",defaultValue = "my",required=false) String relation) {
return success(crmIndexService.getIndexCount(relation));
}

View File

@ -13,27 +13,75 @@ public class BrieCountVO {
@Schema(description = "新增商机")
private Long count01;
@Schema(description = "昨日新增商机")
private Long count001;
@Schema(description = "较昨日比率")
private String per001;
@Schema(description = "新增线索")
private Long count02;
@Schema(description = "昨日新增线索")
private Long count002;
@Schema(description = "较昨日比率")
private String per002;
@Schema(description = "新增客户")
private Long count03;
@Schema(description = "昨日新增客户")
private Long count003;
@Schema(description = "较昨日比率")
private String per003;
@Schema(description = "新增跟进")
private Long count04;
@Schema(description = "昨日新增跟进")
private Long count004;
@Schema(description = "较昨日比率")
private String per004;
@Schema(description = "新增合同")
private Long count05;
@Schema(description = "昨日新增合同")
private Long count005;
@Schema(description = "较昨日比率")
private String per005;
@Schema(description = "合同金额")
private BigDecimal count06;
@Schema(description = "昨日合同金额")
private BigDecimal count006;
@Schema(description = "较昨日比率")
private String per006;
@Schema(description = "回款金额")
private BigDecimal count07;
@Schema(description = "昨日回款金额")
private BigDecimal count007;
@Schema(description = "较昨日比率")
private String per007;
@Schema(description = "新增联系人")
private Long count08;
@Schema(description = "昨日新增联系人")
private Long count008;
@Schema(description = "较昨日比率")
private String per008;
@Schema(description = "客户成交量")
private Long count09;

View File

@ -135,4 +135,6 @@ public class CrmContractDO extends BaseDO {
@TableField(exist = false)
private BigDecimal count06;
@TableField(exist = false)
private BigDecimal count006;
}

View File

@ -100,4 +100,7 @@ public class CrmContractReceivablesDO extends BaseDO {
@TableField(exist = false)
private BigDecimal count07;
@TableField(exist = false)
private BigDecimal count007;
}

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.ContractVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.CrmContractPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.CrmContractRespVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractDO;
@ -13,6 +14,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@ -54,4 +56,9 @@ public interface CrmContractMapper extends BaseMapperX<CrmContractDO> {
.orderByDesc(CrmContractDO::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 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> selectContractTop();
}

View File

@ -3,16 +3,14 @@ package cn.iocoder.yudao.module.crm.dal.mysql.crmcontractreceivables;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.ContractVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmcontractreceivables.vo.CrmContractReceivablesPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmcontractreceivables.vo.CrmContractReceivablesRespVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontractreceivables.CrmContractReceivablesDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@ -48,4 +46,9 @@ 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

@ -229,8 +229,6 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
Date starTime = new Date();
Date endTime = new Date();
Calendar calendar = Calendar.getInstance();
System.out.println("a:" + year);
System.out.println("b:" + month);
if (month == 0) {
//全年
calendar.set(year, 1, 1);
@ -257,9 +255,6 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
.eqIfPresent(CrmAchievementDO::getYear, year));
System.out.println("年开始:" + DateUtil.formatDateTime(starTime));
System.out.println("年结束:" + DateUtil.formatDateTime(endTime));
List<CrmContractDO> crmContractDOS = contractMapper.selectList(new LambdaQueryWrapper<CrmContractDO>()
.in(CrmContractDO::getOwnerUserId, userIds)
.eq(CrmContractDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())

View File

@ -0,0 +1,46 @@
package cn.iocoder.yudao.module.crm.service.crmanalysis;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.*;
import java.util.List;
/**
* 业绩目标 Service 接口
*
* @author yshop
*/
public interface AchievementService {
/**
* 获得用户业绩分析
* @param pageReqVO 分页查询
* @return 业绩目标分页
*/
PageResult<UserAchieveVO> getAchievementPage(AchievementPageReqVO pageReqVO);
/**
* 获取部门业绩分析
* @param pageReqVO
* @return
*/
List<DeptAchieveVO> getDeptAchieve(AchievementPageReqVO pageReqVO);
/**
* 获取业绩完成度
* @param relation
* @return
*/
List<CompletionVO> getCompletion(String relation);
/**
* 销售简报
* @param relation
* @return
*/
List<SalesVO> getSales(String relation);
}

View File

@ -0,0 +1,380 @@
package cn.iocoder.yudao.module.crm.service.crmanalysis;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
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.crm.controller.admin.crmanalysis.vo.*;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmachievement.CrmAchievementDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmclues.CrmCluesDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontractreceivables.CrmContractReceivablesDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
import cn.iocoder.yudao.module.crm.dal.mysql.crmachievement.CrmAchievementMapper;
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.hrm.enums.CluesStatusEnum;
import cn.iocoder.yudao.module.hrm.enums.ContractStatusEnum;
import cn.iocoder.yudao.module.hrm.enums.FlowStepEnum;
import cn.iocoder.yudao.module.hrm.enums.RelationEnum;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptApiDTO;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptApiVO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserApiVO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserPageApiDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
* 业绩目标 Service 实现类
*
* @author yshop
*/
@Service
@Validated
public class AchievementServiceImpl implements AchievementService {
@Resource
private CrmAchievementMapper achievementMapper;
@Resource
private DeptApi deptApi;
@Resource
private AdminUserApi adminUserApi;
@Resource
private CrmContractMapper contractMapper;
@Resource
private CrmContractReceivablesMapper contractReceivablesMapper;
@Resource
private CrmCustomerMapper customerMapper;
@Resource
private CrmBusinessMapper businessMapper;
@Resource
private CrmCluesMapper crmCluesMapper;
@Override
public PageResult<UserAchieveVO> getAchievementPage(AchievementPageReqVO pageReqVO) {
AdminUserPageApiDTO dto = new AdminUserPageApiDTO();
dto.setUsername(pageReqVO.getName());
dto.setPageNo(pageReqVO.getPageNo());
dto.setPageSize(pageReqVO.getPageSize());
PageResult<AdminUserApiVO> pageResult = adminUserApi.getUserPage(dto).getCheckedData();
PageResult<UserAchieveVO> pageResult1 = BeanUtils.toBean(pageResult, UserAchieveVO.class);
pageResult1.getList().forEach(v -> {
LambdaQueryWrapperX<CrmContractDO> wrapperX = new LambdaQueryWrapperX<>();
wrapperX.eq(CrmContractDO::getOwnerUserId, v.getId())
.eq(CrmContractDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
.betweenIfPresent(CrmContractDO::getCreateTime, pageReqVO.getCreateTime());
v.setContractCount(contractMapper.selectCount(wrapperX));
List<CrmContractDO> crmContractDOS = contractMapper.selectList(wrapperX);
BigDecimal contractMoney = crmContractDOS
.stream()
.map(CrmContractDO::getMoney)
.reduce(BigDecimal.ZERO, BigDecimal::add);
v.setContractMoney(contractMoney);
List<CrmContractReceivablesDO> crmContractReceivablesDOS = contractReceivablesMapper
.selectList(new LambdaQueryWrapperX<CrmContractReceivablesDO>()
.eq(CrmContractReceivablesDO::getOwnerUserId, v.getId())
.eq(CrmContractReceivablesDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
.betweenIfPresent(CrmContractReceivablesDO::getCreateTime, pageReqVO.getCreateTime()));
BigDecimal receivablesMoney = crmContractReceivablesDOS
.stream()
.map(CrmContractReceivablesDO::getMoney)
.reduce(BigDecimal.ZERO, BigDecimal::add);
v.setReceivablesMoney(receivablesMoney);
LambdaQueryWrapperX<CrmCluesDO> wrapperX2 = new LambdaQueryWrapperX<>();
wrapperX2.eq(CrmCluesDO::getOwnerUserId, v.getId())
.betweenIfPresent(CrmCluesDO::getCreateTime, pageReqVO.getCreateTime());
Long cluesCount = crmCluesMapper.selectCount(wrapperX2);
v.setCluesCount(cluesCount);
wrapperX2.eq(CrmCluesDO::getStatus, CluesStatusEnum.STATUS_1.getValue());
Long cluesToCustomerCount = crmCluesMapper.selectCount(wrapperX2);
v.setCluesToCustomerCount(cluesToCustomerCount);
String per = "0";
if (cluesCount > 0) {
per = NumberUtil.round(NumberUtil.div(cluesToCustomerCount, cluesCount), 2)
.multiply(new BigDecimal("100")).toString();
}
v.setCluesToCustomerPer(per);
});
return pageResult1;
}
@Override
public List<DeptAchieveVO> getDeptAchieve(AchievementPageReqVO pageReqVO) {
List<DeptApiVO> list = deptApi.getDeptList(new DeptApiDTO().setStatus(CommonStatusEnum.ENABLE.getStatus())).getCheckedData();
List<DeptAchieveVO> achieveRespVOS = BeanUtils.toBean(list, DeptAchieveVO.class);
achieveRespVOS.forEach(vo -> {
List<AdminUserRespDTO> adminUserRespDTOS = adminUserApi.getUserListByDeptIds(CollUtil.newArrayList(vo.getId())).getCheckedData();
List<Long> ids = CollUtil.newArrayList(-1L);
if (!adminUserRespDTOS.isEmpty()) {
ids = adminUserRespDTOS.stream().map(AdminUserRespDTO::getId).collect(Collectors.toList());
}
LambdaQueryWrapperX<CrmContractDO> wrapperX = new LambdaQueryWrapperX<>();
wrapperX.inIfPresent(CrmContractDO::getOwnerUserId, ids)
.eq(CrmContractDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
.betweenIfPresent(CrmContractDO::getCreateTime, pageReqVO.getCreateTime());
List<CrmContractDO> crmContractDOS = contractMapper.selectList(wrapperX);
BigDecimal contractMoney = crmContractDOS
.stream()
.map(CrmContractDO::getMoney)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal receivablesMoney = crmContractDOS
.stream()
.map(CrmContractDO::getReturnMoney)
.reduce(BigDecimal.ZERO, BigDecimal::add);
vo.setContractCount(Long.valueOf(crmContractDOS.size()));
vo.setContractMoney(contractMoney);
vo.setReceivablesMoney(receivablesMoney);
});
return achieveRespVOS;
}
@Override
public List<CompletionVO> getCompletion(String relation) {
Integer year = DateUtil.year(new Date());
List<Long> userIds = new ArrayList<>();
Long userId = SecurityFrameworkUtils.getLoginUserId();
if (RelationEnum.MY.getValue().equals(relation)) {
userIds.add(userId);
} else if (RelationEnum.SUB.getValue().equals(relation)) {
userIds = adminUserApi.getUserListBySubordinateIds(userId).getData();
}
//合同目标
List<CrmAchievementDO> crmAchievementDO = achievementMapper.selectList(new LambdaQueryWrapperX<CrmAchievementDO>()
.eq(CrmAchievementDO::getType, FlowStepEnum.TYPE_2.getValue())
.in(CrmAchievementDO::getTypeId, userIds)
.eqIfPresent(CrmAchievementDO::getConfig, ShopCommonEnum.ACH_1.getValue())
.eqIfPresent(CrmAchievementDO::getYear, year));
List<CompletionVO> completionVOS = new ArrayList<>();
int i = 1;
while (i <= 12) {
BigDecimal targetPrice = BigDecimal.ZERO;
BigDecimal successPrice = BigDecimal.ZERO;
Long successCount = 0L;
BigDecimal perPrice = BigDecimal.ZERO;
String time = "" + year;
if (i < 10) {
time = time + "-0" + i;
} else {
time = time + "-" + i;
}
CompletionVO completionVO = new CompletionVO();
completionVO.setTime(time);
switch (i) {
case 1: {
if (crmAchievementDO != null) {
targetPrice = crmAchievementDO
.stream()
.map(CrmAchievementDO::getJanuary)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
case 2: {
if (crmAchievementDO != null) {
targetPrice = crmAchievementDO
.stream()
.map(CrmAchievementDO::getFebruary)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
case 3: {
if (crmAchievementDO != null) {
targetPrice = crmAchievementDO
.stream()
.map(CrmAchievementDO::getMarch)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
case 4: {
if (crmAchievementDO != null) {
targetPrice = crmAchievementDO
.stream()
.map(CrmAchievementDO::getApril)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
case 5: {
if (crmAchievementDO != null) {
targetPrice = crmAchievementDO
.stream()
.map(CrmAchievementDO::getMay)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
case 6: {
if (crmAchievementDO != null) {
targetPrice = crmAchievementDO
.stream()
.map(CrmAchievementDO::getJune)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
case 7: {
if (crmAchievementDO != null) {
targetPrice = crmAchievementDO
.stream()
.map(CrmAchievementDO::getJuly)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
case 8: {
if (crmAchievementDO != null) {
targetPrice = crmAchievementDO
.stream()
.map(CrmAchievementDO::getAugust)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
case 9: {
if (crmAchievementDO != null) {
targetPrice = crmAchievementDO
.stream()
.map(CrmAchievementDO::getSeptember)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
case 10: {
if (crmAchievementDO != null) {
targetPrice = crmAchievementDO
.stream()
.map(CrmAchievementDO::getOctober)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
case 11: {
if (crmAchievementDO != null) {
targetPrice = crmAchievementDO
.stream()
.map(CrmAchievementDO::getNovember)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
case 12: {
if (crmAchievementDO != null) {
targetPrice = crmAchievementDO
.stream()
.map(CrmAchievementDO::getDecember)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
}
Date starTime = new Date();
Date endTime = new Date();
Calendar calendar = Calendar.getInstance();
//某个月
calendar.set(year, i - 1, 1);
starTime = DateUtil.beginOfMonth(calendar.getTime());
endTime = DateUtil.endOfMonth(calendar.getTime());
LambdaQueryWrapper<CrmContractDO> wrapper = new LambdaQueryWrapper<>();
wrapper.in(CrmContractDO::getOwnerUserId, userIds)
.eq(CrmContractDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
.between(CrmContractDO::getOrderTime, starTime, endTime);
List<CrmContractDO> crmContractDOS = contractMapper.selectList(wrapper);
if (!crmContractDOS.isEmpty()) {
successPrice = crmContractDOS
.stream()
.map(CrmContractDO::getMoney)
.reduce(BigDecimal.ZERO, BigDecimal::add);
successCount = Long.valueOf(crmContractDOS.size());
if (successCount > 0) {
perPrice = NumberUtil.round(NumberUtil.div(successPrice, successCount), 2);
}
}
completionVO.setSuccessPrice(successPrice);
completionVO.setSuccessCount(successCount);
completionVO.setTargetPrice(targetPrice);
completionVO.setPerPrice(perPrice);
completionVOS.add(completionVO);
i++;
}
return completionVOS;
}
@Override
public List<SalesVO> getSales(String relation) {
Integer year = DateUtil.year(new Date());
List<Long> userIds = new ArrayList<>();
Long userId = SecurityFrameworkUtils.getLoginUserId();
if (RelationEnum.MY.getValue().equals(relation)) {
userIds.add(userId);
} else if (RelationEnum.SUB.getValue().equals(relation)) {
userIds = adminUserApi.getUserListBySubordinateIds(userId).getData();
}
List<SalesVO> salesVOS = new ArrayList<>();
int i = 1;
while (i <= 12) {
String time = "" + year;
if (i < 10) {
time = time + "-0" + i;
} else {
time = time + "-" + i;
}
SalesVO salesVO = new SalesVO();
salesVO.setTime(time);
Date starTime = new Date();
Date endTime = new Date();
Calendar calendar = Calendar.getInstance();
//某个月
calendar.set(year, i - 1, 1);
starTime = DateUtil.beginOfMonth(calendar.getTime());
endTime = DateUtil.endOfMonth(calendar.getTime());
Long cluesCount = crmCluesMapper.selectCount(new LambdaQueryWrapper<CrmCluesDO>()
.in(CrmCluesDO::getOwnerUserId, userIds)
.between(CrmCluesDO::getCreateTime, starTime, endTime));
Long customerCount = customerMapper.selectCount(new LambdaQueryWrapper<CrmCustomerDO>()
.in(CrmCustomerDO::getOwnerUserId, userIds)
.between(CrmCustomerDO::getCreateTime, starTime, endTime));
Long businessCount = businessMapper.selectCount(new LambdaQueryWrapper<CrmBusinessDO>()
.in(CrmBusinessDO::getOwnerUserId, userIds)
.between(CrmBusinessDO::getCreateTime, starTime, endTime));
Long contractCount = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
.in(CrmContractDO::getOwnerUserId, userIds)
.between(CrmContractDO::getOrderTime, starTime, endTime));
Long receivablesCount = contractReceivablesMapper.selectCount(new LambdaQueryWrapper<CrmContractReceivablesDO>()
.in(CrmContractReceivablesDO::getOwnerUserId, userIds)
.between(CrmContractReceivablesDO::getReturnTime, starTime, endTime));
salesVO.setCluesCount(contractCount);
salesVO.setCustomerCount(customerCount);
salesVO.setBusinessCount(businessCount);
salesVO.setContractCount(contractCount);
salesVO.setReceivablesCount(receivablesCount);
salesVOS.add(salesVO);
i++;
}
return salesVOS;
}
}

View File

@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.crm.service.crmanalysis;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.AchievementPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.CustomerLevelVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.UserRecordVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.UserVolumeVO;
/**
* 客户分析 Service 接口
*
* @author yshop
*/
public interface CustomerService {
/**
* 客户级别分析
* @return
*/
CustomerLevelVO getCustomerLevel();
/**
* 客户来源分析
* @return
*/
CustomerLevelVO getCustomerSource();
/**
* 客户行业分析
* @return
*/
CustomerLevelVO getCustomerIndustry();
/**
* 获得客户量分析
* @param pageReqVO 分页查询
*/
PageResult<UserVolumeVO> getCustomerVolume(AchievementPageReqVO pageReqVO);
/**
* 获得跟进分析
* @param pageReqVO 分页查询
*/
PageResult<UserRecordVO> getRecord(AchievementPageReqVO pageReqVO);
}

View File

@ -0,0 +1,191 @@
package cn.iocoder.yudao.module.crm.service.crmanalysis;
import cn.hutool.core.util.NumberUtil;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.AchievementPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.CustomerLevelVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.UserRecordVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.UserVolumeVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecord.CrmRecordDO;
import cn.iocoder.yudao.module.crm.dal.mysql.crmachievement.CrmAchievementMapper;
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.crmrecord.CrmRecordMapper;
import cn.iocoder.yudao.module.hrm.enums.TypesEnum;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserApiVO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserPageApiDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* 客户分析 Service 实现类
*
* @author yshop
*/
@Service
@Validated
public class CustomerServiceImpl implements CustomerService {
@Resource
private CrmAchievementMapper achievementMapper;
@Resource
private DeptApi deptApi;
@Resource
private DictDataApi dictDataApi;
@Resource
private CrmContractMapper contractMapper;
@Resource
private CrmContractReceivablesMapper contractReceivablesMapper;
@Resource
private CrmCluesMapper crmCluesMapper;
@Resource
private AdminUserApi adminUserApi;
@Resource
private CrmCustomerMapper customerMapper;
@Resource
private CrmRecordMapper crmRecordMapper;
@Override
public CustomerLevelVO getCustomerLevel() {
List<DictDataRespDTO> list = dictDataApi.getDictDataList("customer_level").getCheckedData();
List<Long> allCustomer = new ArrayList<>();
List<Long> dealCustomer = new ArrayList<>();
list.forEach(v -> {
LambdaQueryWrapper<CrmCustomerDO> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CrmCustomerDO::getLevel, v.getValue());
Long all = customerMapper.selectCount(wrapper);
wrapper.eq(CrmCustomerDO::getDealStatus, ShopCommonEnum.IS_STATUS_1.getValue());
Long deal = customerMapper.selectCount(wrapper);
allCustomer.add(all);
dealCustomer.add(deal);
});
List<String> data = list.stream().map(DictDataRespDTO::getLabel).collect(Collectors.toList());
return CustomerLevelVO.builder().data(data).allCustomer(allCustomer).dealCustomer(dealCustomer).build();
}
@Override
public CustomerLevelVO getCustomerSource() {
List<DictDataRespDTO> list = dictDataApi.getDictDataList("customer_source").getCheckedData();
List<Long> allCustomer = new ArrayList<>();
List<Long> dealCustomer = new ArrayList<>();
list.forEach(v -> {
LambdaQueryWrapper<CrmCustomerDO> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CrmCustomerDO::getSource, v.getValue());
Long all = customerMapper.selectCount(wrapper);
wrapper.eq(CrmCustomerDO::getDealStatus, ShopCommonEnum.IS_STATUS_1.getValue());
Long deal = customerMapper.selectCount(wrapper);
allCustomer.add(all);
dealCustomer.add(deal);
});
List<String> data = list.stream().map(DictDataRespDTO::getLabel).collect(Collectors.toList());
return CustomerLevelVO.builder().data(data).allCustomer(allCustomer).dealCustomer(dealCustomer).build();
}
@Override
public CustomerLevelVO getCustomerIndustry() {
List<DictDataRespDTO> list = dictDataApi.getDictDataList("customer_industry").getCheckedData();
List<Long> allCustomer = new ArrayList<>();
List<Long> dealCustomer = new ArrayList<>();
list.forEach(v -> {
LambdaQueryWrapper<CrmCustomerDO> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CrmCustomerDO::getIndustry, v.getValue());
Long all = customerMapper.selectCount(wrapper);
wrapper.eq(CrmCustomerDO::getDealStatus, ShopCommonEnum.IS_STATUS_1.getValue());
Long deal = customerMapper.selectCount(wrapper);
allCustomer.add(all);
dealCustomer.add(deal);
});
List<String> data = list.stream().map(DictDataRespDTO::getLabel).collect(Collectors.toList());
return CustomerLevelVO.builder().data(data).allCustomer(allCustomer).dealCustomer(dealCustomer).build();
}
@Override
public PageResult<UserVolumeVO> getCustomerVolume(AchievementPageReqVO pageReqVO) {
AdminUserPageApiDTO dto = new AdminUserPageApiDTO();
dto.setUsername(pageReqVO.getName());
dto.setPageNo(pageReqVO.getPageNo());
dto.setPageSize(pageReqVO.getPageSize());
PageResult<AdminUserApiVO> pageResult = adminUserApi.getUserPage(dto).getCheckedData();
PageResult<UserVolumeVO> pageResult1 = BeanUtils.toBean(pageResult, UserVolumeVO.class);
pageResult1.getList().forEach(v -> {
LambdaQueryWrapperX<CrmCustomerDO> wrapperX = new LambdaQueryWrapperX<>();
wrapperX.eq(CrmCustomerDO::getOwnerUserId, v.getId())
.betweenIfPresent(CrmCustomerDO::getCreateTime, pageReqVO.getCreateTime());
Long customerCount = customerMapper.selectCount(wrapperX);
wrapperX.eq(CrmCustomerDO::getDealStatus, ShopCommonEnum.IS_STATUS_1.getValue());
Long successCount = customerMapper.selectCount(wrapperX);
v.setCustomerCount(customerCount);
v.setSuccessCount(successCount);
String per = "0";
if (customerCount > 0) {
per = NumberUtil.round(NumberUtil.div(successCount, customerCount), 2)
.multiply(new BigDecimal("100")).toString();
}
v.setSuccessPer(per);
});
return pageResult1;
}
@Override
public PageResult<UserRecordVO> getRecord(AchievementPageReqVO pageReqVO) {
AdminUserPageApiDTO dto = new AdminUserPageApiDTO();
dto.setUsername(pageReqVO.getName());
dto.setPageNo(pageReqVO.getPageNo());
dto.setPageSize(pageReqVO.getPageSize());
PageResult<AdminUserApiVO> pageResult = adminUserApi.getUserPage(dto).getCheckedData();
PageResult<UserRecordVO> pageResult1 = BeanUtils.toBean(pageResult, UserRecordVO.class);
pageResult1.getList().forEach(v -> {
LambdaQueryWrapperX<CrmRecordDO> wrapperX = new LambdaQueryWrapperX<>();
wrapperX.eq(CrmRecordDO::getCreator, v.getId())
.betweenIfPresent(CrmRecordDO::getCreateTime, pageReqVO.getCreateTime());
Long totalCount = crmRecordMapper.selectCount(wrapperX);
wrapperX.eq(CrmRecordDO::getTypes, TypesEnum.CUSTOMER.getValue());
Long customerCount = crmRecordMapper.selectCount(wrapperX);
wrapperX.eq(CrmRecordDO::getTypes, TypesEnum.BUSINESS.getValue());
Long businessCount = crmRecordMapper.selectCount(wrapperX);
wrapperX.eq(CrmRecordDO::getTypes, TypesEnum.CLUES.getValue());
Long cluesCount = crmRecordMapper.selectCount(wrapperX);
v.setTotalCount(totalCount);
v.setCustomerCount(customerCount);
v.setBusinessCount(businessCount);
v.setCluesCount(cluesCount);
});
return pageResult1;
}
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.crm.service.crmanalysis;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.ContractVO;
import java.util.List;
/**
* 排行分析 Service 接口
*
* @author yshop
*/
public interface RankService {
List<ContractVO> getContractRank();
List<ContractVO> getReceivablesRank();
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.crm.service.crmanalysis;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.ContractVO;
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontract.CrmContractMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontractreceivables.CrmContractReceivablesMapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.List;
/**
* 排行分析 Service 实现类
*
* @author yshop
*/
@Service
@Validated
public class RankServiceImpl implements RankService {
@Resource
private CrmContractMapper contractMapper;
@Resource
private CrmContractReceivablesMapper contractReceivablesMapper;
@Override
public List<ContractVO> getContractRank() {
return contractMapper.selectContractTop();
}
@Override
public List<ContractVO> getReceivablesRank() {
return contractReceivablesMapper.selectReceivablesTop();
}
}

View File

@ -151,6 +151,9 @@ public class CrmCluesServiceImpl implements CrmCluesService {
if (crmCluesDO == null) {
throw exception(CLUES_NOT_EXISTS);
}
if(CluesStatusEnum.STATUS_1.getValue().equals(crmCluesDO.getStatus())){
throw exception(new ErrorCode(202411160,"已经转化成客户!"));
}
createReqVO.setId(null);
CrmCustomerDO customerDO = BeanUtils.toBean(createReqVO, CrmCustomerDO.class);
customerDO.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());

View File

@ -117,7 +117,6 @@ public class CrmContractServiceImpl implements CrmContractService {
//处理客户
CrmCustomerDO crmCustomerDO = customerMapper.selectById(createReqVO.getCustomerId());
// 插入
CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class);
contract.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
@ -130,10 +129,10 @@ public class CrmContractServiceImpl implements CrmContractService {
createContractProductList(contract.getId(), createReqVO.getContractProducts());
//更新审核
updateAfter(contract.getId());
// updateAfter(contract.getId());
//插入日志
crmOperatelogService.createLog("添加合同", 0L, contract.getId(), 0L);
// crmOperatelogService.createLog("添加合同", 0L, contract.getId(), 0L);
//todo 站内信通知 审批
@ -392,7 +391,6 @@ public class CrmContractServiceImpl implements CrmContractService {
}
private void createContractProductList(Long contractId, List<CrmContractProductDO> list) {
List<StoreProductAttrValueApiVO> storeProductAttrValueList = new ArrayList<>();
if (CollUtil.isNotEmpty(list)) {
List<Long> productIds = list.stream().map(CrmContractProductDO::getProductId).collect(Collectors.toList());
@ -402,23 +400,22 @@ public class CrmContractServiceImpl implements CrmContractService {
.setUniques(productAttrUnique)).getCheckedData();
}
Map<String, List<StoreProductAttrValueApiVO>> map = storeProductAttrValueList.stream().collect(Collectors.groupingBy(a -> a.getProductId() + "_" + a.getUnique()));
list.forEach(o -> {
o.setContractId(contractId);
//库存处理
List<StoreProductAttrValueApiVO> storeProductAttrValueApiVOS = map.get(o.getProductId() + "_" + o.getProductAttrUnique());
Integer count = 0;
int count = 0;
if (CollUtil.isNotEmpty(storeProductAttrValueApiVOS)) {
count = storeProductAttrValueApiVOS.size();
count = storeProductAttrValueApiVOS.stream().mapToInt(StoreProductAttrValueApiVO::getStock).sum();
}
if (NumberUtil.compare(count, o.getNums()) < 0) {
throw exception(new ErrorCode(202408250, "该商品ID" + o.getProductId() + "库存不足"));
}
// TODO: 2024/11/21 这里的库存扣件完后 - 如果审批不通过 库存退回
this.decProductStock(o.getNums(), o.getProductId(), o.getProductAttrUnique());
});
contractProductMapper.insertBatch(list);
}

View File

@ -9,6 +9,6 @@ import cn.iocoder.yudao.module.crm.controller.admin.crmindex.vo.CrmIndexRespVO;
*/
public interface CrmIndexService {
CrmIndexRespVO getIndexCount();
CrmIndexRespVO getIndexCount(String relation);
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.crm.service.crmindex;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
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;
@ -12,7 +13,6 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontractreceivables.CrmContractReceivablesDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomercontacts.CrmCustomerContactsDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crminvoice.CrmInvoiceDO;
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;
@ -20,11 +20,11 @@ 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.crminvoice.CrmInvoiceMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecord.CrmRecordMapper;
import cn.iocoder.yudao.module.product.api.storeproduct.StoreProductApi;
import cn.iocoder.yudao.module.hrm.enums.RelationEnum;
import cn.iocoder.yudao.module.system.api.notice.NoticeApi;
import cn.iocoder.yudao.module.system.api.notice.dto.NoticeDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Service;
@ -32,7 +32,9 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 商机 Service 实现类
@ -46,10 +48,6 @@ public class CrmIndexServiceImpl implements CrmIndexService {
@Resource
private CrmBusinessMapper businessMapper;
@Resource
private StoreProductApi storeProductApi;
@Resource
private CrmInvoiceMapper crmInvoiceMapper;
@Resource
private CrmCustomerMapper customerMapper;
@Resource
private CrmCluesMapper crmCluesMapper;
@ -63,50 +61,52 @@ public class CrmIndexServiceImpl implements CrmIndexService {
private CrmCustomerContactsMapper customerContactsMapper;
@Resource
private NoticeApi noticeApi;
@Resource
private AdminUserApi adminUserApi;
@Override
public CrmIndexRespVO getIndexCount() {
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
Date todayStart = DateUtil.beginOfDay(new Date());
Date todayEnd = DateUtil.endOfDay(new Date());
Date day30 = DateUtil.offsetDay(new Date(), 30);
Long followCustomerCount = customerMapper.selectCount(new LambdaQueryWrapper<CrmCustomerDO>()
.between(CrmCustomerDO::getNextTime, todayStart, todayEnd).eq(CrmCustomerDO::getOwnerUserId, loginUserId));
Long followBusinessCount = businessMapper.selectCount(new LambdaQueryWrapper<CrmBusinessDO>()
.between(CrmBusinessDO::getNextTime, todayStart, todayEnd).eq(CrmBusinessDO::getOwnerUserId, loginUserId));
Long followCluesCount = crmCluesMapper.selectCount(new LambdaQueryWrapper<CrmCluesDO>()
.between(CrmCluesDO::getNextTime, todayStart, todayEnd).eq(CrmCluesDO::getOwnerUserId, loginUserId));
Long contractDueCount = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
.between(CrmContractDO::getEndTime, todayStart, day30).eq(CrmContractDO::getOwnerUserId, loginUserId));
Long customerDueCount = 0L;
Long contractReturnCount = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
.eq(CrmContractDO::getOwnerUserId, loginUserId).apply("money > return_money"));
Long myInvoiceCount = crmInvoiceMapper.selectCount(new LambdaQueryWrapper<CrmInvoiceDO>()
.eq(CrmInvoiceDO::getCreator, loginUserId));
Long productCount = storeProductApi.selectCount().getCheckedData();
Long contractCheckCount = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
.apply("FIND_IN_SET ('" + loginUserId + "',flow_admin_id)"));
Long receivablesCheckCount = contractReceivablesMapper.selectCount(new LambdaQueryWrapper<CrmContractReceivablesDO>()
.apply("FIND_IN_SET ('" + loginUserId + "',flow_admin_id)"));
Long invoiceCheckCount = crmInvoiceMapper.selectCount(new LambdaQueryWrapper<CrmInvoiceDO>()
.apply("FIND_IN_SET ('" + loginUserId + "',flow_admin_id)"));
public CrmIndexRespVO getIndexCount(String relation) {
// Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
// Date todayStart = DateUtil.beginOfDay(new Date());
// Date todayEnd = DateUtil.endOfDay(new Date());
// Date day30 = DateUtil.offsetDay(new Date(),30);
//
// Long followCustomerCount = customerMapper.selectCount(new LambdaQueryWrapper<CrmCustomerDO>()
// .between(CrmCustomerDO::getNextTime,todayStart,todayEnd).eq(CrmCustomerDO::getOwnerUserId,loginUserId));
// Long followBusinessCount = businessMapper.selectCount(new LambdaQueryWrapper<CrmBusinessDO>()
// .between(CrmBusinessDO::getNextTime,todayStart,todayEnd).eq(CrmBusinessDO::getOwnerUserId,loginUserId));
// Long followCluesCount = crmCluesMapper.selectCount(new LambdaQueryWrapper<CrmCluesDO>()
// .between(CrmCluesDO::getNextTime,todayStart,todayEnd).eq(CrmCluesDO::getOwnerUserId,loginUserId));
// Long contractDueCount = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
// .between(CrmContractDO::getEndTime,todayStart,day30).eq(CrmContractDO::getOwnerUserId,loginUserId));
// Long customerDueCount = 0L;
// Long contractReturnCount = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
// .eq(CrmContractDO::getOwnerUserId,loginUserId).apply("money > return_money"));
// Long myInvoiceCount = crmInvoiceMapper.selectCount(new LambdaQueryWrapper<CrmInvoiceDO>()
// .eq(CrmInvoiceDO::getCreator,loginUserId));
// Long productCount = storeProductMapper.selectCount();
//
// Long contractCheckCount = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
// .apply( "FIND_IN_SET ('" + loginUserId + "',flow_admin_id)"));
// Long receivablesCheckCount = contractReceivablesMapper.selectCount(new LambdaQueryWrapper<CrmContractReceivablesDO>()
// .apply( "FIND_IN_SET ('" + loginUserId + "',flow_admin_id)"));
// Long invoiceCheckCount = crmInvoiceMapper.selectCount(new LambdaQueryWrapper<CrmInvoiceDO>()
// .apply( "FIND_IN_SET ('" + loginUserId + "',flow_admin_id)"));
return CrmIndexRespVO.builder()
.followCustomerCount(followCustomerCount)
.followBusinessCount(followBusinessCount)
.followCluesCount(followCluesCount)
.contractDueCount(contractDueCount)
.customerDueCount(customerDueCount)
.contractReturnCount(contractReturnCount)
.myInvoiceCount(myInvoiceCount)
.productCount(productCount)
.contractCheckCount(contractCheckCount)
.receivablesCheckCount(receivablesCheckCount)
.invoiceCheckCount(invoiceCheckCount)
.brieCountVO(getBrieCount())
// .followCustomerCount(followCustomerCount)
// .followBusinessCount(followBusinessCount)
// .followCluesCount(followCluesCount)
// .contractDueCount(contractDueCount)
// .customerDueCount(customerDueCount)
// .contractReturnCount(contractReturnCount)
// .myInvoiceCount(myInvoiceCount)
// .productCount(productCount)
// .contractCheckCount(contractCheckCount)
// .receivablesCheckCount(receivablesCheckCount)
// .invoiceCheckCount(invoiceCheckCount)
.brieCountVO(getBrieCount(relation))
.build();
}
@ -116,39 +116,142 @@ public class CrmIndexServiceImpl implements CrmIndexService {
*
* @return
*/
private BrieCountVO getBrieCount() {
private BrieCountVO getBrieCount(String relation) {
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
Date todayStart = DateUtil.beginOfDay(new Date());
Date todayEnd = DateUtil.endOfDay(new Date());
Date yesterdayStart = DateUtil.beginOfDay(DateUtil.yesterday());
Date yesterdayEnd = DateUtil.endOfDay(DateUtil.yesterday());
List<Long> ids = new ArrayList<>();
Long adminId = SecurityFrameworkUtils.getLoginUserId();
if (RelationEnum.MY.getValue().equals(relation)) {
ids.add(adminId);
} else if (RelationEnum.SUB.getValue().equals(relation)) {
ids = adminUserApi.getUserListBySubordinateIds(adminId).getCheckedData();
}
Long count01 = businessMapper.selectCount(new LambdaQueryWrapper<CrmBusinessDO>()
.between(CrmBusinessDO::getCreateTime, todayStart, todayEnd).eq(CrmBusinessDO::getCreator, loginUserId));
.in(!ids.isEmpty(), CrmBusinessDO::getOwnerUserId, ids)
.between(CrmBusinessDO::getCreateTime, todayStart, todayEnd));
Long count001 = businessMapper.selectCount(new LambdaQueryWrapper<CrmBusinessDO>()
.in(!ids.isEmpty(), CrmBusinessDO::getOwnerUserId, ids)
.between(CrmBusinessDO::getCreateTime, yesterdayStart, yesterdayEnd));
String per001 = "0";
if (count001 > 0) {
per001 = NumberUtil.div(NumberUtil.sub(count01, count001), count001, 2)
.multiply(new BigDecimal("100")).toString();
}
Long count02 = crmCluesMapper.selectCount(new LambdaQueryWrapper<CrmCluesDO>()
.between(CrmCluesDO::getCreateTime, todayStart, todayEnd).eq(CrmCluesDO::getCreator, loginUserId));
.in(!ids.isEmpty(), CrmCluesDO::getOwnerUserId, ids)
.between(CrmCluesDO::getCreateTime, todayStart, todayEnd));
Long count002 = crmCluesMapper.selectCount(new LambdaQueryWrapper<CrmCluesDO>()
.in(!ids.isEmpty(), CrmCluesDO::getOwnerUserId, ids)
.between(CrmCluesDO::getCreateTime, yesterdayStart, yesterdayEnd));
String per002 = "0";
if (count002 > 0) {
per002 = NumberUtil.div(NumberUtil.sub(count02, count002), count002, 2)
.multiply(new BigDecimal("100")).toString();
}
Long count03 = customerMapper.selectCount(new LambdaQueryWrapper<CrmCustomerDO>()
.between(CrmCustomerDO::getCreateTime, todayStart, todayEnd).eq(CrmCustomerDO::getCreator, loginUserId));
.in(!ids.isEmpty(), CrmCustomerDO::getOwnerUserId, ids)
.between(CrmCustomerDO::getCreateTime, todayStart, todayEnd));
Long count003 = customerMapper.selectCount(new LambdaQueryWrapper<CrmCustomerDO>()
.in(!ids.isEmpty(), CrmCustomerDO::getOwnerUserId, ids)
.between(CrmCustomerDO::getCreateTime, yesterdayStart, yesterdayEnd));
String per003 = "0";
if (count003 > 0) {
per003 = NumberUtil.div(NumberUtil.sub(count03, count003), count003, 2)
.multiply(new BigDecimal("100")).toString();
}
Long count04 = crmRecordMapper.selectCount(new LambdaQueryWrapper<CrmRecordDO>()
.between(CrmRecordDO::getCreateTime, todayStart, todayEnd).eq(CrmRecordDO::getCreator, loginUserId));
.in(!ids.isEmpty(), CrmRecordDO::getCreator, ids)
.between(CrmRecordDO::getCreateTime, todayStart, todayEnd));
Long count004 = crmRecordMapper.selectCount(new LambdaQueryWrapper<CrmRecordDO>()
.in(!ids.isEmpty(), CrmRecordDO::getCreator, ids)
.between(CrmRecordDO::getCreateTime, yesterdayStart, yesterdayEnd));
String per004 = "0";
if (count004 > 0) {
per004 = NumberUtil.div(NumberUtil.sub(count04, count004), count004, 2)
.multiply(new BigDecimal("100")).toString();
}
Long count05 = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
.between(CrmContractDO::getCreateTime, todayStart, todayEnd).eq(CrmContractDO::getCreator, loginUserId));
.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");
queryWrapper06.eq("to_days(create_time)", "to_days(now())");
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();
}
Long count08 = customerContactsMapper.selectCount(new LambdaQueryWrapper<CrmCustomerContactsDO>()
.between(CrmCustomerContactsDO::getCreateTime, todayStart, todayEnd)
.eq(CrmCustomerContactsDO::getCreator, loginUserId));
.in(!ids.isEmpty(), CrmCustomerContactsDO::getOwnerUserId, ids)
.between(CrmCustomerContactsDO::getCreateTime, todayStart, todayEnd));
Long count008 = customerContactsMapper.selectCount(new LambdaQueryWrapper<CrmCustomerContactsDO>()
.in(!ids.isEmpty(), CrmCustomerContactsDO::getOwnerUserId, ids)
.between(CrmCustomerContactsDO::getCreateTime, yesterdayStart, yesterdayEnd));
String per008 = "0";
if (count008 > 0) {
per008 = NumberUtil.div(NumberUtil.sub(count08, count008), count008, 2)
.multiply(new BigDecimal("100")).toString();
}
Long count09 = customerMapper.selectCount(new LambdaQueryWrapper<CrmCustomerDO>()
.between(CrmCustomerDO::getDealTime, todayStart, todayEnd)
.eq(CrmCustomerDO::getDealStatus, ShopCommonEnum.IS_STATUS_1.getValue())
@ -169,16 +272,15 @@ public class CrmIndexServiceImpl implements CrmIndexService {
.setStatus(CommonStatusEnum.ENABLE.getStatus())
.setBeginTime(todayStart)
.setEndTime(todayEnd)).getCheckedData();
return BrieCountVO.builder()
.count01(count01)
.count02(count02)
.count03(count03)
.count04(count04)
.count05(count05)
.count06(count06)
.count07(count07)
.count08(count08)
.count01(count01).count001(count001).per001(per001)
.count02(count02).count002(count002).per002(per002)
.count03(count03).count003(count003).per003(per003)
.count04(count04).count004(count004).per004(per004)
.count05(count05).count005(count005).per005(per005)
.count06(count06).count006(count006).per006(per006)
.count07(count07).count007(count007).per007(per007)
.count08(count08).count008(count008).per008(per008)
.count09(count09)
.count10(count10)
.count11(count11)

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.service.crminvoice;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@ -23,6 +24,8 @@ import cn.iocoder.yudao.module.crm.dal.mysql.crmflow.CrmFlowStepMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmflowlog.CrmFlowLogMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crminvoice.CrmInvoiceMapper;
import cn.iocoder.yudao.module.hrm.enums.*;
import cn.iocoder.yudao.module.system.api.mail.MailSendApi;
import cn.iocoder.yudao.module.system.api.mail.dto.MailSendSingleReqDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
@ -35,7 +38,9 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.*;
@ -66,6 +71,8 @@ public class CrmInvoiceServiceImpl implements CrmInvoiceService {
private RedissonClient redissonClient;
@Resource
private CrmFlowLogMapper crmFlowLogMapper;
@Resource
private MailSendApi mailSendApi;
private static final String LOCK_KEY = "invoice:check:lock";
@ -294,5 +301,13 @@ public class CrmInvoiceServiceImpl implements CrmInvoiceService {
crmContractDO.setInvoiceMoney(money);
contractMapper.updateById(crmContractDO);
//发送邮件
if(StrUtil.isNotEmpty(updateObj.getFiles()) && StrUtil.isNotEmpty(updateObj.getEmail())){
Map<String, Object> templateParams = new HashMap<>();
templateParams.put("files",updateObj.getFiles());
mailSendApi.sendSingleMail(new MailSendSingleReqDTO()
.setMail(updateObj.getEmail()).setUserId(updateObj.getCustomerId()).setUserType(UserTypeEnum.CUSTOMER.getValue())
.setTemplateCode("invoice-send").setTemplateParams(templateParams));
}
}
}

View File

@ -1,11 +1,14 @@
package cn.iocoder.yudao.module.crm.service.crmoperatelog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.crm.controller.admin.crmoperatelog.vo.CrmOperatelogPageReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmoperatelog.CrmOperatelogDO;
import cn.iocoder.yudao.module.crm.dal.mysql.crmoperatelog.CrmOperatelogMapper;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@ -22,10 +25,19 @@ public class CrmOperatelogServiceImpl implements CrmOperatelogService {
@Resource
private CrmOperatelogMapper crmOperatelogMapper;
@Resource
private AdminUserApi adminUserApi;
@Override
public void createLog(String title, Long customerId, Long contractId, Long receivableId) {
String nickname = "";
if (SecurityFrameworkUtils.getLoginUser() != null) {
CommonResult<AdminUserRespDTO> result = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUser().getId());
if (result.isSuccess() && result.getCheckedData() != null) {
nickname = result.getCheckedData().getNickname();
}
}
CrmOperatelogDO crmOperatelogDO = CrmOperatelogDO.builder()
.title(title)
.customerId(customerId)
@ -34,8 +46,8 @@ public class CrmOperatelogServiceImpl implements CrmOperatelogService {
.ip(ServletUtils.getClientIP())
.useragent(ServletUtils.getUserAgent())
.url(ServletUtils.getUrl())
.nickname(SecurityFrameworkUtils.getLoginUser().getInfo().get("nickname"))
.username(SecurityFrameworkUtils.getLoginUser().getInfo().get("nickname"))
.nickname(nickname)
.username(nickname)
.build();
crmOperatelogMapper.insert(crmOperatelogDO);

View File

@ -19,7 +19,7 @@
from crm_contract as a
left join crm_customer as t3 on t3.id = a.customer_id
left join system_users as t1 on a.order_admin_id = t1.id
left join system_users as t2 on a.creator = t1.id
left join system_users as t2 on a.creator = t2.id
<where>
a.deleted = 0
and t1.deleted = 0

View File

@ -31,7 +31,7 @@ public class StoreProductAttrValueApiImpl implements StoreProductAttrValueApi {
public CommonResult<List<StoreProductAttrValueApiVO>> getStoreProductAttrValueList(StoreProductAttrValueApiDTO dto) {
List<StoreProductAttrValueDO> list = storeProductAttrValueService.list(new LambdaQueryWrapper<StoreProductAttrValueDO>()
.in(CollUtil.isNotEmpty(dto.getProductIds()), StoreProductAttrValueDO::getProductId, dto.getProductIds())
.eq(CollUtil.isNotEmpty(dto.getUniques()), StoreProductAttrValueDO::getUnique, dto.getUniques())
.in(CollUtil.isNotEmpty(dto.getUniques()), StoreProductAttrValueDO::getUnique, dto.getUniques())
);
List<StoreProductAttrValueApiVO> result = BeanUtil.copyToList(list, StoreProductAttrValueApiVO.class);
return CommonResult.success(result);

View File

@ -115,5 +115,5 @@ public interface AdminUserApi {
@GetMapping(PREFIX + "/getUserListBySubordinateIds")
@Operation(summary = "获取当前部门以及下级部门所有人员(负责人)")
CommonResult<List<Long>> getUserListBySubordinateIds(Long adminId);
CommonResult<List<Long>> getUserListBySubordinateIds(@RequestParam(name = "adminId") Long adminId);
}

View File

@ -11,12 +11,12 @@ import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPage
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataRespVO;
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSimpleRespVO;
import cn.iocoder.yudao.module.system.controller.app.dict.vo.AppDictDataVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
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.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -101,4 +101,12 @@ public class DictDataController {
BeanUtils.toBean(list, DictDataRespVO.class));
}
@GetMapping("/type")
@Operation(summary = "根据字典类型查询字典数据信息")
@Parameter(name = "type", description = "字典类型", required = true, example = "common_status")
public CommonResult<List<AppDictDataVO>> getDictDataListByType(@RequestParam("type") String type) {
List<DictDataDO> list = dictDataService.getDictDataList(
CommonStatusEnum.ENABLE.getStatus(), type);
return success(BeanUtils.toBean(list, AppDictDataVO.class));
}
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.controller.app.dict.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AppDictDataVO {
@Schema(description = "字典数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
@JsonProperty("name")
private String label;
@Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder")
private String value;
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex")
private String dictType;
}