Compare commits

...

7 Commits

Author SHA1 Message Date
aikai
521a162233 refactor(crm): 为 CrmCustomerSaveReqVO 类中的 repeatConfirmationFlag 字段添加默认值0 2025-03-13 15:23:41 +08:00
aikai
92850e2d12 feat(crm): 添加线索跟进任务并优化客户导入功能
- 新增线索跟进任务定时 job,自动更新三天未跟进的线索状态- 优化客户导入功能,增加重复客户检测和提示
- 添加合同编号字段到发票响应 VO- 修改合同列表获取逻辑,支持下属和自己的合同查询
-优化发票列表查询,支持关系筛选
- 新增商机状态更新接口
2025-03-13 15:20:39 +08:00
aikai
32309d2842 Merge branch 'dev' of http://git.znkjfw.com/ak/zn-cloud into crm-业绩目标 2025-03-11 10:15:17 +08:00
aikai
b532e46a1e refactor(crm): 移除客户导入中未使用的地理位置和消费 2025-03-10 17:26:21 +08:00
aikai
1f65ca883c refactor(bpm): 重构回款结算接口并添加客户转移功能
- 重构了 BpmOAReceiptService 接口,使用 ReceiptSettlementVO 替代 LocalDateTime[] 参数
- 添加了客户转移相关的 API 和服务实现
- 优化了销售业绩结算相关的数据结构和接口
- 调整了权限控制相关的配置
2025-03-10 16:41:14 +08:00
aikai
f3f91f7350 Merge branch 'dev' of http://git.znkjfw.com/ak/zn-cloud into crm-业绩目标
# Conflicts:
#	yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAReceiptMapper.java
#	yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java
#	yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReceiptServiceImpl.java
2025-03-06 17:55:06 +08:00
aikai
7f474c33cb feat(bpm): 新增销售业绩目标申请OA功能
- 添加销售业绩目标申请相关的API接口和实现类
- 创建销售业绩目标申请的数据库表和DO类
- 实现销售业绩目标申请的CRUD操作
- 添加销售业绩目标申请的前端页面和表单组件
2025-03-06 17:51:33 +08:00
118 changed files with 3758 additions and 225 deletions

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.common.template;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.SocialTypeEnum;
import cn.iocoder.yudao.framework.common.template.dto.ApprovalResultNotificationMessageDTO;
import cn.iocoder.yudao.framework.common.template.dto.PerformanceResultConfirmationReminderDTO;
import cn.iocoder.yudao.framework.common.template.dto.ProcessToDoReminderDTO;
import cn.iocoder.yudao.framework.common.template.vo.MsgData;
import cn.iocoder.yudao.framework.common.template.vo.SubscribeMessageReqDTO;
@ -22,6 +23,10 @@ public class WxMpMsgTemplateUtils {
* OA流程待办提醒
*/
String OA_PROCESS_TO_DO_REMINDER = "rV94N8PbUOz4EQyjpJcucPQOTrBPx2icOZ5F2KNgD40";
/**
* 绩效结果确认提醒
*/
String PERFORMANCE_RESULT_CONFIRMATION_REMINDER = "56VcBVdG__KGmYQzq2q3KUbijUlKwz6KaaK0mzfPQtc";
/**
@ -115,4 +120,33 @@ public class WxMpMsgTemplateUtils {
return message;
}
/**
* 绩效结果确认提醒
*
* @param dto
* @return
*/
public SubscribeMessageReqDTO convertPerformanceResultConfirmationReminder(PerformanceResultConfirmationReminderDTO dto) {
SubscribeMessageReqDTO message = new SubscribeMessageReqDTO();
message.setToUser(dto.getOpenId());
message.setTemplateId(PERFORMANCE_RESULT_CONFIRMATION_REMINDER);
//待办标题
MsgData processType = new MsgData();
processType.setName("thing1");
processType.setValue(dto.getUserName());
message.addData(processType);
//申请人
MsgData applicant = new MsgData();
applicant.setName("time2");
applicant.setValue(dto.getTime());
message.addData(applicant);
message.setJumpWxMaFlag(true);
message.setMiniProgramState(dto.getMiniProgramState());
message.setPage(dto.getPage());
message.setSocialType(SocialTypeEnum.WECHAT_MINI_APP_CRM.getType());
return message;
}
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.framework.common.template.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class PerformanceResultConfirmationReminderDTO {
@Schema(description = "接收者(用户)的 openid")
private String openId;
@Schema(description = "被考核人")
private String userName;
@Schema(description = "考核时间")
private String time;
@Schema(description = "跳转小程序类型")
private String miniProgramState = "formal";
@Schema(description = "小程序页面地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "pages/home/index")
private String page;
}

View File

@ -0,0 +1,322 @@
package cn.iocoder.yudao.framework.common.util.number;
import cn.hutool.core.util.StrUtil;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
* @Desc:
* @Author: aikai
* @Date: 2025/04/11
*/
public class BigDecimalUtil {
// 默认除法运算精度
private static final int DEF_DIV_SCALE = 2;
private static final BigDecimal ZERO = new BigDecimal(0);
// 这个类不能实例化
private BigDecimalUtil() {
}
// 是否大于0
public static boolean isGreaterThanZero(Object value) {
if (null == value) {
value = BigDecimal.ZERO;
}
return getBigDecimal(value).compareTo(ZERO) > 0;
}
// 是否大于0
public static boolean isGreaterThanOrEqualToZero(Object value) {
if (null == value) {
value = BigDecimal.ZERO;
}
return getBigDecimal(value).compareTo(ZERO) >= 0;
}
// 是否小于0
public static boolean isLessThanZero(Object value) {
if (null == value) {
value = BigDecimal.ZERO;
}
return getBigDecimal(value).compareTo(ZERO) < 0;
}
// 是否小于等于0
public static boolean isLessThanOrEqualToZero(Object value) {
if (null == value) {
value = BigDecimal.ZERO;
}
return getBigDecimal(value).compareTo(ZERO) <= 0;
}
// 是否大于
public static boolean isGreaterThan(Object v1, Object v2) {
if (null == v1) {
v1 = BigDecimal.ZERO;
}
if (null == v2) {
v2 = BigDecimal.ZERO;
}
return getBigDecimal(v1).compareTo(getBigDecimal(v2)) > 0;
}
// 是否大于等于
public static boolean isGreaterThanOrEqualTo(Object v1, Object v2) {
if (null == v1) {
v1 = BigDecimal.ZERO;
}
if (null == v2) {
v2 = BigDecimal.ZERO;
}
return getBigDecimal(v1).compareTo(getBigDecimal(v2)) >= 0;
}
// 是否小于
public static boolean isLessThan(Object v1, Object v2) {
if (null == v1) {
v1 = BigDecimal.ZERO;
}
if (null == v2) {
v2 = BigDecimal.ZERO;
}
return getBigDecimal(v1).compareTo(getBigDecimal(v2)) < 0;
}
// 是否小于等于
public static boolean isLessThanOrEqualTo(Object v1, Object v2) {
if (null == v1) {
v1 = BigDecimal.ZERO;
}
if (null == v2) {
v2 = BigDecimal.ZERO;
}
return getBigDecimal(v1).compareTo(getBigDecimal(v2)) <= 0;
}
// 是否等于
public static boolean isEqualTo(Object v1, Object v2) {
if (null == v1) {
v1 = BigDecimal.ZERO;
}
if (null == v2) {
v2 = BigDecimal.ZERO;
}
BigDecimal var1 = getBigDecimal(v1);
BigDecimal var2 = getBigDecimal(v2);
return var1.compareTo(var2) == 0;
}
public static boolean isEqZero(Object v1) {
if (null == v1) {
v1 = BigDecimal.ZERO;
}
BigDecimal var1 = getBigDecimal(v1);
return var1.compareTo(BigDecimal.ZERO) == 0;
}
// 是否为空 /
public static boolean isEmpty(Object obj) {
if (null == obj) {
return true;
}
if (isEqualTo(BigDecimal.ZERO, obj)) {
return true;
}
return false;
}
public static boolean isNotEmpty(Object obj) {
if (null == obj) {
return false;
}
if (isEqualTo(BigDecimal.ZERO, obj)) {
return false;
}
return true;
}
/**
* 提供精确的加法运算
*
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/
public static BigDecimal add(Object v1, Object v2) {
if (null == v1) {
v1 = BigDecimal.ZERO;
}
if (null == v2) {
v2 = BigDecimal.ZERO;
}
return getBigDecimal(v1).add(getBigDecimal(v2));
}
/**
* 提供精确的减法运算
*
* @param v1 被减数
* @param v2 减数
* @return 两个参数的差
*/
public static BigDecimal sub(Object v1, Object v2) {
if (null == v1) {
v1 = BigDecimal.ZERO;
}
if (null == v2) {
v2 = BigDecimal.ZERO;
}
return getBigDecimal(v1).subtract(getBigDecimal(v2));
}
/**
* 提供精确的乘法运算
*
* @param v1 被乘数
* @param v2 乘数
* @return 两个参数的积
*/
public static BigDecimal mul(Object v1, Object v2) {
if (null == v1) {
v1 = BigDecimal.ZERO;
}
if (null == v2) {
v2 = BigDecimal.ZERO;
}
return getBigDecimal(v1).multiply(getBigDecimal(v2));
}
/**
* 提供精确的乘法运算
*
* @param v1
* @param arg
* @return 多数
*/
public static BigDecimal mostMul(Object v1, Object... arg) {
if (v1 == null) {
v1 = BigDecimal.ZERO;
}
for (Object obj : arg) {
if (obj == null) {
obj = BigDecimal.ZERO;
}
v1 = getBigDecimal(v1).multiply(getBigDecimal(obj));
}
return (BigDecimal) v1;
}
/**
* 提供相对精确的除法运算当发生除不尽的情况时 精确到小数点以后10位以后的数字四舍五入
*
* @param v1 被除数
* @param v2 除数
* @return 两个参数的商
*/
public static BigDecimal div(Object v1, Object v2) {
return div(getBigDecimal(v1), getBigDecimal(v2), DEF_DIV_SCALE);
}
/**
* 提供相对精确的除法运算 当发生除不尽的情况时由scale参数指定精度以后的数字四舍五入
*
* @param v1 被除数
* @param v2 除数
* @param scale 表示表示需要精确到小数点以后几位
* @return 两个参数的商
*/
public static BigDecimal div(Object v1, Object v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
return getBigDecimal(v1).divide(getBigDecimal(v2), scale, BigDecimal.ROUND_HALF_UP);
}
public static BigDecimal div(Object v1, Object v2, int scale, int roundingMode) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
return getBigDecimal(v1).divide(getBigDecimal(v2), scale, roundingMode);
}
/**
* Object转BigDecimal类型
*
* @param value 要转的object类型
* @return 转成的BigDecimal类型数据
*/
public static BigDecimal getBigDecimal(Object value) {
BigDecimal ret = null;
if (value != null) {
if (value instanceof BigDecimal) {
ret = (BigDecimal) value;
} else if (value instanceof String) {
if (StrUtil.isEmpty((String) value)) {
value = "0";
}
ret = new BigDecimal((String) value);
} else if (value instanceof BigInteger) {
ret = new BigDecimal((BigInteger) value);
} else if (value instanceof Number) {
ret = new BigDecimal(value.toString());
} else if (value instanceof Integer) {
ret = new BigDecimal((Integer) value);
} else {
throw new ClassCastException("Not possible to coerce [" + value + "] from class " + value.getClass() + " into a BigDecimal.");
}
} else {
return BigDecimal.ZERO;
}
return ret;
}
/**
*
*
* @param i
* @param arg
* @return
*/
public static BigDecimal subs(BigDecimal i, BigDecimal... arg) {
BigDecimal difference = i;
for (BigDecimal b : arg) {
difference = difference.subtract(b);
}
return difference;
}
public static BigDecimal getZeroMax(BigDecimal bigDecimal) {
if (isLessThanZero(bigDecimal)) {
return ZERO;
}
return bigDecimal;
}
/**
*
*
* @param i
* @param arg
* @return
*/
public static BigDecimal adds(BigDecimal i, BigDecimal... arg) {
BigDecimal bigDecimal = i;
if (bigDecimal == null) {
bigDecimal = BigDecimal.ZERO;
}
for (BigDecimal b : arg) {
if (b == null) {
b = BigDecimal.ZERO;
}
bigDecimal = bigDecimal.add(b);
}
return bigDecimal;
}
}

View File

@ -16,7 +16,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Tag(name = "RPC 服务 - 流程实例")
@ -41,4 +40,8 @@ public interface BpmOAContractApi {
@PostMapping(PREFIX + "/getList")
@Operation(summary = "获得合同列表")
CommonResult<List<BpmOAContractDTO>> getContractList(@RequestBody BpmOAContractVO respVO);
@PostMapping(PREFIX + "/updateSettlementFlagByIds")
@Operation(summary = "批量更新合同结算状态")
void updateSettlementFlagByIds(@RequestBody List<Long> contractIds);
}

View File

@ -1,9 +1,7 @@
package cn.iocoder.yudao.module.bpm.api.oa;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
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.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.*;
import cn.iocoder.yudao.module.bpm.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -33,5 +31,9 @@ public interface BpmOAReceiptApi {
@GetMapping(PREFIX + "/get-receipt-statistics")
@Operation(summary = "获得指定用户的回款统计信息")
CommonResult<List<ReceiptStatisticsDTO>> getContractStatistics(@RequestParam("userId") List<Long> userIds,
@RequestParam(name = "createTime", required = false) LocalDateTime[] createTime);
@RequestParam(name = "createTime", required = false) LocalDateTime[] createTime);
@PostMapping(PREFIX + "/getReceiptSettlement")
@Operation(summary = "获取用户回款结算信息")
CommonResult<List<ReceiptSettlementDTO>> getReceiptSettlement(@RequestBody ReceiptSettlementVO vo);
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.bpm.api.oa;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.bpm.api.oa.vo.salesperformance.SalesPerformanceDTO;
import cn.iocoder.yudao.module.bpm.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
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.RequestParam;
import java.util.List;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Tag(name = "RPC 服务 - 销售目标")
public interface BpmOASalesPerformanceApi {
String PREFIX = ApiConstants.PREFIX + "/oa/salesPerformance";
@GetMapping(PREFIX + "/getSalesPerformance")
@Operation(summary = "根据日期获取用户销售目标申请")
CommonResult<List<SalesPerformanceDTO>> getReceiptSettlement(@RequestParam(name = "year", required = false) String year,
@RequestParam(name = "month", required = false) String month);
@GetMapping(PREFIX + "/getBySalesPerformanceId")
@Operation(summary = "根据日期获取用户销售目标申请")
CommonResult<SalesPerformanceDTO> getBySalesPerformanceId(@RequestParam(name = "salesPerformanceId", required = false) Long salesPerformanceId);
}

View File

@ -0,0 +1,15 @@
package cn.iocoder.yudao.module.bpm.api.oa.vo.receipt;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class ReceiptSettlementDTO {
@Schema(description = "用户编号")
private Long userId;
@Schema(description = "回款总金额")
private BigDecimal money;
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.bpm.api.oa.vo.receipt;
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.math.BigDecimal;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Data
@ToString(callSuper = true)
public class ReceiptSettlementVO {
@Schema(description = "时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.bpm.api.oa.vo.salesperformance;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class SalesPerformanceDTO {
/**
* 销售业绩目标申请id
*/
private Long id;
/**
* 申请人的用户编号
*/
private Long userId;
/**
*
*/
private String year;
/**
*
*/
private String month;
/**
* 回款目标
*/
private BigDecimal paymentTarget;
/**
* 销售目标
*/
private Integer saleTarget;
/**
* 备注
*/
private String remark;
/**
* 申请结果
*/
private Integer result;
}

View File

@ -117,6 +117,10 @@ public interface ErrorCodeConstants {
// ========== 用户组模块 1-009-011-000 ==========
ErrorCode USER_GROUP_NOT_EXISTS = new ErrorCode(1_009_011_000, "用户组不存在");
ErrorCode USER_GROUP_IS_DISABLE = new ErrorCode(1_009_011_001, "名字为【{}】的用户组已被禁用");
// ========== 业绩申请模块 1-009-012-000 ==========
ErrorCode CAN_ONLY_APPLY_FOR_CURRENT_MONTH_PERFORMANCE_TARGET = new ErrorCode(1_009_012_001, "只能申请当月业绩目标");
ErrorCode THE_PROCESS_IS_BEING_APPROVED_OR_HAS_PASSED_THE_CURRENT_MONTH_AND_THE_APPLICATION_CANNOT_BE_REPEATED
= new ErrorCode(1_009_012_002, "流程审批中或已通过当月不可重复申请");
ErrorCode BPM_SYSTEM_BUG = new ErrorCode(1_009_012_001, "系统问题,请联系管理员");

View File

@ -52,4 +52,9 @@ public class BpmOAContractApiImpl implements BpmOAContractApi {
List<BpmOAContractDO> contractDO = contractService.getContractList(respVO);
return success(BeanUtils.toBean(contractDO, BpmOAContractDTO.class));
}
@Override
public void updateSettlementFlagByIds(List<Long> contractIds) {
contractService.updateSettlementFlagByIds(contractIds);
}
}

View File

@ -2,13 +2,12 @@ package cn.iocoder.yudao.module.bpm.api.oa;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
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.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.*;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.ReceiptStatisticsVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReceiptDO;
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReceiptService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@ -45,4 +44,9 @@ public class BpmOAReceiptApiImpl implements BpmOAReceiptApi{
List<ReceiptStatisticsDTO> respVOS = receiptService.getReceiptStatisticsListByUserIds(userIds, createTime);
return success(BeanUtils.toBean(respVOS, ReceiptStatisticsDTO.class));
}
@Override
public CommonResult<List<ReceiptSettlementDTO>> getReceiptSettlement(ReceiptSettlementVO vo) {
return success(receiptService.getReceiptSettlement(vo));
}
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.bpm.api.oa;
import cn.hutool.core.bean.BeanUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.bpm.api.oa.vo.salesperformance.SalesPerformanceDTO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalesPerformanceDO;
import cn.iocoder.yudao.module.bpm.service.oa.BpmOASalesPerformanceService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* Flowable 流程实例 Api 实现类
*/
@RestController
@Validated
public class BpmOASalesPerformanceApiImpl implements BpmOASalesPerformanceApi {
@Resource
private BpmOASalesPerformanceService salesPerformanceService;
@Override
public CommonResult<List<SalesPerformanceDTO>> getReceiptSettlement(String year, String month) {
List<BpmOASalesPerformanceDO> list = salesPerformanceService.list(new LambdaQueryWrapper<BpmOASalesPerformanceDO>()
.eq(BpmOASalesPerformanceDO::getYear, year)
.eq(BpmOASalesPerformanceDO::getMonth, month)
.eq(BpmOASalesPerformanceDO::getResult, 2));
return CommonResult.success(BeanUtil.copyToList(list, SalesPerformanceDTO.class));
}
@Override
public CommonResult<SalesPerformanceDTO> getBySalesPerformanceId(Long salesPerformanceId) {
BpmOASalesPerformanceDO item = salesPerformanceService.getById(salesPerformanceId);
return CommonResult.success(BeanUtil.copyProperties(item, SalesPerformanceDTO.class));
}
}

View File

@ -37,7 +37,6 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
* OA 合同审批 Controller
*
* @author 符溶馨
*/
@Tag(name = "管理后台 - OA 合同审批")
@RestController
@ -68,7 +67,6 @@ public class BpmOAContractController {
@Operation(summary = "获得合同审批")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
public CommonResult<BpmOAContractRespVO> getContract(@RequestParam("id") Long id) {
BpmOAContractDO contract = contractService.getContract(id);
BpmOAContractRespVO respVO = BpmOAContractConvert.INSTANCE.convert(contract);
if (respVO != null) {
@ -137,15 +135,12 @@ public class BpmOAContractController {
return success(contractService.getContractPage(pageReqVO));
}
@GetMapping("/getListByDeptId")
@Operation(summary = "获得同部门的销售合同")
public CommonResult<List<BpmOAContractRespVO>> getListByDeptId() {
// 获取同部门所有用户id
List<Long> userIds = userApi.getUserIdsByUserIdGroupByDept(getLoginUserId()).getCheckedData();
List<BpmOAContractDO> contracts = contractService.getListByDeptId(userIds);
@GetMapping("/getList")
@Operation(summary = "获取下属和自己的合同列表")
public CommonResult<List<BpmOAContractRespVO>> getList(@RequestParam(required = false) String relation,
@RequestParam(required = false) Integer contractType,
@RequestParam(required = false) String contractName) {
List<BpmOAContractDO> contracts = contractService.getList(relation, contractType, contractName);
return success(BeanUtils.toBean(contracts, BpmOAContractRespVO.class));
}

View File

@ -0,0 +1,74 @@
package cn.iocoder.yudao.module.bpm.controller.admin.oa;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salesperformance.SalesPerformancePageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salesperformance.SalesPerformanceRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salesperformance.SalesPerformanceSaveReqVO;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalesPerformanceDO;
import cn.iocoder.yudao.module.bpm.service.oa.BpmOASalesPerformanceService;
@Tag(name = "管理后台 - 销售业绩目标申请OA")
@RestController
@RequestMapping("/bpm/sales-performance")
@Validated
public class SalesPerformanceController {
@Resource
private BpmOASalesPerformanceService bpmOASalesPerformanceService;
@PostMapping("/create")
@Operation(summary = "创建销售业绩目标申请OA")
@PreAuthorize("@ss.hasPermission('bpm:sales-performance:create')")
public CommonResult<Long> createSalesPerformance(@Valid @RequestBody SalesPerformanceSaveReqVO createReqVO) {
return success(bpmOASalesPerformanceService.createSalesPerformance(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新销售业绩目标申请OA")
@PreAuthorize("@ss.hasPermission('bpm:sales-performance:update')")
public CommonResult<Boolean> updateSalesPerformance(@Valid @RequestBody SalesPerformanceSaveReqVO updateReqVO) {
bpmOASalesPerformanceService.updateSalesPerformance(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除销售业绩目标申请OA")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('bpm:sales-performance:delete')")
public CommonResult<Boolean> deleteSalesPerformance(@RequestParam("id") Long id) {
bpmOASalesPerformanceService.deleteSalesPerformance(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得销售业绩目标申请OA")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('bpm:sales-performance:query')")
public CommonResult<SalesPerformanceRespVO> getSalesPerformance(@RequestParam("id") Long id) {
BpmOASalesPerformanceDO salesPerformance = bpmOASalesPerformanceService.getSalesPerformance(id);
return success(BeanUtils.toBean(salesPerformance, SalesPerformanceRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得销售业绩目标申请OA分页")
@PreAuthorize("@ss.hasPermission('bpm:sales-performance:query')")
public CommonResult<PageResult<SalesPerformanceRespVO>> getSalesPerformancePage(@Valid SalesPerformancePageReqVO pageReqVO) {
PageResult<BpmOASalesPerformanceDO> pageResult = bpmOASalesPerformanceService.getSalesPerformancePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, SalesPerformanceRespVO.class));
}
}

View File

@ -26,6 +26,9 @@ public class BpmOAInvoiceRespVO extends BpmOABaseRespVO {
@Schema(description = "合同名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private String contractName;
@Schema(description = "合同编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private String contractNo;
@Schema(description = "关联合同流程实例编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private String contractInstanceId;

View File

@ -0,0 +1,46 @@
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salesperformance;
import lombok.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import java.math.BigDecimal;
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 = "管理后台 - 销售业绩目标申请OA分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SalesPerformancePageReqVO extends PageParam {
@Schema(description = "申请人的用户编号", example = "2022")
private Long userId;
@Schema(description = "")
private String year;
@Schema(description = "")
private String month;
@Schema(description = "回款目标")
private BigDecimal paymentTarget;
@Schema(description = "销售目标")
private Integer saleTarget;
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "申请结果")
private Integer result;
@Schema(description = "流程实例的编号", example = "1600")
private String processInstanceId;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,43 @@
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salesperformance;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 销售业绩目标申请OA Response VO")
@Data
public class SalesPerformanceRespVO {
@Schema(description = "销售业绩目标申请", requiredMode = Schema.RequiredMode.REQUIRED, example = "1883")
private Long id;
@Schema(description = "申请人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022")
private Long userId;
@Schema(description = "", requiredMode = Schema.RequiredMode.REQUIRED)
private String year;
@Schema(description = "", requiredMode = Schema.RequiredMode.REQUIRED)
private String month;
@Schema(description = "回款目标")
private BigDecimal paymentTarget;
@Schema(description = "销售目标")
private Integer saleTarget;
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "申请结果", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer result;
@Schema(description = "流程实例的编号", example = "1600")
private String processInstanceId;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salesperformance;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import javax.validation.constraints.*;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 销售业绩目标申请OA新增/修改 Request VO")
@Data
public class SalesPerformanceSaveReqVO {
@Schema(description = "销售业绩目标申请", requiredMode = Schema.RequiredMode.REQUIRED, example = "1883")
private Long id;
@Schema(description = "申请人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022")
private Long userId;
@Schema(description = "", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "年不能为空")
private String year;
@Schema(description = "", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "月不能为空")
private String month;
@Schema(description = "回款目标")
private BigDecimal paymentTarget;
@Schema(description = "销售目标")
private Integer saleTarget;
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "申请结果", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer result;
@Schema(description = "流程实例的编号", example = "1600")
private String processInstanceId;
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.bpm.convert.oa;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salesperformance.SalesPerformanceSaveReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalesPerformanceDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* 销售业绩目标申请OA Convert
*
* @author 艾楷
*/
@Mapper
public interface BpmOASalesPerformanceConvert {
BpmOASalesPerformanceConvert INSTANCE = Mappers.getMapper(BpmOASalesPerformanceConvert.class);
BpmOASalesPerformanceDO convert(SalesPerformanceSaveReqVO createReqVO);
}

View File

@ -134,6 +134,11 @@ public class BpmOAContractDO extends BaseDO {
*/
private Integer status;
/**
* 是否结算 0否 1是
*/
private Integer settlementFlag;
/**
* 审批结果
* 枚举 {@link BpmProcessInstanceResultEnum}

View File

@ -0,0 +1,63 @@
package cn.iocoder.yudao.module.bpm.dal.dataobject.oa;
import lombok.*;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 销售业绩目标申请OA DO
*
* @author 艾楷
*/
@TableName("bpm_oa_sales_performance")
@KeySequence("bpm_oa_sales_performance_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BpmOASalesPerformanceDO extends BaseDO {
/**
* 销售业绩目标申请
*/
@TableId
private Long id;
/**
* 申请人的用户编号
*/
private Long userId;
/**
*
*/
private String year;
/**
*
*/
private String month;
/**
* 回款目标
*/
private BigDecimal paymentTarget;
/**
* 销售目标
*/
private Integer saleTarget;
/**
* 备注
*/
private String remark;
/**
* 申请结果
*/
private Integer result;
/**
* 流程实例的编号
*/
private String processInstanceId;
}

View File

@ -16,32 +16,17 @@ import java.util.Objects;
public interface BpmOAInvoiceMapper extends BaseMapperX<BpmOAInvoiceDO> {
default PageResult<BpmOAInvoiceRespVO> selectPage(BpmOAInvoicePageReqVO pageReqVO,
Long userId) {
List<Long> userIds) {
MPJLambdaWrapperX<BpmOAInvoiceDO> query = new MPJLambdaWrapperX<>();
query.selectAll(BpmOAInvoiceDO.class);
query.selectAs(BpmOAContractDO::getContractName, BpmOAInvoiceRespVO::getContractName);
query.selectAs(BpmOAContractDO::getCustomerName, BpmOAInvoiceRespVO::getCustomerName);
query.selectAs(BpmOAContractDO::getContractNo, BpmOAInvoiceRespVO::getContractNo);
query.leftJoin(BpmOAContractDO.class, "c", BpmOAContractDO::getId, BpmOAInvoiceDO::getContractId);
query.apply(Objects.nonNull(pageReqVO.getContractName()), "c.contract_name LIKE CONCAT('%', {0}, '%')", pageReqVO.getContractName());
query.apply(Objects.nonNull(pageReqVO.getCustomerName()), "c.customer_name LIKE CONCAT('%', {0}, '%')", pageReqVO.getCustomerName());
if ("my".equals(pageReqVO.getRelation())) {
query.eq(BpmOAContractDO::getUserId, userId);
}else if ("sub".equals(pageReqVO.getRelation())){
query.innerJoin("(" +
"\tSELECT DISTINCT\n" +
"\t\tu.id \n" +
"\tFROM\n" +
"\t\tsystem_users u\n" +
"\t\tINNER JOIN system_dept d ON d.leader_user_id = "+ userId +"\n" +
"\t\tINNER JOIN system_dept d1 ON d1.flag LIKE CONCAT( '%', d.id, '-' ) \n" +
"\t\tOR d1.flag LIKE CONCAT( '%-', d.id, '-%' ) \n" +
"\t\tOR d1.flag LIKE CONCAT( '-', d.id, '%' ) \n" +
"\tWHERE\n" +
"\t\tu.dept_id = d1.id \n" +
"\t\tAND u.STATUS = 0 \n" +
"\t) subordinate ON subordinate.id = t.user_id");
}
query.in(BpmOAInvoiceDO::getUserId, userIds);
query.orderByDesc(BpmOAInvoiceDO::getCreateTime);
return selectJoinPage(pageReqVO, BpmOAInvoiceRespVO.class, query);

View File

@ -4,6 +4,8 @@ import cn.hutool.core.collection.CollUtil;
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.MPJLambdaWrapperX;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptRespVO;
@ -45,4 +47,11 @@ public interface BpmOAReceiptMapper extends BaseMapperX<BpmOAReceiptDO> {
List<ReceiptStatisticsDTO> selectReceiptStatisticsListByUserIds(@Param("userIds") List<Long> userIds,
@Param("createTime") LocalDateTime[] createTime);
/**
* 获取用户结算回款信息
*
* @return
*/
List<ReceiptSettlementDTO> getReceiptSettlement(@Param("vo") ReceiptSettlementVO vo);
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.bpm.dal.mysql.oa;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salesperformance.SalesPerformancePageReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalesPerformanceDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 销售业绩目标申请OA Mapper
*
* @author 艾楷
*/
@Mapper
public interface BpmOASalesPerformanceMapper extends BaseMapperX<BpmOASalesPerformanceDO> {
default PageResult<BpmOASalesPerformanceDO> selectPage(SalesPerformancePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<BpmOASalesPerformanceDO>()
.eqIfPresent(BpmOASalesPerformanceDO::getUserId, reqVO.getUserId())
.eqIfPresent(BpmOASalesPerformanceDO::getYear, reqVO.getYear())
.eqIfPresent(BpmOASalesPerformanceDO::getMonth, reqVO.getMonth())
.eqIfPresent(BpmOASalesPerformanceDO::getPaymentTarget, reqVO.getPaymentTarget())
.eqIfPresent(BpmOASalesPerformanceDO::getSaleTarget, reqVO.getSaleTarget())
.eqIfPresent(BpmOASalesPerformanceDO::getRemark, reqVO.getRemark())
.eqIfPresent(BpmOASalesPerformanceDO::getResult, reqVO.getResult())
.eqIfPresent(BpmOASalesPerformanceDO::getProcessInstanceId, reqVO.getProcessInstanceId())
.betweenIfPresent(BpmOASalesPerformanceDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(BpmOASalesPerformanceDO::getId));
}
}

View File

@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.hrm.api.crmbusiness.BusinessApi;
import cn.iocoder.yudao.module.hrm.api.crmcontract.ContractApi;
import cn.iocoder.yudao.module.hrm.api.crmcustomer.CrmCustomerApi;
import cn.iocoder.yudao.module.hrm.api.userlivetree.UserLiveTreeApi;
import cn.iocoder.yudao.module.hrm.api.salesperformancesettlement.SalesPerformanceSettlementApi;
import cn.iocoder.yudao.module.infra.api.config.ConfigApi;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.product.api.storeproduct.StoreProductApi;
@ -44,7 +45,7 @@ import org.springframework.context.annotation.Configuration;
SubscribeMessageSendApi.class, SocialClientApi.class, UsersExtApi.class, AttendanceApi.class, BankApi.class, ConfigApi.class, PositionApi.class, SupplierApi.class, AssetsApi.class,
AssetsTypeApi.class, AssetReceiveApi.class, AttendanceApi.class, AttendanceGroupApi.class, WorkOvertimeApi.class, HolidayApi.class,
RentalOrderApi.class, RentalDepositRecordApi.class, ProjectApi.class, RentalItemsRecordApi.class,AdminOauthUserOtherInfoApi.class, StoreProductAttrValueApi.class, StoreProductApi.class,
ContractApi.class, BusinessApi.class, CrmCustomerApi.class, StaffApi.class, LoanApi.class, FactoryInfoApi.class, UserLiveTreeApi.class
ContractApi.class, BusinessApi.class, CrmCustomerApi.class, StaffApi.class, LoanApi.class, FactoryInfoApi.class, UserLiveTreeApi.class, SalesPerformanceSettlementApi.class
})
public class RpcConfiguration {
}

View File

@ -120,4 +120,18 @@ public interface BpmOAContractService {
* @return 合同列表
*/
List<BpmOAContractDO> getListByCustomerId(Long customerId);
/**
* 批量更新合同结算状态
*
* @param contractIds
*/
void updateSettlementFlagByIds(List<Long> contractIds);
/**
* 获取下属和自己的合同列表
*
* @return
*/
List<BpmOAContractDO> getList(String relation, Integer contractType, String contractName);
}

View File

@ -2,9 +2,7 @@ package cn.iocoder.yudao.module.bpm.service.oa;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@ -18,6 +16,7 @@ import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAContractMapper;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.hrm.api.crmbusiness.BusinessApi;
import cn.iocoder.yudao.module.hrm.api.crmcontract.ContractApi;
import cn.iocoder.yudao.module.hrm.api.crmcontract.dto.CrmContractProductDTO;
import cn.iocoder.yudao.module.hrm.api.crmcustomer.CrmCustomerApi;
@ -25,12 +24,11 @@ import cn.iocoder.yudao.module.hrm.api.crmcustomer.dto.CrmCustomerDTO;
import cn.iocoder.yudao.module.hrm.api.userlivetree.UserLiveTreeApi;
import cn.iocoder.yudao.module.product.api.storeproduct.StoreProductApi;
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.StoreProductAttrValueApi;
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.dto.StoreProductAttrValueApiDTO;
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.vo.StoreProductAttrValueApiVO;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.runtime.ProcessInstance;
@ -106,7 +104,8 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
@Resource
private CrmCustomerApi customerApi;
@Resource
private BusinessApi businessApi;
@Resource
private UserLiveTreeApi userLiveTreeApi;
@ -205,13 +204,15 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
ProcessInstance instance = processInstanceService.getProcessInstance(processInstanceId);
if (instance.isEnded()) {
// 审批通过后更新客户成交信息
customerApi.updateCustomerPurchaseTotal(new CrmCustomerDTO()
.setId(contract.getCustomerId())
.setDealStatus(ShopCommonEnum.IS_STATUS_1.getValue())
.setDealTime(LocalDateTime.now())
.setPurchaseTotal(contract.getContractMoney()));
// 审批通过后更新商机状态
businessApi.updateIsEnd(contract.getBusinessId(), ShopCommonEnum.IS_STATUS_1.getValue());
}
}
@ -271,11 +272,13 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
List<Long> userIds = new ArrayList<>();
if ("my".equals(pageReqVO.getRelation())) {
userIds.add(getLoginUserId());
}else if ("sub".equals(pageReqVO.getRelation())){
} else if ("sub".equals(pageReqVO.getRelation())) {
// 查询当前用户 所有下级用户编号
userIds.addAll(userLiveTreeApi.getItemIdsByUserId(getLoginUserId()).getCheckedData());
}
if (CollUtil.isEmpty(userIds)) {
return PageResult.empty();
}
return contractMapper.selectPage(pageReqVO, userIds);
}
@ -326,9 +329,10 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
@Override
public List<BpmOAContractDO> getContractList(BpmOAContractVO respVO) {
Date[] dateArray = new Date[]{respVO.getStarTime(), respVO.getEndTime()};
if (CollUtil.isEmpty(respVO.getUserId())) {
return Collections.emptyList();
}
return contractMapper.selectList(new LambdaQueryWrapperX<BpmOAContractDO>()
.inIfPresent(BpmOAContractDO::getUserId, respVO.getUserId())
.eqIfPresent(BpmOAContractDO::getContractType, respVO.getContractType())
@ -344,6 +348,33 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
.eq(BpmOAContractDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult()));
}
@Override
public void updateSettlementFlagByIds(List<Long> contractIds) {
contractMapper.update(new BpmOAContractDO().setSettlementFlag(1), new LambdaQueryWrapper<BpmOAContractDO>()
.in(BpmOAContractDO::getId, contractIds));
}
@Override
public List<BpmOAContractDO> getList(String relation, Integer contractType, String contractName) {
List<Long> userIds = new ArrayList<>();
Long id = getLoginUserId();
if ("my".equals(relation)) {
userIds.add(id);
} else if ("sub".equals(relation)) {
// 查询当前用户 所有下级用户编号
userIds.addAll(userLiveTreeApi.getItemIdsByUserId(id).getCheckedData());
}
userIds.add(id);
if (CollUtil.isNotEmpty(userIds)) {
return contractMapper.selectList(new LambdaQueryWrapperX<BpmOAContractDO>()
.in(BpmOAContractDO::getUserId, userIds)
.eqIfPresent(BpmOAContractDO::getContractType, contractType)
.likeIfPresent(BpmOAContractDO::getContractName, contractName)
.eq(BpmOAContractDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult()));
}
return Collections.emptyList();
}
public static BigDecimal calculatePercentageChange(Object today, Object yesterday) {
// 转换为 BigDecimal 进行高精度计算
@ -363,30 +394,30 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
}
private void createContractProductList(Long contractId, List<CrmContractProductVO> list) {
List<StoreProductAttrValueApiVO> storeProductAttrValueList = new ArrayList<>();
if (CollUtil.isNotEmpty(list)) {
List<Long> productIds = list.stream().map(CrmContractProductVO::getProductId).collect(Collectors.toList());
List<String> productAttrUnique = list.stream().map(CrmContractProductVO::getProductAttrUnique).collect(Collectors.toList());
storeProductAttrValueList = storeProductAttrValueApi.getStoreProductAttrValueList(new StoreProductAttrValueApiDTO()
.setProductIds(productIds)
.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());
int count = 0;
if (CollUtil.isNotEmpty(storeProductAttrValueApiVOS)) {
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());
});
// List<StoreProductAttrValueApiVO> storeProductAttrValueList = new ArrayList<>();
// if (CollUtil.isNotEmpty(list)) {
// List<Long> productIds = list.stream().map(CrmContractProductVO::getProductId).collect(Collectors.toList());
// List<String> productAttrUnique = list.stream().map(CrmContractProductVO::getProductAttrUnique).collect(Collectors.toList());
// storeProductAttrValueList = storeProductAttrValueApi.getStoreProductAttrValueList(new StoreProductAttrValueApiDTO()
// .setProductIds(productIds)
// .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());
//
// int count = 0;
// if (CollUtil.isNotEmpty(storeProductAttrValueApiVOS)) {
// 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());
// });
contractApi.createProduct(BeanUtils.toBean(list, CrmContractProductDTO.class));
}

View File

@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAInvoiceDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAInvoiceMapper;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService;
import cn.iocoder.yudao.module.hrm.api.userlivetree.UserLiveTreeApi;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
@ -22,6 +23,7 @@ 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;
@ -36,11 +38,10 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
* OA 开票申请 Service 实现类
*
* @author 符溶馨
*/
@Service
@Validated
public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAInvoiceService{
public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAInvoiceService {
/**
* OA 开票申请对应的流程定义 KEY
@ -61,6 +62,8 @@ public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAIn
@Resource
private RedissonClient redissonClient;
@Resource
private UserLiveTreeApi userLiveTreeApi;
@Override
@Transactional(rollbackFor = Exception.class)
@ -74,7 +77,7 @@ public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAIn
.setUserId(userId)
.setStatus(0)
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
invoiceMapper.insert(invoice) ;
invoiceMapper.insert(invoice);
// 发起 BPM 流程
Map<String, Object> processInstanceVariables = new HashMap<>();
@ -90,10 +93,10 @@ public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAIn
historyProcessInstanceService.createHistoryProcessInstance(processInstanceId, createReqVO.getProcessInstanceId());
}
List<UploadUserFile> fileItems = createReqVO.getFileItems() ;
List<UploadUserFile> fileItems = createReqVO.getFileItems();
//这里的逻辑如果fileItems不为空且有数据那么说明是上传了附件的则需要更工作流文件表对应的实例Id
if (fileItems != null && !fileItems.isEmpty()) {
uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ;
uploadBpmFileProcessInstanceId(processInstanceId, fileItems);
}
return invoice.getId();
@ -184,8 +187,14 @@ public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAIn
@Override
public PageResult<BpmOAInvoiceRespVO> getInvoicePage(BpmOAInvoicePageReqVO pageReqVO) {
return invoiceMapper.selectPage(pageReqVO, getLoginUserId());
Long loginUserId = getLoginUserId();
List<Long> userIds = new ArrayList<>();
if ("my".equals(pageReqVO.getRelation())) {
userIds.add(loginUserId);
} else {
userIds = userLiveTreeApi.getItemIdsByUserId(loginUserId).getCheckedData();
}
return invoiceMapper.selectPage(pageReqVO, userIds);
}
@Override

View File

@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.bpm.service.oa;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptPageReqVO;
@ -18,7 +20,7 @@ public interface BpmOAReceiptService {
/**
* 创建回款申请
*
* @param userId 用户编号
* @param userId 用户编号
* @param createReqVO 创建信息
* @return 编号
*/
@ -27,7 +29,7 @@ public interface BpmOAReceiptService {
/**
* 更新回款申请的状态
*
* @param id 编号
* @param id 编号
* @param result 结果
*/
void updateReceiptResult(String processInstanceId, Long id, Integer result);
@ -42,6 +44,7 @@ public interface BpmOAReceiptService {
/**
* 获得指定的回款申请
*
* @param processInstanceId 流程实例编号
* @return 退款申请
*/
@ -49,6 +52,7 @@ public interface BpmOAReceiptService {
/**
* 获得回款申请分页列表
*
* @param pageReqVO 分页信息
* @return 分页列表
*/
@ -56,7 +60,8 @@ public interface BpmOAReceiptService {
/**
* 获得回款统计信息
* @param userId 用户编号
*
* @param userId 用户编号
* @param relation 查询类型
* @return 回款统计信息
*/
@ -64,6 +69,7 @@ public interface BpmOAReceiptService {
/**
* 获得回款列表
*
* @param respVO 参数信息
* @return 回款信息列表
*/
@ -71,9 +77,18 @@ public interface BpmOAReceiptService {
/**
* 获得指定用户回款统计信息
* @param userIds 用户编号
*
* @param userIds 用户编号
* @param createTime 创建时间
* @return 回款统计信息
*/
List<ReceiptStatisticsDTO> getReceiptStatisticsListByUserIds(List<Long> userIds, LocalDateTime[] createTime);
/**
* 获取用户结算回款信息
*
* @param vo
* @return
*/
List<ReceiptSettlementDTO> getReceiptSettlement(ReceiptSettlementVO vo);
}

View File

@ -1,10 +1,13 @@
package cn.iocoder.yudao.module.bpm.service.oa;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
@ -29,10 +32,7 @@ import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@ -42,11 +42,10 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_RECEIPT_NO
* OA 回款申请 Service 实现类
*
* @author 符溶馨
*/
@Service
@Validated
public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOAReceiptService{
public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOAReceiptService {
/**
* OA 退款对应的流程定义 KEY
@ -78,7 +77,7 @@ public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOARe
BpmOAReceiptDO receipt = BeanUtils.toBean(createReqVO, BpmOAReceiptDO.class)
.setUserId(userId)
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
receiptMapper.insert(receipt) ;
receiptMapper.insert(receipt);
// 发起 BPM 流程
Map<String, Object> processInstanceVariables = new HashMap<>();
@ -95,10 +94,10 @@ public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOARe
historyProcessInstanceService.createHistoryProcessInstance(processInstanceId, createReqVO.getProcessInstanceId());
}
List<UploadUserFile> fileItems = createReqVO.getFileItems() ;
List<UploadUserFile> fileItems = createReqVO.getFileItems();
//这里的逻辑如果fileItems不为空且有数据那么说明是上传了附件的则需要更工作流文件表对应的实例Id
if (fileItems != null && !fileItems.isEmpty()) {
uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ;
uploadBpmFileProcessInstanceId(processInstanceId, fileItems);
}
return receipt.getId();
@ -150,11 +149,13 @@ public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOARe
List<Long> userIds = new ArrayList<>();
if ("my".equals(pageReqVO.getRelation())) {
userIds.add(getLoginUserId());
}else if ("sub".equals(pageReqVO.getRelation())){
} else if ("sub".equals(pageReqVO.getRelation())) {
// 查询当前用户 所有下级用户编号
userIds.addAll(userLiveTreeApi.getItemIdsByUserId(getLoginUserId()).getCheckedData());
}
if (CollUtil.isEmpty(userIds)) {
return PageResult.empty();
}
return receiptMapper.selectReceiptPage(pageReqVO, userIds);
}
@ -169,7 +170,9 @@ public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOARe
@Override
public List<BpmOAReceiptDO> getReceiptList(BpmOAReceiptVO respVO) {
if (CollUtil.isEmpty(respVO.getUserId())) {
return Collections.emptyList();
}
return receiptMapper.selectList(new LambdaQueryWrapperX<BpmOAReceiptDO>()
.inIfPresent(BpmOAReceiptDO::getUserId, respVO.getUserId())
.eq(BpmOAReceiptDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult())
@ -182,6 +185,11 @@ public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOARe
return receiptMapper.selectReceiptStatisticsListByUserIds(userIds, createTime);
}
@Override
public List<ReceiptSettlementDTO> getReceiptSettlement(ReceiptSettlementVO vo) {
return receiptMapper.getReceiptSettlement(vo);
}
public static BigDecimal calculatePercentageChange(Object today, Object yesterday) {
// 转换为 BigDecimal 进行高精度计算

View File

@ -0,0 +1,64 @@
package cn.iocoder.yudao.module.bpm.service.oa;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salesperformance.SalesPerformancePageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salesperformance.SalesPerformanceSaveReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalesPerformanceDO;
import com.baomidou.mybatisplus.extension.service.IService;
import javax.validation.Valid;
/**
* 销售业绩目标申请OA Service 接口
*
* @author 艾楷
*/
public interface BpmOASalesPerformanceService extends IService<BpmOASalesPerformanceDO> {
/**
* 创建销售业绩目标申请OA
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createSalesPerformance(@Valid SalesPerformanceSaveReqVO createReqVO);
/**
* 更新销售业绩目标申请OA
*
* @param updateReqVO 更新信息
*/
void updateSalesPerformance(@Valid SalesPerformanceSaveReqVO updateReqVO);
/**
* 删除销售业绩目标申请OA
*
* @param id 编号
*/
void deleteSalesPerformance(Long id);
/**
* 获得销售业绩目标申请OA
*
* @param id 编号
* @return 销售业绩目标申请OA
*/
BpmOASalesPerformanceDO getSalesPerformance(Long id);
/**
* 获得销售业绩目标申请OA分页
*
* @param pageReqVO 分页查询
* @return 销售业绩目标申请OA分页
*/
PageResult<BpmOASalesPerformanceDO> getSalesPerformancePage(SalesPerformancePageReqVO pageReqVO);
/**
* 更新销售业绩目标申请的状态
*
* @param processInstanceId 流程实例id
* @param id
* @param result 结果
*/
void updateSalesPerformanceResult(String processInstanceId, Long id, Integer result);
}

View File

@ -0,0 +1,134 @@
package cn.iocoder.yudao.module.bpm.service.oa;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salesperformance.SalesPerformancePageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salesperformance.SalesPerformanceSaveReqVO;
import cn.iocoder.yudao.module.bpm.convert.oa.BpmOASalesPerformanceConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalesPerformanceDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOASalesPerformanceMapper;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.hrm.api.salesperformancesettlement.SalesPerformanceSettlementApi;
import cn.iocoder.yudao.module.hrm.api.salesperformancesettlement.dto.SalesPerformanceSettlementDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.CAN_ONLY_APPLY_FOR_CURRENT_MONTH_PERFORMANCE_TARGET;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.THE_PROCESS_IS_BEING_APPROVED_OR_HAS_PASSED_THE_CURRENT_MONTH_AND_THE_APPLICATION_CANNOT_BE_REPEATED;
/**
* 销售业绩目标申请OA Service 实现类
*
* @author 艾楷
*/
@Service
@Validated
public class BpmOASalesPerformanceServiceImpl extends ServiceImpl<BpmOASalesPerformanceMapper, BpmOASalesPerformanceDO> implements BpmOASalesPerformanceService {
@Resource
private BpmOASalesPerformanceMapper bpmOASalesPerformanceMapper;
@Resource
private BpmProcessInstanceApi processInstanceApi;
@Resource
private BpmHistoryProcessInstanceService historyProcessInstanceService;
@Resource
private BpmProcessInstanceService processInstanceService;
@Resource
private SalesPerformanceSettlementApi salesPerformanceSettlementApi;
/**
* OA 销售业绩目标申请OA对应的流程定义 KEY
*/
public static final String PROCESS_KEY = "oa_sales_performance";
@Override
public Long createSalesPerformance(SalesPerformanceSaveReqVO createReqVO) {
// 判断是否是当月的目标
LocalDateTime now = LocalDateTime.now();
String year = String.valueOf(now.getYear());
String month = String.format("%02d", now.getMonthValue());
Long userId = getLoginUserId();
if (!year.equals(createReqVO.getYear()) || !month.equals(createReqVO.getMonth())) {
throw exception(CAN_ONLY_APPLY_FOR_CURRENT_MONTH_PERFORMANCE_TARGET);
}
// 判断是否已经存在
Long count = bpmOASalesPerformanceMapper.selectCount(new LambdaQueryWrapper<BpmOASalesPerformanceDO>()
.eq(BpmOASalesPerformanceDO::getUserId, userId)
.eq(BpmOASalesPerformanceDO::getYear, year)
.eq(BpmOASalesPerformanceDO::getMonth, month)
.in(BpmOASalesPerformanceDO::getResult, BpmProcessInstanceResultEnum.PROCESS.getResult(), BpmProcessInstanceResultEnum.APPROVE.getResult()));
if (count > 0L) {
throw exception(THE_PROCESS_IS_BEING_APPROVED_OR_HAS_PASSED_THE_CURRENT_MONTH_AND_THE_APPLICATION_CANNOT_BE_REPEATED);
}
BpmOASalesPerformanceDO bpmOASalesPerformanceDO = BpmOASalesPerformanceConvert.INSTANCE.convert(createReqVO).setUserId(userId)
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
bpmOASalesPerformanceMapper.insert(bpmOASalesPerformanceDO);
// 发起 BPM 流程
String processInstanceId = processInstanceApi.createProcessInstance(userId,
new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY)
.setBusinessKey(String.valueOf(bpmOASalesPerformanceDO.getId()))).getCheckedData();
bpmOASalesPerformanceMapper.updateById(bpmOASalesPerformanceDO.setProcessInstanceId(processInstanceId));
// 判断是否为重新发起的流程
if (createReqVO.getProcessInstanceId() != null && createReqVO.getResult() == 3) {
historyProcessInstanceService.createHistoryProcessInstance(processInstanceId, createReqVO.getProcessInstanceId());
}
// 返回
return bpmOASalesPerformanceDO.getId();
}
@Override
public void updateSalesPerformance(SalesPerformanceSaveReqVO updateReqVO) {
// 更新
BpmOASalesPerformanceDO updateObj = BeanUtils.toBean(updateReqVO, BpmOASalesPerformanceDO.class);
bpmOASalesPerformanceMapper.updateById(updateObj);
}
@Override
public void deleteSalesPerformance(Long id) {
// 删除
bpmOASalesPerformanceMapper.deleteById(id);
}
@Override
public BpmOASalesPerformanceDO getSalesPerformance(Long id) {
return bpmOASalesPerformanceMapper.selectById(id);
}
@Override
public PageResult<BpmOASalesPerformanceDO> getSalesPerformancePage(SalesPerformancePageReqVO pageReqVO) {
return bpmOASalesPerformanceMapper.selectPage(pageReqVO);
}
@Override
public void updateSalesPerformanceResult(String processInstanceId, Long id, Integer result) {
//审核通过 最后节点
if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) {
ProcessInstance instance = processInstanceService.getProcessInstance(processInstanceId);
if (instance.isEnded()) {
// -- 拿到当前的id set到表中目标表中
// 当前用户
BpmOASalesPerformanceDO bpmOASalesPerformanceDO = bpmOASalesPerformanceMapper.selectById(id);
salesPerformanceSettlementApi.update(new SalesPerformanceSettlementDTO().setSalesPerformanceId(id)
.setYear(bpmOASalesPerformanceDO.getYear())
.setMonth(bpmOASalesPerformanceDO.getMonth())
.setUserId(bpmOASalesPerformanceDO.getUserId()));
}
}
bpmOASalesPerformanceMapper.updateById(new BpmOASalesPerformanceDO().setId(id).setResult(result));
}
}

View File

@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.bpm.service.oa.listener;
import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEvent;
import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventListener;
import cn.iocoder.yudao.module.bpm.service.oa.BpmOASalesPerformanceService;
import cn.iocoder.yudao.module.bpm.service.oa.BpmOASalesPerformanceServiceImpl;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* OA 销售业绩目标申请OA
*
* @author 符溶馨
*/
@Component
public class BpmOASalesPerformanceResultListener extends BpmProcessInstanceResultEventListener {
@Resource
private BpmOASalesPerformanceService salesPerformanceService;
@Override
protected String getProcessDefinitionKey() {
return BpmOASalesPerformanceServiceImpl.PROCESS_KEY;
}
@Override
protected void onEvent(BpmProcessInstanceResultEvent event) {
salesPerformanceService.updateSalesPerformanceResult(event.getId(), Long.parseLong(event.getBusinessKey()), event.getResult());
}
}

View File

@ -59,4 +59,24 @@
</if>
GROUP BY user_id
</select>
<select id="getReceiptSettlement"
resultType="cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO">
SELECT
user_id AS userId,
SUM(money) AS money
FROM
bpm_oa_receipt
WHERE
deleted = 0
AND result = 2
<if test="vo.createTime != null and vo.createTime.length > 0">
<if test="vo.createTime[0] != null">
and create_time &gt;= #{vo.createTime[0]}
</if>
<if test="vo.createTime[1] != null">
and create_time &lt;= #{vo.createTime[1]}
</if>
</if>
GROUP BY user_id
</select>
</mapper>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOASalesPerformanceMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

View File

@ -28,4 +28,9 @@ public interface BusinessApi {
@Operation(summary = "获得商机所绑定产品信息")
@Parameter(name = "businessId", description = "商机编号", required = true)
CommonResult<List<CrmBusinessProductDTO>> getBusinessProduct(@RequestParam("businessId") Long businessId);
@GetMapping(PREFIX + "/updateIsEnd")
@Operation(summary = "更新商机状态")
@Parameter(name = "id", description = "ID", required = true)
CommonResult<Boolean> updateIsEnd(@RequestParam("id") Long id, @RequestParam("isEnd") Integer isEnd);
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.hrm.api.crmcontract.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class CrmContractProductSettlementDTO {
@Schema(description = "crm申请用户id")
private Long userId;
@Schema(description = "合同编号")
private Long contractId;
@Schema(description = "产品编号")
private Long productId;
@Schema(description = "产品单价")
private BigDecimal price;
@Schema(description = "数量")
private Integer nums;
@Schema(description = "折扣")
private BigDecimal discount;
@Schema(description = "小计")
private BigDecimal subtotal;
@Schema(description = "备注")
private String remarks;
}

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.hrm.api.salesperformancesettlement;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.hrm.api.crmcustomer.dto.CrmCustomerDTO;
import cn.iocoder.yudao.module.hrm.api.salesperformancesettlement.dto.SalesPerformanceSettlementDTO;
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 服务 - 销售业绩目标")
public interface SalesPerformanceSettlementApi {
String PREFIX = ApiConstants.PREFIX + "/crm/salesPerformanceSettlement";
@PostMapping(PREFIX + "/update")
@Operation(summary = "更新")
CommonResult<Boolean> update(@RequestBody SalesPerformanceSettlementDTO salesPerformanceSettlementDTO);
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.hrm.api.salesperformancesettlement.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class SalesPerformanceSettlementDTO {
@Schema(description = "用户id")
private Long userId;
@Schema(description = "")
private String year;
@Schema(description = "")
private String month;
@Schema(description = "销售业绩目标申请ID", example = "14373")
private Long salesPerformanceId;
}

View File

@ -14,4 +14,8 @@ public interface ErrorCodeConstants {
ErrorCode CONTRACT_RECEIVABLES_NOT_EXISTS = new ErrorCode(200007, "回款不存在");
ErrorCode INVOICE_NOT_EXISTS = new ErrorCode(200008, "发票不存在");
ErrorCode ACHIEVEMENT_NOT_EXISTS = new ErrorCode(200009, "业绩目标不存在");
ErrorCode NOT_EDITABLE_UNTIL_SALES_TARGET_HAS_BEEN_APPLIED = new ErrorCode(200010, "未申请销售目标前不可编辑");
ErrorCode THIS_CUSTOMER_ALREADY_EXISTS_IN_THE_SYSTEM_AND_CANNOT_BE_ENTERED_REPEATEDLY = new ErrorCode(200011, "系统已存在该客户,不可重复录入");
ErrorCode THIS_CUSTOMER_ALREADY_EXISTS_IN_THE_SYSTEM_DO_YOU_WANT_TO_CONTINUE_ADDING = new ErrorCode(200012, "系统已存在该客户,是否继续添加");
}

View File

@ -12,7 +12,6 @@ import org.springframework.validation.annotation.Validated;
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;
@ -38,4 +37,10 @@ public class BusinessApiImpl implements BusinessApi {
List<CrmBusinessProductDO> businessProductList = businessService.getBusinessProductListByBusinessId(businessId);
return success(BeanUtils.toBean(businessProductList, CrmBusinessProductDTO.class));
}
@Override
public CommonResult<Boolean> updateIsEnd(Long id, Integer isEnd) {
businessService.updateIsEnd(id, isEnd);
return success(true);
}
}

View File

@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractProduct
import cn.iocoder.yudao.module.crm.service.crmcontract.CrmContractService;
import cn.iocoder.yudao.module.hrm.api.crmcontract.ContractApi;
import cn.iocoder.yudao.module.hrm.api.crmcontract.dto.CrmContractProductDTO;
import cn.iocoder.yudao.module.hrm.api.crmcontract.dto.CrmContractProductSettlementDTO;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.crm.api.salesperformancesettlement;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.crm.dal.dataobject.salesperformancesettlement.SalesPerformanceSettlementDO;
import cn.iocoder.yudao.module.crm.service.salesperformancesettlement.SalesPerformanceSettlementService;
import cn.iocoder.yudao.module.hrm.api.salesperformancesettlement.SalesPerformanceSettlementApi;
import cn.iocoder.yudao.module.hrm.api.salesperformancesettlement.dto.SalesPerformanceSettlementDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* Flowable CRM Api 实现类
*/
@RestController
@Validated
public class SalesPerformanceSettlementApImpl implements SalesPerformanceSettlementApi {
@Resource
private SalesPerformanceSettlementService salesPerformanceSettlementService;
@Override
public CommonResult<Boolean> update(SalesPerformanceSettlementDTO salesPerformanceSettlementDTO) {
salesPerformanceSettlementService.update(new SalesPerformanceSettlementDO().setSalesPerformanceId(salesPerformanceSettlementDTO.getSalesPerformanceId()),
new LambdaQueryWrapper<SalesPerformanceSettlementDO>().eq(SalesPerformanceSettlementDO::getYear, salesPerformanceSettlementDTO.getYear())
.eq(SalesPerformanceSettlementDO::getMonth, salesPerformanceSettlementDTO.getMonth())
.eq(SalesPerformanceSettlementDO::getUserId, salesPerformanceSettlementDTO.getUserId()));
return CommonResult.success(true);
}
}

View File

@ -5,6 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessSaveReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessTransferVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CrmCustomerTransferVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessProductDO;
import cn.iocoder.yudao.module.crm.service.crmbusiness.CrmBusinessService;
import io.swagger.v3.oas.annotations.Operation;
@ -62,6 +64,13 @@ public class CrmBusinessController {
return success(businessService.getBusiness(id));
}
@PostMapping("/transfer")
@Operation(summary = "转移商机")
public CommonResult<Boolean> transferBusiness(@Valid @RequestBody CrmBusinessTransferVO transferVO) {
businessService.transfer(transferVO);
return success(true);
}
@GetMapping("/page")
@Operation(summary = "获得商机分页")
// @PreAuthorize("@ss.hasPermission('crm:business:query')")

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 客户转移 VO")
@Data
public class CrmBusinessTransferVO {
@Schema(description = "商机ID")
private List<Long> businessIds;
@Schema(description = "接受员工ID")
private List<Long> ownerAdminIds;
@Schema(description = "分配方式")
private Integer averageType;
}

View File

@ -12,15 +12,13 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@ -105,12 +103,12 @@ public class CrmCustomerController {
@Operation(summary = "导出客户 Excel")
// @PreAuthorize("@ss.hasPermission('crm:customer:export')")
public void exportCustomerExcel(@Valid CrmCustomerPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<CrmCustomerDO> list = customerService.getCustomerPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "客户.xls", "数据", CrmCustomerRespVO.class,
BeanUtils.toBean(list, CrmCustomerRespVO.class));
BeanUtils.toBean(list, CrmCustomerRespVO.class));
}
@GetMapping("/get-import-template")
@ -119,9 +117,9 @@ public class CrmCustomerController {
// 手动创建导出 demo
List<CrmCustomerImportVO> list = Arrays.asList(
CrmCustomerImportVO.builder().name("yshop").mobile("18888888888").telephone("18888888888").tags("重要,厉害")
.remark("yshop").detailAddress("详细地址").lng(10.1).lat(10.2).weixin("wechat").qq("100000").build(),
.remark("yshop").detailAddress("详细地址").weixin("wechat").qq("100000").build(),
CrmCustomerImportVO.builder().name("yshop2").mobile("18888888888=0").telephone("18888888880").tags("重要2,厉害")
.remark("yshop2").detailAddress("详细地址2").lng(10.1).lat(10.2).weixin("wechat2").qq("1000002").build()
.remark("yshop2").detailAddress("详细地址2").weixin("wechat2").qq("1000002").build()
);
// 输出
ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportVO.class, list);
@ -136,11 +134,11 @@ public class CrmCustomerController {
@Parameter(name = "averageType", description = "分配方式")
})
public CommonResult<CustomerImportRespVO> importExcel(@RequestParam("file") MultipartFile file,
@RequestParam("deptId") String deptId,
@RequestParam("adminIds") String adminIds,
@RequestParam("averageType") Integer averageType) throws Exception {
@RequestParam("averageType") Integer averageType,
@RequestParam(value = "repeatConfirmationFlag", defaultValue = "0") Integer repeatConfirmationFlag) throws Exception {
List<CrmCustomerImportVO> list = ExcelUtils.read(file, CrmCustomerImportVO.class);
return success(customerService.importList(list, deptId,adminIds,averageType));
return success(customerService.importList(list, adminIds, averageType, repeatConfirmationFlag));
}
@PostMapping("/recover")
@ -172,6 +170,4 @@ public class CrmCustomerController {
}
}

View File

@ -34,20 +34,10 @@ public class CrmCustomerImportVO {
@ExcelProperty("详细地址")
private String detailAddress;
@ExcelProperty("地理位置经度")
private Double lng;
@ExcelProperty("地理位置维度")
private Double lat;
@ExcelProperty("微信")
private String weixin;
@ExcelProperty("QQ")
private String qq;
@ExcelProperty("消费总额")
private BigDecimal purchaseTotal;
}

View File

@ -16,6 +16,8 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CrmCustomerPageReqVO extends PageParam {
@Schema(description = "是否去重 0否 1是 默认否", example = "0")
private Integer distinctFlag = 0;
@Schema(description = "客户名称", example = "李四")
private String name;

View File

@ -133,4 +133,6 @@ public class CrmCustomerRespVO {
@Schema(description = "负责人")
private String createName;
@Schema(description = "相同客户自增排序")
private Integer sortNum;
}

View File

@ -1,9 +1,9 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import javax.validation.constraints.NotEmpty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@ -108,6 +108,7 @@ public class CrmCustomerSaveReqVO {
@Schema(description = "跟进状态", example = "1")
private Integer followStatus;
@Schema(description = "重复客户依旧添加 0否 1是 默认否", example = "1")
private Integer repeatConfirmationFlag = 0;
}

View File

@ -0,0 +1,81 @@
package cn.iocoder.yudao.module.crm.controller.admin.salesperformanceassessment;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformanceassessment.vo.*;
import cn.iocoder.yudao.module.crm.dal.dataobject.salesperformanceassessment.SalesPerformanceAssessmentDO;
import cn.iocoder.yudao.module.crm.service.salesperformanceassessment.SalesPerformanceAssessmentService;
@Tag(name = "管理后台 - 绩效考核设置")
@RestController
@RequestMapping("/crm/sales-performance-assessment")
@Validated
public class SalesPerformanceAssessmentController {
@Resource
private SalesPerformanceAssessmentService salesPerformanceAssessmentService;
@PostMapping("/create")
@Operation(summary = "创建绩效考核设置")
@PreAuthorize("@ss.hasPermission('crm:sales-performance-assessment:create')")
public CommonResult<Long> createSalesPerformanceAssessment(@Valid @RequestBody SalesPerformanceAssessmentSaveReqVO createReqVO) {
return success(salesPerformanceAssessmentService.createSalesPerformanceAssessment(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新绩效考核设置")
@PreAuthorize("@ss.hasPermission('crm:sales-performance-assessment:update')")
public CommonResult<Boolean> updateSalesPerformanceAssessment(@Valid @RequestBody SalesPerformanceAssessmentSaveReqVO updateReqVO) {
salesPerformanceAssessmentService.updateSalesPerformanceAssessment(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除绩效考核设置")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('crm:sales-performance-assessment:delete')")
public CommonResult<Boolean> deleteSalesPerformanceAssessment(@RequestParam("id") Long id) {
salesPerformanceAssessmentService.deleteSalesPerformanceAssessment(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得绩效考核设置")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('crm:sales-performance-assessment:query')")
public CommonResult<SalesPerformanceAssessmentRespVO> getSalesPerformanceAssessment(@RequestParam("id") Long id) {
SalesPerformanceAssessmentDO salesPerformanceAssessment = salesPerformanceAssessmentService.getSalesPerformanceAssessment(id);
return success(BeanUtils.toBean(salesPerformanceAssessment, SalesPerformanceAssessmentRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得绩效考核设置分页")
@PreAuthorize("@ss.hasPermission('crm:sales-performance-assessment:query')")
public CommonResult<PageResult<SalesPerformanceAssessmentRespVO>> getSalesPerformanceAssessmentPage(@Valid SalesPerformanceAssessmentPageReqVO pageReqVO) {
PageResult<SalesPerformanceAssessmentDO> pageResult = salesPerformanceAssessmentService.getSalesPerformanceAssessmentPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, SalesPerformanceAssessmentRespVO.class));
}
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.crm.controller.admin.salesperformanceassessment.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import java.math.BigDecimal;
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 SalesPerformanceAssessmentPageReqVO extends PageParam {
@Schema(description = "计算表达式 例如 10<=n&&n<=20")
private String calculationExpression;
@Schema(description = "核发比例%")
private BigDecimal proportion;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.crm.controller.admin.salesperformanceassessment.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.util.*;
import java.math.BigDecimal;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - 绩效考核设置 Response VO")
@Data
@ExcelIgnoreUnannotated
public class SalesPerformanceAssessmentRespVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "3321")
@ExcelProperty("id")
private Long id;
@Schema(description = "计算表达式 例如 10<=n&&n<=20")
@ExcelProperty("计算表达式 例如 10<=n&&n<=20")
private String calculationExpression;
@Schema(description = "核发比例%")
@ExcelProperty("核发比例%")
private BigDecimal proportion;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.crm.controller.admin.salesperformanceassessment.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
import java.util.*;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 绩效考核设置新增/修改 Request VO")
@Data
public class SalesPerformanceAssessmentSaveReqVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "3321")
private Long id;
@Schema(description = "计算表达式 例如 10<=n&&n<=20")
private String calculationExpression;
@Schema(description = "核发比例%")
private BigDecimal proportion;
}

View File

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo.SalesPerformanceSettlementPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo.SalesPerformanceSettlementRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo.SalesPerformanceSettlementSaveReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.salesperformancesettlement.SalesPerformanceSettlementDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.userlivetree.UserLiveTreeDO;
import cn.iocoder.yudao.module.crm.service.salesperformancesettlement.SalesPerformanceSettlementService;
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.*;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - 销售业绩结算记录")
@RestController
@RequestMapping("/crm/sales-performance-settlement")
@Validated
public class SalesPerformanceSettlementController {
@Resource
private SalesPerformanceSettlementService salesPerformanceSettlementService;
@PutMapping("/update")
@Operation(summary = "更新销售业绩结算记录")
public CommonResult<Boolean> updateSalesPerformanceSettlement(@Valid @RequestBody SalesPerformanceSettlementSaveReqVO updateReqVO) {
salesPerformanceSettlementService.updateSalesPerformanceSettlement(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除销售业绩结算记录")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('crm:sales-performance-settlement:delete')")
public CommonResult<Boolean> deleteSalesPerformanceSettlement(@RequestParam("id") Long id) {
salesPerformanceSettlementService.deleteSalesPerformanceSettlement(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得销售业绩结算记录")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('crm:sales-performance-settlement:query')")
public CommonResult<SalesPerformanceSettlementRespVO> getSalesPerformanceSettlement(@RequestParam("id") Long id) {
SalesPerformanceSettlementDO salesPerformanceSettlement = salesPerformanceSettlementService.getSalesPerformanceSettlement(id);
return success(BeanUtils.toBean(salesPerformanceSettlement, SalesPerformanceSettlementRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得销售业绩结算记录分页")
public CommonResult<PageResult<SalesPerformanceSettlementRespVO>> getSalesPerformanceSettlementPage(@Valid SalesPerformanceSettlementPageReqVO pageReqVO) {
PageResult<SalesPerformanceSettlementDO> pageResult = salesPerformanceSettlementService.getSalesPerformanceSettlementPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, SalesPerformanceSettlementRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出销售业绩结算记录 Excel")
@PreAuthorize("@ss.hasPermission('crm:sales-performance-settlement:export')")
@OperateLog(type = EXPORT)
public void exportSalesPerformanceSettlementExcel(@Valid SalesPerformanceSettlementPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<SalesPerformanceSettlementDO> list = salesPerformanceSettlementService.getSalesPerformanceSettlementPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "销售业绩结算记录.xls", "数据", SalesPerformanceSettlementRespVO.class,
BeanUtils.toBean(list, SalesPerformanceSettlementRespVO.class));
}
@GetMapping("/test")
@Operation(summary = "测试")
@PermitAll
public CommonResult<Boolean> test() {
salesPerformanceSettlementService.settlement();
return success(true);
}
}

View File

@ -0,0 +1,80 @@
package cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.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.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
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 SalesPerformanceSettlementPageReqVO extends PageParam {
@Schema(description = "用户id", example = "27486")
private Long userId;
@Schema(description = "销售业绩目标申请ID", example = "14373")
private Long salesPerformanceId;
@Schema(description = "")
private String year;
@Schema(description = "")
private String month;
@Schema(description = "实际回款额")
private BigDecimal actualPayment;
@Schema(description = "实际销售额")
private Integer actualSale;
@Schema(description = "评分")
private BigDecimal score;
@Schema(description = "销售任务%")
private BigDecimal saleTask;
@Schema(description = "回款任务%")
private BigDecimal paymentTask;
@Schema(description = "评分任务%")
private BigDecimal scoreTask;
@Schema(description = "总分")
private BigDecimal totalScore;
@Schema(description = "核发比例")
private BigDecimal proportionOfIssuance;
@Schema(description = "是否确认 0否 1是")
private Integer confirmFlag;
@Schema(description = "是否可以确认 0否 1是")
private Integer canConfirmFlag;
@Schema(description = "评分状态 0待评分 1已评分")
private Integer scoreStatus;
@Schema(description = "结算状态 0待结算 1已结算待评分 2已结算")
private Integer settlementStatus;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "用户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "27486")
private String nickname;
@Schema(description = "用户ids", example = "27486")
private List<Long> userIds;
}

View File

@ -0,0 +1,87 @@
package cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.util.*;
import java.math.BigDecimal;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - 销售业绩结算记录 Response VO")
@Data
@ExcelIgnoreUnannotated
public class SalesPerformanceSettlementRespVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "23686")
@ExcelProperty("id")
private Long id;
@Schema(description = "用户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "27486")
@ExcelProperty("用户id")
private Long userId;
@Schema(description = "用户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "27486")
@ExcelProperty("用户名称")
private String nickname;
@Schema(description = "销售业绩目标申请ID", example = "14373")
@ExcelProperty("销售业绩目标申请ID")
private Long salesPerformanceId;
@Schema(description = "", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("")
private String year;
@Schema(description = "", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("")
private String month;
@Schema(description = "实际回款额")
private BigDecimal actualPayment;
@Schema(description = "实际销售额")
private Integer actualSale;
@Schema(description = "回款目标")
private BigDecimal paymentTarget;
@Schema(description = "销售目标")
private Integer saleTarget;
@Schema(description = "评分")
private BigDecimal score;
@Schema(description = "销售任务%")
private BigDecimal saleTask;
@Schema(description = "回款任务%")
private BigDecimal paymentTask;
@Schema(description = "评分任务%")
private BigDecimal scoreTask;
@Schema(description = "总分")
private BigDecimal totalScore;
@Schema(description = "核发比例")
private BigDecimal proportionOfIssuance;
@Schema(description = "是否确认 0否 1是")
private Integer confirmFlag;
@Schema(description = "是否可以确认 0否 1是")
private Integer canConfirmFlag;
@Schema(description = "评分状态 0待评分 1已评分")
private Integer scoreStatus;
@Schema(description = "结算状态 0待结算 1已结算待评分 2已结算")
private Integer settlementStatus;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,67 @@
package cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
import java.util.*;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 销售业绩结算记录新增/修改 Request VO")
@Data
public class SalesPerformanceSettlementSaveReqVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "23686")
private Long id;
@Schema(description = "用户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "27486")
@NotNull(message = "用户id不能为空")
private Long userId;
@Schema(description = "销售业绩目标申请ID", example = "14373")
private Long salesPerformanceId;
@Schema(description = "", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "年不能为空")
private String year;
@Schema(description = "", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "月不能为空")
private String month;
@Schema(description = "实际回款额")
private BigDecimal actualPayment;
@Schema(description = "实际销售额")
private Integer actualSale;
@Schema(description = "评分")
private BigDecimal score;
@Schema(description = "销售任务%")
private BigDecimal saleTask;
@Schema(description = "回款任务%")
private BigDecimal paymentTask;
@Schema(description = "评分任务%")
private BigDecimal scoreTask;
@Schema(description = "总分")
private BigDecimal totalScore;
@Schema(description = "核发比例")
private BigDecimal proportionOfIssuance;
@Schema(description = "是否确认 0否 1是")
private Integer confirmFlag;
@Schema(description = "是否可以确认 0否 1是")
private Integer canConfirmFlag;
@Schema(description = "评分状态 0待评分 1已评分")
private Integer scoreStatus;
@Schema(description = "结算状态 0待结算 1已结算待评分 2已结算")
private Integer settlementStatus;
}

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.crm.controller.admin.salesperformanceweight;
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.salesperformanceweight.vo.SalesPerformanceWeightRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformanceweight.vo.SalesPerformanceWeightSaveReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.salesperformanceweight.SalesPerformanceWeightDO;
import cn.iocoder.yudao.module.crm.service.salesperformanceweight.SalesPerformanceWeightService;
import io.swagger.v3.oas.annotations.Operation;
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.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 销售业绩权重设置")
@RestController
@RequestMapping("/crm/sales-performance-weight")
@Validated
public class SalesPerformanceWeightController {
@Resource
private SalesPerformanceWeightService salesPerformanceWeightService;
@PutMapping("/saveOrEdit")
@Operation(summary = "新增/修改销售业绩权重设置")
@PreAuthorize("@ss.hasPermission('crm:sales-performance-weight:update')")
public CommonResult<Boolean> saveOrEdit(@Valid @RequestBody SalesPerformanceWeightSaveReqVO updateReqVO) {
salesPerformanceWeightService.saveOrEdit(updateReqVO);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得销售业绩权重设置")
@PreAuthorize("@ss.hasPermission('crm:sales-performance-weight:query')")
public CommonResult<SalesPerformanceWeightRespVO> getSalesPerformanceWeight() {
SalesPerformanceWeightDO salesPerformanceWeight = salesPerformanceWeightService.getSalesPerformanceWeight();
return success(BeanUtils.toBean(salesPerformanceWeight, SalesPerformanceWeightRespVO.class));
}
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.crm.controller.admin.salesperformanceweight.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import java.math.BigDecimal;
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 SalesPerformanceWeightPageReqVO extends PageParam {
@Schema(description = "销售权重%")
private BigDecimal saleWeight;
@Schema(description = "回款权重%")
private BigDecimal paymentWeight;
@Schema(description = "评分权重%")
private BigDecimal scoreWeight;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.crm.controller.admin.salesperformanceweight.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.util.*;
import java.math.BigDecimal;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - 销售业绩权重设置 Response VO")
@Data
@ExcelIgnoreUnannotated
public class SalesPerformanceWeightRespVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "2375")
@ExcelProperty("id")
private Long id;
@Schema(description = "销售权重%")
@ExcelProperty("销售权重%")
private BigDecimal saleWeight;
@Schema(description = "回款权重%")
@ExcelProperty("回款权重%")
private BigDecimal paymentWeight;
@Schema(description = "评分权重%")
@ExcelProperty("评分权重%")
private BigDecimal scoreWeight;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.crm.controller.admin.salesperformanceweight.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
import java.util.*;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 销售业绩权重设置新增/修改 Request VO")
@Data
public class SalesPerformanceWeightSaveReqVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "2375")
private Long id;
@Schema(description = "销售权重%")
private BigDecimal saleWeight;
@Schema(description = "回款权重%")
private BigDecimal paymentWeight;
@Schema(description = "评分权重%")
private BigDecimal scoreWeight;
}

View File

@ -21,6 +21,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
@ -81,6 +82,15 @@ public class UserLiveTreeController {
return success(BeanUtils.toBean(userLiveTree, UserLiveTreeRespVO.class));
}
@GetMapping("/getItemByPid")
@Operation(summary = "获取用户直接下级")
@Parameter(name = "pid", description = "编号", required = true, example = "1024")
public CommonResult<List<UserLiveTreeRespVO>> getItemByPid(@RequestParam("pid") Long pid) {
List<UserLiveTreeDO> userLiveTree = userLiveTreeService.getItemByPid(pid);
return success(BeanUtils.toBean(userLiveTree, UserLiveTreeRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得crm用户结构树分页")
@PreAuthorize("@ss.hasPermission('crm:user-live-tree:query')")
@ -101,5 +111,4 @@ public class UserLiveTreeController {
ExcelUtils.write(response, "crm用户结构树.xls", "数据", UserLiveTreeRespVO.class,
BeanUtils.toBean(list, UserLiveTreeRespVO.class));
}
}

View File

@ -61,7 +61,7 @@ public class CrmCluesDO extends BaseDO {
*/
private Integer industry;
/**
* 客户标签
* 客户标签
*/
private String tags;
/**
@ -107,11 +107,11 @@ public class CrmCluesDO extends BaseDO {
private LocalDateTime collectTime;
/**
* 跟进状态1|新客
2|待再次沟通
3|有意向
4|已加微信
5|转商机
0|无效
* 2|待再次沟通
* 3|有意向
* 4|已加微信
* 5|转商机
* 0|无效
*/
private Integer followStatus;

View File

@ -78,7 +78,10 @@ public class CrmCustomerDO extends BaseDO {
* 负责人ID
*/
private Long ownerUserId;
/**
* 相同客户自增排序
*/
private Integer sortNum;
/**
* 省份id
*/

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.crm.dal.dataobject.salesperformanceassessment;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 绩效考核设置 DO
*
* @author 艾楷
*/
@TableName("crm_sales_performance_assessment")
@KeySequence("crm_sales_performance_assessment_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SalesPerformanceAssessmentDO extends BaseDO {
/**
* id
*/
@TableId
private Long id;
/**
* 计算表达式 例如 10<=n&&n<=20
*/
private String calculationExpression;
/**
* 核发比例%
*/
private BigDecimal proportion;
}

View File

@ -0,0 +1,114 @@
package cn.iocoder.yudao.module.crm.dal.dataobject.salesperformancesettlement;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.math.BigDecimal;
/**
* 销售业绩结算记录 DO
*
* @author 艾楷
*/
@TableName("crm_sales_performance_settlement")
@KeySequence("crm_sales_performance_settlement_seq")
// 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SalesPerformanceSettlementDO extends BaseDO {
/**
* id
*/
@TableId
private Long id;
/**
* 用户id
*/
private Long userId;
/**
* 销售业绩目标申请ID
*/
private Long salesPerformanceId;
/**
*
*/
private String year;
/**
*
*/
private String month;
/**
* 实际回款额
*/
private BigDecimal actualPayment;
/**
* 实际销售额
*/
private Integer actualSale;
/**
* 评分
*/
private BigDecimal score;
/**
* 销售任务%
*/
private BigDecimal saleTask;
/**
* 回款任务%
*/
private BigDecimal paymentTask;
/**
* 评分任务%
*/
private BigDecimal scoreTask;
/**
* 总分
*/
private BigDecimal totalScore;
/**
* 核发比例
*/
private BigDecimal proportionOfIssuance;
/**
* 是否确认 0否 1是
*/
private Integer confirmFlag;
/**
* 是否可以确认 0否 1是
*/
private Integer canConfirmFlag;
/**
* 评分状态 0待评分 1已评分
*/
private Integer scoreStatus;
/**
* 结算状态 0待结算 1已结算待评分 2已结算
*/
private Integer settlementStatus;
/**
* 昵称
*/
@TableField(exist = false)
private String nickname;
/**
* 回款目标
*/
@TableField(exist = false)
private BigDecimal paymentTarget;
/**
* 销售目标
*/
@TableField(exist = false)
private Integer saleTarget;
}

View File

@ -0,0 +1,46 @@
package cn.iocoder.yudao.module.crm.dal.dataobject.salesperformanceweight;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import java.math.BigDecimal;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 销售业绩权重设置 DO
*
* @author 艾楷
*/
@TableName("crm_sales_performance_weight")
@KeySequence("crm_sales_performance_weight_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SalesPerformanceWeightDO extends BaseDO {
/**
* id
*/
@TableId
private Long id;
/**
* 销售权重%
*/
private BigDecimal saleWeight;
/**
* 回款权重%
*/
private BigDecimal paymentWeight;
/**
* 评分权重%
*/
private BigDecimal scoreWeight;
}

View File

@ -8,6 +8,7 @@ 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;
import cn.iocoder.yudao.module.hrm.api.crmcontract.dto.CrmContractProductSettlementDTO;
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.vo.UserProductCountVO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Mapper;
@ -58,9 +59,17 @@ public interface CrmContractMapper extends BaseMapperX<CrmContractDO> {
/**
* 获取用户合同产品数量
*
* @param userIds
* @param createTime
* @return
*/
List<UserProductCountVO> getProductCount(@Param("userIds") List<Long> userIds, @Param("createTime") LocalDateTime[] createTime);
/**
* 获取合同结算信息
*
* @return
*/
List<CrmContractProductSettlementDTO> getContractProductSettlement();
}

View File

@ -27,7 +27,7 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
return selectPage(reqVO, new LambdaQueryWrapperX<CrmCustomerDO>()
//.eq(CustomerTypesEnum.OPEN.getValue().equals(reqVO.getType()),)
.inIfPresent(CrmCustomerDO::getOwnerUserId,ids)
.inIfPresent(CrmCustomerDO::getOwnerUserId, ids)
.likeIfPresent(CrmCustomerDO::getName, reqVO.getName())
.eqIfPresent(CrmCustomerDO::getMobile, reqVO.getMobile())
.eqIfPresent(CrmCustomerDO::getTelephone, reqVO.getTelephone())
@ -41,7 +41,17 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
.orderByDesc(CrmCustomerDO::getId));
}
IPage<CrmCustomerRespVO> selectPageList(@Param("page") IPage page, @Param("dto") CrmCustomerPageReqVO pageReqVO, @Param("ids") List<Long> ids);
IPage<CrmCustomerRespVO> selectPageList2(@Param("page") IPage page, @Param("dto") CrmCustomerPageReqVO pageReqVO, @Param("ids") List<Long> ids);
List<CustomerStatisticRespVO> selectStatistic(@Param("userIds") List<Long> userIds, @Param("createTime") LocalDateTime[] createTime);
IPage<CrmCustomerDO> selectPageList(@Param("page") IPage page, @Param("dto") CrmCustomerPageReqVO pageReqVO, @Param("ids") List<Long> ids);
/**
* 获取重复客户的所有负责人名称
*
* @param name
* @return
*/
List<String> getRepeatOwnerUserName(@Param("name") String name);
}

View File

@ -10,8 +10,11 @@ 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.crminvoice.CrmInvoiceDO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -26,6 +29,7 @@ public interface CrmInvoiceMapper extends BaseMapperX<CrmInvoiceDO> {
default PageResult<CrmInvoiceRespVO> selectPage2(CrmInvoicePageReqVO reqVO, List<Long> ids) {
Long loginAdminId = SecurityFrameworkUtils.getLoginUserId();
return selectJoinPage(reqVO, CrmInvoiceRespVO.class, new MPJLambdaWrapper<CrmInvoiceDO>()
.selectAll(CrmInvoiceDO.class)
.selectAs(CrmCustomerDO::getName,CrmInvoiceRespVO::getCustomerName)

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.crm.dal.mysql.salesperformanceassessment;
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.module.crm.controller.admin.salesperformanceassessment.vo.SalesPerformanceAssessmentPageReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.salesperformanceassessment.SalesPerformanceAssessmentDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 绩效考核设置 Mapper
*
* @author 艾楷
*/
@Mapper
public interface SalesPerformanceAssessmentMapper extends BaseMapperX<SalesPerformanceAssessmentDO> {
default PageResult<SalesPerformanceAssessmentDO> selectPage(SalesPerformanceAssessmentPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<SalesPerformanceAssessmentDO>()
.eqIfPresent(SalesPerformanceAssessmentDO::getCalculationExpression, reqVO.getCalculationExpression())
.eqIfPresent(SalesPerformanceAssessmentDO::getProportion, reqVO.getProportion())
.betweenIfPresent(SalesPerformanceAssessmentDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(SalesPerformanceAssessmentDO::getId));
}
}

View File

@ -0,0 +1,52 @@
package cn.iocoder.yudao.module.crm.dal.mysql.salesperformancesettlement;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.crm.dal.dataobject.salesperformancesettlement.SalesPerformanceSettlementDO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo.*;
import org.apache.ibatis.annotations.Param;
/**
* 销售业绩结算记录 Mapper
*
* @author 艾楷
*/
@Mapper
public interface SalesPerformanceSettlementMapper extends BaseMapperX<SalesPerformanceSettlementDO> {
default PageResult<SalesPerformanceSettlementDO> selectPage(SalesPerformanceSettlementPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<SalesPerformanceSettlementDO>()
.eqIfPresent(SalesPerformanceSettlementDO::getUserId, reqVO.getUserId())
.eqIfPresent(SalesPerformanceSettlementDO::getSalesPerformanceId, reqVO.getSalesPerformanceId())
.eqIfPresent(SalesPerformanceSettlementDO::getYear, reqVO.getYear())
.eqIfPresent(SalesPerformanceSettlementDO::getMonth, reqVO.getMonth())
.eqIfPresent(SalesPerformanceSettlementDO::getActualPayment, reqVO.getActualPayment())
.eqIfPresent(SalesPerformanceSettlementDO::getActualSale, reqVO.getActualSale())
.eqIfPresent(SalesPerformanceSettlementDO::getScore, reqVO.getScore())
.eqIfPresent(SalesPerformanceSettlementDO::getTotalScore, reqVO.getTotalScore())
.eqIfPresent(SalesPerformanceSettlementDO::getConfirmFlag, reqVO.getConfirmFlag())
.betweenIfPresent(SalesPerformanceSettlementDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(SalesPerformanceSettlementDO::getId));
}
/**
*
* @param vo
* @param page
* @return
*/
IPage<SalesPerformanceSettlementDO> getSalesPerformanceSettlementPage(@Param("vo") SalesPerformanceSettlementPageReqVO vo, @Param("page") Page page);
/**
*
* @param id
* @return
*/
SalesPerformanceSettlementDO getSalesPerformanceSettlement(@Param("id") Long id);
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.crm.dal.mysql.salesperformanceweight;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.crm.dal.dataobject.salesperformanceweight.SalesPerformanceWeightDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformanceweight.vo.*;
/**
* 销售业绩权重设置 Mapper
*
* @author 艾楷
*/
@Mapper
public interface SalesPerformanceWeightMapper extends BaseMapperX<SalesPerformanceWeightDO> {
default PageResult<SalesPerformanceWeightDO> selectPage(SalesPerformanceWeightPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<SalesPerformanceWeightDO>()
.eqIfPresent(SalesPerformanceWeightDO::getSaleWeight, reqVO.getSaleWeight())
.eqIfPresent(SalesPerformanceWeightDO::getPaymentWeight, reqVO.getPaymentWeight())
.eqIfPresent(SalesPerformanceWeightDO::getScoreWeight, reqVO.getScoreWeight())
.betweenIfPresent(SalesPerformanceWeightDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(SalesPerformanceWeightDO::getId));
}
}

View File

@ -2,19 +2,24 @@ 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.bpm.api.oa.BpmOASalesPerformanceApi;
import cn.iocoder.yudao.module.hrm.api.crmbusiness.BusinessApi;
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.auth.AdminOauthUserOtherInfoApi;
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.mail.MailSendApi;
import cn.iocoder.yudao.module.system.api.notice.NoticeApi;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.sms.SmsSendApi;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import org.springframework.cloud.openfeign.EnableFeignClients;
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, BpmOAReceiptApi.class})
@EnableFeignClients(clients = {DeptApi.class, DictDataApi.class, AdminUserApi.class, StoreProductApi.class, StoreProductAttrValueApi.class, SmsSendApi.class, MailSendApi.class, NoticeApi.class,
BpmOAContractApi.class, BpmOAReceiptApi.class, BpmOASalesPerformanceApi.class, AdminOauthUserOtherInfoApi.class, SubscribeMessageSendApi.class, RoleApi.class, BusinessApi.class})
public class RpcConfiguration {
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.crm.job.salesperformance;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.crm.service.salesperformancesettlement.SalesPerformanceSettlementService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
@Slf4j
public class AutoConfirmJob {
// TODO: 2024/11/04 - 每个月月初03号 未确认的 自动确认上个月的结算记录
@Resource
private SalesPerformanceSettlementService salesPerformanceSettlementService;
@XxlJob("autoConfirmJob")
@TenantJob // --- 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
public ReturnT<String> execute() {
log.info("开始 自动确认");
salesPerformanceSettlementService.autoConfirmJob();
log.info("结束 自动确认");
return ReturnT.SUCCESS;
}
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.crm.job.salesperformance;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.crm.service.crmclues.CrmCluesService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
@Slf4j
public class FollowUpCluesJob {
// TODO: 2024/11/04 - 每天晚上2点 执行一次 判断三天内是否有跟进
@Resource
private CrmCluesService cluesService;
@XxlJob("followUpClues")
@TenantJob // --- 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
public ReturnT<String> execute() {
log.info("开始 线索跟进任务");
cluesService.autoConfirmJob();
log.info("结束 线索跟进任务");
return ReturnT.SUCCESS;
}
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.crm.job.salesperformance;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.crm.service.salesperformancesettlement.SalesPerformanceSettlementService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
@Slf4j
public class GenerateSalesPerformanceJob {
// TODO: 2024/11/04 - 每个月最后一天晚上11点半 执行一次
@Resource
private SalesPerformanceSettlementService salesPerformanceSettlementService;
@XxlJob("generateSalesPerformanceJob")
@TenantJob // --- 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
public ReturnT<String> execute() {
log.info("开始 生产下一个月的销售业绩");
salesPerformanceSettlementService.generateSalesPerformanceJob();
log.info("结束 生产下一个月的销售业绩");
return ReturnT.SUCCESS;
}
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.crm.job.salesperformance;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.crm.service.salesperformancesettlement.SalesPerformanceSettlementService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
@Component
@Slf4j
public class SalesPerformanceJob {
// TODO: 2024/11/04 - 每个月月初 凌晨0点01分结算上个月的数据
@Resource
private SalesPerformanceSettlementService salesPerformanceSettlementService;
@XxlJob("salesPerformanceJob")
@TenantJob // --- 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
public ReturnT<String> execute() throws Exception {
log.info("开始 销售业绩结算");
salesPerformanceSettlementService.settlement();
log.info("结束 销售业绩结算");
return ReturnT.SUCCESS;
}
}

View File

@ -357,11 +357,6 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
.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 (CollectionUtil.isNotEmpty(receiptDTOS)) {
receivablesSuccessMoney = receiptDTOS

View File

@ -198,6 +198,9 @@ public class AchievementServiceImpl implements AchievementService {
} else if (RelationEnum.SUB.getValue().equals(relation)) {
userIds = userLiveTreeService.getItemIdsByUserId(userId);
}
if (CollUtil.isEmpty(userIds)){
return Collections.emptyList();
}
//合同目标
List<CrmAchievementDO> crmAchievementDO = achievementMapper.selectList(new LambdaQueryWrapperX<CrmAchievementDO>()
.eq(CrmAchievementDO::getType, FlowStepEnum.TYPE_2.getValue())
@ -364,6 +367,9 @@ public class AchievementServiceImpl implements AchievementService {
} else if (RelationEnum.SUB.getValue().equals(relation)) {
userIds = userLiveTreeService.getItemIdsByUserId(userId);
}
if (CollUtil.isEmpty(userIds)){
return Collections.emptyList();
}
List<SalesVO> salesVOS = new ArrayList<>();
int i = 1;
while (i <= 12) {

View File

@ -137,7 +137,7 @@ public class CustomerServiceImpl implements CustomerService {
pageResult1.getList().forEach(v -> {
String per = "0";
String per = "0.00";
if (customerMap.get(v.getId()) == null) {
v.setCustomerCount(0L);
v.setSuccessCount(0L);

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessSaveReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessTransferVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessProductDO;
import javax.validation.Valid;
@ -65,4 +66,18 @@ public interface CrmBusinessService {
*/
List<CrmBusinessProductDO> getBusinessProductListByBusinessId(Long businessId);
/**
* 转移商机
*
* @param transferVO
*/
void transfer(@Valid CrmBusinessTransferVO transferVO);
/**
* 更新商机状态
*
* @param id
* @param isEnd
*/
void updateIsEnd(Long id, Integer isEnd);
}

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.crm.service.crmbusiness;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
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;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
@ -8,7 +10,7 @@ import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessSaveReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmclues.vo.CrmCluesRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessTransferVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessProductDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
@ -17,13 +19,13 @@ import cn.iocoder.yudao.module.crm.dal.mysql.crmbusiness.CrmBusinessMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmbusiness.CrmBusinessProductMapper;
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.crm.service.crmoperatelog.CrmOperatelogService;
import cn.iocoder.yudao.module.crm.service.userlivetree.UserLiveTreeService;
import cn.iocoder.yudao.module.hrm.enums.RelationEnum;
import cn.iocoder.yudao.module.hrm.enums.TypesEnum;
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.StoreProductAttrValueApi;
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.dto.StoreProductAttrValueApiDTO;
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.vo.StoreProductAttrValueApiVO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.stereotype.Service;
@ -34,6 +36,7 @@ import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -61,6 +64,8 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
private CrmRecordMapper crmRecordMapper;
@Resource
private UserLiveTreeService userLiveTreeService;
@Resource
private CrmOperatelogService crmOperatelogService;
@Override
@Transactional(rollbackFor = Exception.class)
@ -130,7 +135,9 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
} else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
ids = userLiveTreeService.getItemIdsByUserId(adminId);
}
if (CollUtil.isEmpty(ids)) {
return PageResult.empty();
}
IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
IPage<CrmBusinessRespVO> page = businessMapper.selectPageList(mpPage, pageReqVO, ids);
return new PageResult<>(page.getRecords(), page.getTotal());
@ -160,6 +167,52 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
return businessProductDOS;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void transfer(CrmBusinessTransferVO transferVO) {
//客户
List<CrmBusinessDO> crmBusinessDOS = businessMapper.selectBatchIds(transferVO.getBusinessIds());
if (crmBusinessDOS == null || crmBusinessDOS.isEmpty()) {
throw exception(new ErrorCode(202409091, "商机信息不存在"));
}
int adminCount = transferVO.getOwnerAdminIds().size();
int i = 0;
List<CrmBusinessDO> businessUpdateList = new ArrayList<>();
for (CrmBusinessDO businessDO : crmBusinessDOS) {
Long adminId;
if (ShopCommonEnum.AVG_1.getValue().equals(transferVO.getAverageType())) {
//平均分配
adminId = transferVO.getOwnerAdminIds().get(i);
if (i == (adminCount - 1)) {
i = 0;
} else {
i++;
}
} else {
//随机分配
Random random = new Random();
int num = random.nextInt(adminCount);
adminId = transferVO.getOwnerAdminIds().get(num);
}
businessDO.setOwnerUserId(adminId);
businessUpdateList.add(businessDO);
//处理日志
crmOperatelogService.createLog("转移商机", businessDO.getCustomerId(), 0L, 0L);
}
if (CollUtil.isNotEmpty(businessUpdateList)) {
businessMapper.updateBatch(businessUpdateList);
}
}
@Override
public void updateIsEnd(Long id, Integer isEnd) {
CrmBusinessDO businessDO = new CrmBusinessDO();
businessDO.setId(id);
businessDO.setIsEnd(isEnd);
businessMapper.updateById(businessDO);
}
private void createBusinessProductList(Long businessId, List<CrmBusinessProductDO> list) {
list.forEach(o -> o.setBusinessId(businessId));
businessProductMapper.insertBatch(list);

View File

@ -57,27 +57,31 @@ public interface CrmCluesService {
/**
* 放入线索池
*
* @param id
*/
void openClues(Long id);
/**
* 领取线索
*
* @param id
*/
void receiveClues(Long id);
/**
* 线索转换成客户
*
* @param createReqVO
*/
void createCustomer(CrmCustomerSaveReqVO createReqVO);
/**
* 线索导入
*
* @param importUsers 导入文件
* @param deptId 部门ID
* @param adminIds 用户ID
* @param deptId 部门ID
* @param adminIds 用户ID
* @param averageType 导入类型
* @return
*/
@ -85,14 +89,21 @@ public interface CrmCluesService {
/**
* 转移线索
*
* @param transferVO
*/
void transfer(CrmCluesTransferVO transferVO);
/**
* 获取指定用户的线索统计信息
*
* @param ownerUserIds 用户ID
* @return 线索统计信息列表
*/
List<CrmCluesStatisticsRespVO> getCluesStatisticsByUserIds(List<Long> ownerUserIds, LocalDateTime[] createTime);
/**
* 线索跟进任务
*/
void autoConfirmJob();
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.crm.service.crmclues;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
@ -32,10 +33,7 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Random;
import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -118,7 +116,9 @@ public class CrmCluesServiceImpl implements CrmCluesService {
} else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
ids = userLiveTreeService.getItemIdsByUserId(adminId);
}
if (CollUtil.isEmpty(ids)) {
return PageResult.empty();
}
IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
IPage<CrmCluesRespVO> page = cluesMapper.selectPageList(mpPage, pageReqVO, ids);
return new PageResult<>(page.getRecords(), page.getTotal());
@ -154,16 +154,20 @@ 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,"已经转化成客户!"));
if (CluesStatusEnum.STATUS_1.getValue().equals(crmCluesDO.getStatus())) {
throw exception(new ErrorCode(202411160, "已经转化成客户!"));
}
// 判断客户名称是否唯一
List<String> repeatOwnerUserNameList = customerMapper.getRepeatOwnerUserName(createReqVO.getName());
if (CollUtil.isNotEmpty(repeatOwnerUserNameList) && createReqVO.getRepeatConfirmationFlag() == 0) {
List<String> items = repeatOwnerUserNameList.stream().distinct().collect(Collectors.toList());
throw exception(new ErrorCode(200012, "该客户已被:" + String.join(",", items) + "添加过,是否继续添加?")); }
createReqVO.setId(null);
CrmCustomerDO customerDO = BeanUtils.toBean(createReqVO, CrmCustomerDO.class);
customerDO.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
customerDO.setNextTime(LocalDateTime.now());
customerDO.setCollectTime(LocalDateTime.now());
customerMapper.insert(customerDO);
//更新线索
crmCluesDO.setStatus(CluesStatusEnum.STATUS_1.getValue());
crmCluesDO.setCustomerId(customerDO.getId());
@ -277,4 +281,19 @@ public class CrmCluesServiceImpl implements CrmCluesService {
return cluesMapper.selectStatisticsByUserIds(ownerUserIds, createTime);
}
@Override
public void autoConfirmJob() {
// 获取负责人不为0 并且跟进记录为3天以外的数据
List<CrmCluesDO> crmCluesDOS = cluesMapper.selectList(new LambdaQueryWrapper<CrmCluesDO>()
.ne(CrmCluesDO::getOwnerUserId, 0)
.in(CrmCluesDO::getStatus, Arrays.asList(CluesStatusEnum.STATUS_0.getValue(), CluesStatusEnum.STATUS_NEG_1.getValue()))
.le(CrmCluesDO::getFollowTime, LocalDateTime.now().minusDays(3)));
for (CrmCluesDO crmCluesDO : crmCluesDOS) {
crmCluesDO.setOwnerUserId(0L);
}
if (CollUtil.isNotEmpty(crmCluesDOS)) {
cluesMapper.updateBatch(crmCluesDOS);
}
}
}

View File

@ -6,12 +6,12 @@ import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.CrmContractPa
import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.CrmContractRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.CrmContractSaveReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractProductDO;
import cn.iocoder.yudao.module.hrm.api.crmcontract.dto.CrmContractProductSettlementDTO;
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.vo.UserProductCountVO;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 合同 Service 接口
@ -98,4 +98,11 @@ public interface CrmContractService {
* @return
*/
List<UserProductCountVO> getProductCount(List<Long> userIds, LocalDateTime[] createTime);
/**
* 获取合同结算信息
*
* @return
*/
List<CrmContractProductSettlementDTO> getContractProductSettlement();
}

View File

@ -33,6 +33,7 @@ import cn.iocoder.yudao.module.crm.dal.mysql.crmflow.CrmFlowMapper;
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.service.userlivetree.UserLiveTreeService;
import cn.iocoder.yudao.module.hrm.api.crmcontract.dto.CrmContractProductSettlementDTO;
import cn.iocoder.yudao.module.hrm.enums.ContractStatusEnum;
import cn.iocoder.yudao.module.hrm.enums.FlowStepEnum;
import cn.iocoder.yudao.module.hrm.enums.RelationEnum;
@ -401,31 +402,36 @@ public class CrmContractServiceImpl implements CrmContractService {
return contractMapper.getProductCount(userIds, createTime);
}
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());
List<String> productAttrUnique = list.stream().map(CrmContractProductDO::getProductAttrUnique).collect(Collectors.toList());
storeProductAttrValueList = storeProductAttrValueApi.getStoreProductAttrValueList(new StoreProductAttrValueApiDTO()
.setProductIds(productIds)
.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());
@Override
public List<CrmContractProductSettlementDTO> getContractProductSettlement() {
return contractMapper.getContractProductSettlement();
}
int count = 0;
if (CollUtil.isNotEmpty(storeProductAttrValueApiVOS)) {
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());
});
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());
// List<String> productAttrUnique = list.stream().map(CrmContractProductDO::getProductAttrUnique).collect(Collectors.toList());
// storeProductAttrValueList = storeProductAttrValueApi.getStoreProductAttrValueList(new StoreProductAttrValueApiDTO()
// .setProductIds(productIds)
// .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());
//
// int count = 0;
// if (CollUtil.isNotEmpty(storeProductAttrValueApiVOS)) {
// 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

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.crm.service.crmcontractreceivables;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.PatternPool;
import cn.hutool.core.util.ReUtil;
@ -186,6 +187,9 @@ public class CrmContractReceivablesServiceImpl implements CrmContractReceivables
} else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
ids = userLiveTreeService.getItemIdsByUserId(loginAdminId);
}
if (CollUtil.isEmpty(ids)){
return PageResult.empty();
}
pageReqVO.setLoginAdminId(loginAdminId);
IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
IPage<CrmContractReceivablesRespVO> pageResult = contractReceivablesMapper.selectPageList(mpPage, pageReqVO, ids);

View File

@ -82,12 +82,11 @@ public interface CrmCustomerService {
/**
* 客户导入
* @param importUsers 导入文件
* @param deptId 部门ID
* @param adminIds 用户ID
* @param averageType 导入类型
* @return
*/
CustomerImportRespVO importList(List<CrmCustomerImportVO> importUsers, String deptId, String adminIds, Integer averageType);
CustomerImportRespVO importList(List<CrmCustomerImportVO> importUsers, String adminIds, Integer averageType,Integer repeatConfirmationFlag);
/**

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.crm.service.crmcustomer;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
@ -31,8 +32,6 @@ import cn.iocoder.yudao.module.system.api.mail.dto.MailSendSingleReqDTO;
import cn.iocoder.yudao.module.system.api.sms.SmsSendApi;
import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleReqDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserApiDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserApiVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.stereotype.Service;
@ -41,10 +40,7 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Random;
import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -86,12 +82,18 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
@Override
@Transactional(rollbackFor = Exception.class)
public Long createCustomer(CrmCustomerSaveReqVO createReqVO) {
// 插入
// 判断客户名称是否唯一
List<String> repeatOwnerUserNameList = customerMapper.getRepeatOwnerUserName(createReqVO.getName());
if (CollUtil.isNotEmpty(repeatOwnerUserNameList) && createReqVO.getRepeatConfirmationFlag() == 0) {
List<String> items = repeatOwnerUserNameList.stream().distinct().collect(Collectors.toList());
throw exception(new ErrorCode(200012, "该客户已被:" + String.join(",", items) + "添加过,是否继续添加?"));
}
CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class);
customer.setCollectTime(LocalDateTime.now());
customer.setFollowTime(LocalDateTime.now());
// 由于这里是 size 而排序是从0开始的 所以这里递增一个直接用size即可
customer.setSortNum(repeatOwnerUserNameList.size());
customer.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
customerMapper.insert(customer);
@ -119,8 +121,17 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
public void updateCustomer(CrmCustomerSaveReqVO updateReqVO) {
// 校验存在
CrmCustomerDO customerDO = validateCustomerExists(updateReqVO.getId());
List<String> repeatOwnerUserNameList = customerMapper.getRepeatOwnerUserName(updateReqVO.getName());
if (!customerDO.getName().equals(updateReqVO.getName())
&& CollUtil.isNotEmpty(repeatOwnerUserNameList)
&& updateReqVO.getRepeatConfirmationFlag() == 0) {
List<String> items = repeatOwnerUserNameList.stream().distinct().collect(Collectors.toList());
throw exception(new ErrorCode(200012, "该客户已被:" + String.join(",", items) + "添加过,是否继续添加?")); }
// 更新
CrmCustomerDO updateObj = BeanUtils.toBean(updateReqVO, CrmCustomerDO.class);
// 由于这里是 size 而排序是从0开始的 所以这里递增一个直接用size即可
updateObj.setSortNum(repeatOwnerUserNameList.size());
customerMapper.updateById(updateObj);
//插入日志
@ -245,7 +256,17 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
ids = userLiveTreeService.getItemIdsByUserId(adminId);
}
}
return customerMapper.selectPage(pageReqVO, ids);
if (CollUtil.isEmpty(ids)) {
return PageResult.empty();
}
IPage<CrmCustomerDO> pageResult;
if (pageReqVO.getDistinctFlag() == 0) {
return customerMapper.selectPage(pageReqVO, ids);
} else {
IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
pageResult = customerMapper.selectPageList(mpPage, pageReqVO, ids);
}
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
}
@ -262,43 +283,50 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
ids = userLiveTreeService.getItemIdsByUserId(adminId);
}
}
if (CollUtil.isEmpty(ids)) {
return PageResult.empty();
}
IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
IPage<CrmCustomerRespVO> pageResult = customerMapper.selectPageList(mpPage, pageReqVO, ids);
IPage<CrmCustomerRespVO> pageResult = customerMapper.selectPageList2(mpPage, pageReqVO, ids);
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
}
@Override
public CustomerImportRespVO importList(List<CrmCustomerImportVO> importUsers, String deptId, String adminIds,
Integer averageType) {
public CustomerImportRespVO importList(List<CrmCustomerImportVO> importUsers, String adminIds,
Integer averageType, Integer repeatConfirmationFlag) {
CustomerImportRespVO respVO = CustomerImportRespVO.builder().createNames(new ArrayList<>())
.failureNames(new LinkedHashMap<>()).build();
//处理客户归属方案
//如果只选择了机构没有选择用户直接获取当前部门下的用户
List<Long> userList = new ArrayList<>();
if (StrUtil.isNotEmpty(deptId) && StrUtil.isEmpty(adminIds)) {
List<AdminUserApiVO> adminUserDOS = adminUserApi.getUserList(new AdminUserApiDTO().setDeptId(Long.valueOf(deptId)).setNextDept(1)).getCheckedData();
userList = adminUserDOS.stream().map(AdminUserApiVO::getId).collect(Collectors.toList());
if (userList.isEmpty()) {
throw exception(new ErrorCode(202409080, "当前部门下没有用户,清重新选择"));
}
} else {
if (StrUtil.isNotEmpty(adminIds)) {
userList = StrUtil.split(adminIds, ",").stream().map(Long::parseLong).collect(Collectors.toList());
}
int i = 1;
int j = 0;
int adminCount = userList.size();
List<CrmCustomerDO> customerList = new ArrayList<>();
// -- 查询重复
Map<String, Integer> map = new HashMap<>();
if (repeatConfirmationFlag == 0) {
List<String> nameList = importUsers.stream().map(CrmCustomerImportVO::getName).filter(StrUtil::isNotEmpty).distinct().collect(Collectors.toList());
if (CollUtil.isNotEmpty(nameList)) {
List<CrmCustomerDO> crmCustomerDOS = customerMapper.selectList(new LambdaQueryWrapper<CrmCustomerDO>()
.in(CrmCustomerDO::getName, nameList));
map = crmCustomerDOS.stream().collect(Collectors.groupingBy(CrmCustomerDO::getName, Collectors.summingInt(e -> 1)));
}
}
for (CrmCustomerImportVO importVO : importUsers) {
if (StrUtil.isEmpty(importVO.getName())) {
respVO.getFailureNames().put("" + i + "行:", "客户名称为空,已经被过滤掉");
continue;
}
Long count = customerMapper.selectCount(new LambdaQueryWrapper<CrmCustomerDO>()
.eq(CrmCustomerDO::getName, importVO.getName()));
if (count > 0) {
respVO.getFailureNames().put("" + i + "行:", "客户名称已经存在,已经被过滤掉");
continue;
if (repeatConfirmationFlag == 0) {
Integer num = map.get(importVO.getName());
if (num != null && num > 1) {
respVO.getFailureNames().put("" + i + "行:", "客户名称重复,已经被过滤掉");
continue;
}
}
CrmCustomerDO customer = BeanUtils.toBean(importVO, CrmCustomerDO.class);
Long adminId = 0L;
@ -316,11 +344,22 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
int num = random.nextInt(adminCount);
adminId = userList.get(num);
}
Integer num = map.get(importVO.getName());
if (num != null && num > 1) {
map.put(importVO.getName(), num + 1);
} else if (num == null) {
num = 0;
map.put(importVO.getName(), num);
}
customer.setSortNum(num);
customer.setOwnerUserId(adminId);
customerMapper.insert(customer);
customerList.add(customer);
respVO.getCreateNames().add("" + i + "行:导入成功用户名->" + importVO.getName());
i++;
}
if (!customerList.isEmpty()) {
customerMapper.insertBatch(customerList);
}
return respVO;
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.crm.service.crmcustomercontacts;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;

View File

@ -1,9 +1,11 @@
package cn.iocoder.yudao.module.crm.service.crmindex;
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.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReceiptApi;
@ -101,7 +103,9 @@ public class CrmIndexServiceImpl implements CrmIndexService {
ids = userLiveTreeService.getItemIdsByUserId(adminId);
}
}
if (CollUtil.isEmpty(ids)){
return BrieCountVO.builder().build();
}
Long count01 = businessMapper.selectCount(new LambdaQueryWrapper<CrmBusinessDO>()
.in(!ids.isEmpty(), CrmBusinessDO::getOwnerUserId, ids)
.between(CrmBusinessDO::getCreateTime, todayStart, todayEnd));

View File

@ -1,10 +1,12 @@
package cn.iocoder.yudao.module.crm.service.crminvoice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
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;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.CheckInfoVO;
import cn.iocoder.yudao.module.crm.controller.admin.crminvoice.vo.CrmInvoicePageReqVO;
@ -27,6 +29,7 @@ import cn.iocoder.yudao.module.hrm.enums.*;
import cn.iocoder.yudao.module.system.api.mail.MailSendApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
@ -181,6 +184,9 @@ public class CrmInvoiceServiceImpl implements CrmInvoiceService {
} else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
ids = userLiveTreeService.getItemIdsByUserId(loginAdminId);
}
if (CollUtil.isEmpty(ids)){
return PageResult.empty();
}
PageResult<CrmInvoiceRespVO> pageResult = invoiceMapper.selectPage2(pageReqVO, ids);
for (CrmInvoiceRespVO respVO : pageResult.getList()) {
List<String> adminIds = StrUtil.split(respVO.getFlowAdminId(), ",");

View File

@ -43,7 +43,6 @@ import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.RECORD_NOT_EXISTS;
/**
@ -71,6 +70,7 @@ public class CrmRecordServiceImpl implements CrmRecordService {
private DictDataApi dictDataApi;
@Resource
private UserLiveTreeService userLiveTreeService;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createRecord(CrmRecordSaveReqVO createReqVO) {
@ -156,7 +156,7 @@ public class CrmRecordServiceImpl implements CrmRecordService {
List<CrmRecordUserDO> crmRecordUserDOS = crmRecordUserMapper.selectList(new LambdaQueryWrapper<CrmRecordUserDO>().eq(CrmRecordUserDO::getRecordId, id));
crmRecordUserMapper.delete(new LambdaQueryWrapper<CrmRecordUserDO>().eq(CrmRecordUserDO::getRecordId, id).eq(CrmRecordUserDO::getUserId, adminId));
// 删除如果是最后一个的话删除一下
if (crmRecordUserDOS.size() == 1 && adminId.equals(crmRecordUserDOS.get(0).getUserId())){
if (crmRecordUserDOS.size() == 1 && adminId.equals(crmRecordUserDOS.get(0).getUserId())) {
recordMapper.deleteById(id);
}
}

View File

@ -0,0 +1,56 @@
package cn.iocoder.yudao.module.crm.service.salesperformanceassessment;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformanceassessment.vo.SalesPerformanceAssessmentPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformanceassessment.vo.SalesPerformanceAssessmentSaveReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.salesperformanceassessment.SalesPerformanceAssessmentDO;
import com.baomidou.mybatisplus.extension.service.IService;
import javax.validation.Valid;
/**
* 绩效考核设置 Service 接口
*
* @author 艾楷
*/
public interface SalesPerformanceAssessmentService extends IService<SalesPerformanceAssessmentDO> {
/**
* 创建绩效考核设置
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createSalesPerformanceAssessment(@Valid SalesPerformanceAssessmentSaveReqVO createReqVO);
/**
* 更新绩效考核设置
*
* @param updateReqVO 更新信息
*/
void updateSalesPerformanceAssessment(@Valid SalesPerformanceAssessmentSaveReqVO updateReqVO);
/**
* 删除绩效考核设置
*
* @param id 编号
*/
void deleteSalesPerformanceAssessment(Long id);
/**
* 获得绩效考核设置
*
* @param id 编号
* @return 绩效考核设置
*/
SalesPerformanceAssessmentDO getSalesPerformanceAssessment(Long id);
/**
* 获得绩效考核设置分页
*
* @param pageReqVO 分页查询
* @return 绩效考核设置分页
*/
PageResult<SalesPerformanceAssessmentDO> getSalesPerformanceAssessmentPage(SalesPerformanceAssessmentPageReqVO pageReqVO);
}

View File

@ -0,0 +1,59 @@
package cn.iocoder.yudao.module.crm.service.salesperformanceassessment;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformanceassessment.vo.SalesPerformanceAssessmentPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformanceassessment.vo.SalesPerformanceAssessmentSaveReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.salesperformanceassessment.SalesPerformanceAssessmentDO;
import cn.iocoder.yudao.module.crm.dal.mysql.salesperformanceassessment.SalesPerformanceAssessmentMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 绩效考核设置 Service 实现类
*
* @author 艾楷
*/
@Service
@Validated
public class SalesPerformanceAssessmentServiceImpl extends ServiceImpl<SalesPerformanceAssessmentMapper, SalesPerformanceAssessmentDO> implements SalesPerformanceAssessmentService {
@Resource
private SalesPerformanceAssessmentMapper salesPerformanceAssessmentMapper;
@Override
public Long createSalesPerformanceAssessment(SalesPerformanceAssessmentSaveReqVO createReqVO) {
// 插入
SalesPerformanceAssessmentDO salesPerformanceAssessment = BeanUtils.toBean(createReqVO, SalesPerformanceAssessmentDO.class);
salesPerformanceAssessmentMapper.insert(salesPerformanceAssessment);
// 返回
return salesPerformanceAssessment.getId();
}
@Override
public void updateSalesPerformanceAssessment(SalesPerformanceAssessmentSaveReqVO updateReqVO) {
// 更新
SalesPerformanceAssessmentDO updateObj = BeanUtils.toBean(updateReqVO, SalesPerformanceAssessmentDO.class);
salesPerformanceAssessmentMapper.updateById(updateObj);
}
@Override
public void deleteSalesPerformanceAssessment(Long id) {
// 删除
salesPerformanceAssessmentMapper.deleteById(id);
}
@Override
public SalesPerformanceAssessmentDO getSalesPerformanceAssessment(Long id) {
return salesPerformanceAssessmentMapper.selectById(id);
}
@Override
public PageResult<SalesPerformanceAssessmentDO> getSalesPerformanceAssessmentPage(SalesPerformanceAssessmentPageReqVO pageReqVO) {
return salesPerformanceAssessmentMapper.selectPage(pageReqVO);
}
}

View File

@ -0,0 +1,71 @@
package cn.iocoder.yudao.module.crm.service.salesperformancesettlement;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo.SalesPerformanceSettlementPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo.SalesPerformanceSettlementSaveReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.salesperformancesettlement.SalesPerformanceSettlementDO;
import com.baomidou.mybatisplus.extension.service.IService;
import javax.validation.Valid;
import java.time.LocalDateTime;
/**
* 销售业绩结算记录 Service 接口
*
* @author 艾楷
*/
public interface SalesPerformanceSettlementService extends IService<SalesPerformanceSettlementDO> {
/**
* 创建 - 这里用户crm新增用户
*
* @param now
* @param userId
*/
void createSalesPerformanceSettlement(LocalDateTime now, Long userId);
/**
* 更新销售业绩结算记录
*
* @param updateReqVO 更新信息
*/
void updateSalesPerformanceSettlement(@Valid SalesPerformanceSettlementSaveReqVO updateReqVO);
/**
* 删除销售业绩结算记录
*
* @param id 编号
*/
void deleteSalesPerformanceSettlement(Long id);
/**
* 获得销售业绩结算记录
*
* @param id 编号
* @return 销售业绩结算记录
*/
SalesPerformanceSettlementDO getSalesPerformanceSettlement(Long id);
/**
* 获得销售业绩结算记录分页
*
* @param pageReqVO 分页查询
* @return 销售业绩结算记录分页
*/
PageResult<SalesPerformanceSettlementDO> getSalesPerformanceSettlementPage(SalesPerformanceSettlementPageReqVO pageReqVO);
/**
* 每月结算
*/
void settlement();
/**
* 生成下一个月的业绩
*/
void generateSalesPerformanceJob();
/**
* 自动确认上个月的业绩
*/
void autoConfirmJob();
}

Some files were not shown because too many files have changed in this diff Show More