Merge remote-tracking branch 'upstream/develop' into develop
# Conflicts: # yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java
This commit is contained in:
commit
cd1e73cc3f
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
12
README.md
12
README.md
|
@ -128,6 +128,8 @@
|
||||||
* 数据报表
|
* 数据报表
|
||||||
* 商城系统
|
* 商城系统
|
||||||
* 微信公众号
|
* 微信公众号
|
||||||
|
* ERP 系统
|
||||||
|
* CRM 系统
|
||||||
|
|
||||||
> 友情提示:本项目基于 RuoYi-Vue 修改,**重构优化**后端的代码,**美化**前端的界面。
|
> 友情提示:本项目基于 RuoYi-Vue 修改,**重构优化**后端的代码,**美化**前端的界面。
|
||||||
>
|
>
|
||||||
|
@ -247,12 +249,18 @@
|
||||||
| 🚀 | 会员分组 | 对会员进行分组,用于用户画像、内容推送等运营手段 |
|
| 🚀 | 会员分组 | 对会员进行分组,用于用户画像、内容推送等运营手段 |
|
||||||
| 🚀 | 积分签到 | 回馈给签到、消费等行为的积分,会员可订单抵现、积分兑换等途径消耗 |
|
| 🚀 | 积分签到 | 回馈给签到、消费等行为的积分,会员可订单抵现、积分兑换等途径消耗 |
|
||||||
|
|
||||||
|
### ERP 系统
|
||||||
|
|
||||||
|
![功能图](/.image/common/erp-feature.png)
|
||||||
|
|
||||||
|
演示地址:<https://doc.iocoder.cn/erp-preview/>
|
||||||
|
|
||||||
## 🐨 技术栈
|
## 🐨 技术栈
|
||||||
|
|
||||||
### 模块
|
### 模块
|
||||||
|
|
||||||
| 项目 | 说明 |
|
| 项目 | 说明 |
|
||||||
|--------------------------------------------------------------------------|--------------------|
|
|-----------------------|--------------------|
|
||||||
| `yudao-dependencies` | Maven 依赖版本管理 |
|
| `yudao-dependencies` | Maven 依赖版本管理 |
|
||||||
| `yudao-framework` | Java 框架拓展 |
|
| `yudao-framework` | Java 框架拓展 |
|
||||||
| `yudao-server` | 管理后台 + 用户 APP 的服务端 |
|
| `yudao-server` | 管理后台 + 用户 APP 的服务端 |
|
||||||
|
@ -262,6 +270,8 @@
|
||||||
| `yudao-module-bpm` | 工作流程的 Module 模块 |
|
| `yudao-module-bpm` | 工作流程的 Module 模块 |
|
||||||
| `yudao-module-pay` | 支付系统的 Module 模块 |
|
| `yudao-module-pay` | 支付系统的 Module 模块 |
|
||||||
| `yudao-module-mall` | 商城系统的 Module 模块 |
|
| `yudao-module-mall` | 商城系统的 Module 模块 |
|
||||||
|
| `yudao-module-erp` | ERP 系统的 Module 模块 |
|
||||||
|
| `yudao-module-crm` | CRM 系统的 Module 模块 |
|
||||||
| `yudao-module-mp` | 微信公众号的 Module 模块 |
|
| `yudao-module-mp` | 微信公众号的 Module 模块 |
|
||||||
| `yudao-module-report` | 大屏报表 Module 模块 |
|
| `yudao-module-report` | 大屏报表 Module 模块 |
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package cn.iocoder.yudao.framework.file.core.client;
|
package cn.iocoder.yudao.framework.file.core.client;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.file.core.client.s3.FilePresignedUrlRespDTO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件客户端
|
* 文件客户端
|
||||||
*
|
*
|
||||||
|
@ -40,4 +42,14 @@ public interface FileClient {
|
||||||
*/
|
*/
|
||||||
byte[] getContent(String path) throws Exception;
|
byte[] getContent(String path) throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得文件预签名地址
|
||||||
|
*
|
||||||
|
* @param path 相对路径
|
||||||
|
* @return 文件预签名地址
|
||||||
|
*/
|
||||||
|
default FilePresignedUrlRespDTO getPresignedObjectUrl(String path) throws Exception {
|
||||||
|
throw new UnsupportedOperationException("不支持的操作");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package cn.iocoder.yudao.framework.file.core.client.s3;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件预签名地址 Response DTO
|
||||||
|
*
|
||||||
|
* @author owen
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class FilePresignedUrlRespDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传 URL(用于上传)
|
||||||
|
*
|
||||||
|
* 例如说:
|
||||||
|
*/
|
||||||
|
private String uploadUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件 URL(用于读取、下载等)
|
||||||
|
*/
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
}
|
|
@ -5,8 +5,10 @@ import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
import cn.iocoder.yudao.framework.file.core.client.AbstractFileClient;
|
import cn.iocoder.yudao.framework.file.core.client.AbstractFileClient;
|
||||||
import io.minio.*;
|
import io.minio.*;
|
||||||
|
import io.minio.http.Method;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig.ENDPOINT_ALIYUN;
|
import static cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig.ENDPOINT_ALIYUN;
|
||||||
import static cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig.ENDPOINT_TENCENT;
|
import static cn.iocoder.yudao.framework.file.core.client.s3.S3FileClientConfig.ENDPOINT_TENCENT;
|
||||||
|
@ -117,4 +119,16 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
|
||||||
return IoUtil.readBytes(response);
|
return IoUtil.readBytes(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) throws Exception {
|
||||||
|
String uploadUrl = client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
|
||||||
|
.method(Method.PUT)
|
||||||
|
.bucket(config.getBucket())
|
||||||
|
.object(path)
|
||||||
|
.expiry(10, TimeUnit.MINUTES) // 过期时间(秒数)取值范围:1 秒 ~ 7 天
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
return new FilePresignedUrlRespDTO(uploadUrl, config.getDomain() + "/" + path);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,10 @@ public class BannerApplicationRunner implements ApplicationRunner {
|
||||||
if (isNotPresent("cn.iocoder.yudao.module.trade.framework.web.config.TradeWebConfiguration")) {
|
if (isNotPresent("cn.iocoder.yudao.module.trade.framework.web.config.TradeWebConfiguration")) {
|
||||||
System.out.println("[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
|
System.out.println("[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
|
||||||
}
|
}
|
||||||
|
// ERP 系统
|
||||||
|
if (isNotPresent("cn.iocoder.yudao.module.erp.framework.web.config.ErpWebConfiguration")) {
|
||||||
|
System.out.println("[ERP 系统 yudao-module-erp - 已禁用][参考 https://doc.iocoder.cn/erp/build/ 开启]");
|
||||||
|
}
|
||||||
// 支付平台
|
// 支付平台
|
||||||
if (isNotPresent("cn.iocoder.yudao.module.pay.framework.pay.config.PayConfiguration")) {
|
if (isNotPresent("cn.iocoder.yudao.module.pay.framework.pay.config.PayConfiguration")) {
|
||||||
System.out.println("[支付系统 yudao-module-pay - 已禁用][参考 https://doc.iocoder.cn/pay/build/ 开启]");
|
System.out.println("[支付系统 yudao-module-pay - 已禁用][参考 https://doc.iocoder.cn/pay/build/ 开启]");
|
||||||
|
|
|
@ -313,7 +313,13 @@ public class GlobalExceptionHandler {
|
||||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||||
"[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
|
"[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
|
||||||
}
|
}
|
||||||
// 5. 支付平台
|
// 5. ERP 系统
|
||||||
|
if (message.contains("erp_")) {
|
||||||
|
log.error("[ERP 系统 yudao-module-erp - 表结构未导入][参考 https://doc.iocoder.cn/erp/build/ 开启]");
|
||||||
|
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||||
|
"[ERP 系统 yudao-module-erp - 表结构未导入][参考 https://doc.iocoder.cn/erp/build/ 开启]");
|
||||||
|
}
|
||||||
|
// 6. 支付平台
|
||||||
if (message.contains("pay_")) {
|
if (message.contains("pay_")) {
|
||||||
log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]");
|
log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]");
|
||||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||||
|
|
|
@ -93,6 +93,8 @@ public interface LogRecordConstants {
|
||||||
String CRM_CONTRACT_DELETE_SUCCESS = "删除了合同【{{#contractName}}】";
|
String CRM_CONTRACT_DELETE_SUCCESS = "删除了合同【{{#contractName}}】";
|
||||||
String CRM_CONTRACT_TRANSFER_SUB_TYPE = "转移合同";
|
String CRM_CONTRACT_TRANSFER_SUB_TYPE = "转移合同";
|
||||||
String CRM_CONTRACT_TRANSFER_SUCCESS = "将合同【{{#contract.name}}】的负责人从【{getAdminUserById{#contract.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】";
|
String CRM_CONTRACT_TRANSFER_SUCCESS = "将合同【{{#contract.name}}】的负责人从【{getAdminUserById{#contract.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】";
|
||||||
|
String CRM_CONTRACT_SUBMIT_SUB_TYPE = "提交合同审批";
|
||||||
|
String CRM_CONTRACT_SUBMIT_SUCCESS = "提交合同【{{#contractName}}】审批成功";
|
||||||
|
|
||||||
// ======================= CRM_PRODUCT 产品 =======================
|
// ======================= CRM_PRODUCT 产品 =======================
|
||||||
|
|
||||||
|
|
|
@ -42,4 +42,46 @@ public class CrmBiRankController {
|
||||||
return success(rankingService.getReceivablePriceRank(rankingReqVO));
|
return success(rankingService.getReceivablePriceRank(rankingReqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-contract-count-rank")
|
||||||
|
@Operation(summary = "获得签约合同数量排行榜")
|
||||||
|
@PreAuthorize("@ss.hasPermission('crm:bi-rank:query')")
|
||||||
|
public CommonResult<List<CrmBiRanKRespVO>> getContractCountRank(@Valid CrmBiRankReqVO rankingReqVO) {
|
||||||
|
return success(rankingService.getContractCountRank(rankingReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-product-sales-rank")
|
||||||
|
@Operation(summary = "获得产品销量排行榜")
|
||||||
|
@PreAuthorize("@ss.hasPermission('crm:bi-rank:query')")
|
||||||
|
public CommonResult<List<CrmBiRanKRespVO>> getProductSalesRank(@Valid CrmBiRankReqVO rankingReqVO) {
|
||||||
|
return success(rankingService.getProductSalesRank(rankingReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-customer-count-rank")
|
||||||
|
@Operation(summary = "获得新增客户数排行榜")
|
||||||
|
@PreAuthorize("@ss.hasPermission('crm:bi-rank:query')")
|
||||||
|
public CommonResult<List<CrmBiRanKRespVO>> getCustomerCountRank(@Valid CrmBiRankReqVO rankingReqVO) {
|
||||||
|
return success(rankingService.getCustomerCountRank(rankingReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-contacts-count-rank")
|
||||||
|
@Operation(summary = "获得新增联系人数排行榜")
|
||||||
|
@PreAuthorize("@ss.hasPermission('crm:bi-rank:query')")
|
||||||
|
public CommonResult<List<CrmBiRanKRespVO>> getContactsCountRank(@Valid CrmBiRankReqVO rankingReqVO) {
|
||||||
|
return success(rankingService.getContactsCountRank(rankingReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-follow-count-rank")
|
||||||
|
@Operation(summary = "获得跟进次数排行榜")
|
||||||
|
@PreAuthorize("@ss.hasPermission('crm:bi-rank:query')")
|
||||||
|
public CommonResult<List<CrmBiRanKRespVO>> getFollowCountRank(@Valid CrmBiRankReqVO rankingReqVO) {
|
||||||
|
return success(rankingService.getFollowCountRank(rankingReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-follow-customer-count-rank")
|
||||||
|
@Operation(summary = "获得跟进客户数排行榜")
|
||||||
|
@PreAuthorize("@ss.hasPermission('crm:bi-rank:query')")
|
||||||
|
public CommonResult<List<CrmBiRanKRespVO>> getFollowCustomerCountRank(@Valid CrmBiRankReqVO rankingReqVO) {
|
||||||
|
return success(rankingService.getFollowCustomerCountRank(rankingReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusiness
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeQueryVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeQueryVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeRespVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeRespVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeSaveReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeSaveReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.convert.businessstatus.CrmBusinessStatusConvert;
|
import cn.iocoder.yudao.module.crm.convert.business.CrmBusinessStatusConvert;
|
||||||
import cn.iocoder.yudao.module.crm.convert.businessstatustype.CrmBusinessStatusTypeConvert;
|
import cn.iocoder.yudao.module.crm.convert.business.CrmBusinessStatusTypeConvert;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO;
|
||||||
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusService;
|
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusService;
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business;
|
package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.product.CrmBusinessProductSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.enums.business.CrmBizEndStatus;
|
import cn.iocoder.yudao.module.crm.enums.business.CrmBizEndStatus;
|
||||||
import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerParseFunction;
|
import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerParseFunction;
|
||||||
import com.mzt.logapi.starter.annotation.DiffLogField;
|
import com.mzt.logapi.starter.annotation.DiffLogField;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
@ -58,7 +58,6 @@ public class CrmBusinessSaveReqVO {
|
||||||
@DiffLogField(name = "商机金额")
|
@DiffLogField(name = "商机金额")
|
||||||
private Integer price;
|
private Integer price;
|
||||||
|
|
||||||
// TODO @lzxhqs:折扣使用 Integer 类型,存储时,默认 * 100;展示的时候,前端需要 / 100;避免精度丢失问题
|
|
||||||
@Schema(description = "整单折扣")
|
@Schema(description = "整单折扣")
|
||||||
@DiffLogField(name = "整单折扣")
|
@DiffLogField(name = "整单折扣")
|
||||||
private Integer discountPercent;
|
private Integer discountPercent;
|
||||||
|
@ -75,11 +74,30 @@ public class CrmBusinessSaveReqVO {
|
||||||
@InEnum(CrmBizEndStatus.class)
|
@InEnum(CrmBizEndStatus.class)
|
||||||
private Integer endStatus;
|
private Integer endStatus;
|
||||||
|
|
||||||
// TODO @lzxhqs:不设置默认 new ArrayList<>();一般 pojo 不设置默认值哈
|
|
||||||
@Schema(description = "商机产品列表")
|
|
||||||
private List<CrmBusinessProductSaveReqVO> products = new ArrayList<>();
|
|
||||||
|
|
||||||
@Schema(description = "联系人编号", example = "110")
|
@Schema(description = "联系人编号", example = "110")
|
||||||
private Long contactId; // 使用场景,在【联系人详情】添加商机时,如果需要关联两者,需要传递 contactId 字段
|
private Long contactId; // 使用场景,在【联系人详情】添加商机时,如果需要关联两者,需要传递 contactId 字段
|
||||||
|
|
||||||
|
// TODO @puhui999:传递 items 就行啦;
|
||||||
|
@Schema(description = "产品列表")
|
||||||
|
private List<CrmBusinessProductItem> productItems;
|
||||||
|
|
||||||
|
@Schema(description = "产品列表")
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class CrmBusinessProductItem {
|
||||||
|
|
||||||
|
@Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529")
|
||||||
|
@NotNull(message = "产品编号不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
|
||||||
|
@NotNull(message = "产品数量不能为空")
|
||||||
|
private Integer count;
|
||||||
|
|
||||||
|
@Schema(description = "产品折扣")
|
||||||
|
private Integer discountPercent;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.crm.controller.admin.business.vo.product;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// TODO @lzxhqs:这个类,如果没用到,可以考虑删除哈
|
|
||||||
@Schema(description = "管理后台 - 商机产品分页 Request VO")
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class CrmBusinessProductPageReqVO extends PageParam {
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.crm.controller.admin.business.vo.product;
|
|
||||||
|
|
||||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 商机产品关联 Response VO")
|
|
||||||
@Data
|
|
||||||
@ExcelIgnoreUnannotated
|
|
||||||
public class CrmBusinessProductRespVO {
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.crm.controller.admin.business.vo.product;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
@Schema(description = "管理后台 - CRM 商机产品关联表 创建/更新 Request VO")
|
|
||||||
@Data
|
|
||||||
public class CrmBusinessProductSaveReqVO {
|
|
||||||
|
|
||||||
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320")
|
|
||||||
@NotNull(message = "商机编号不能为空")
|
|
||||||
private Long businessId;
|
|
||||||
|
|
||||||
@Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320")
|
|
||||||
@NotNull(message = "产品编号不能为空")
|
|
||||||
private Long productId;
|
|
||||||
|
|
||||||
@Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320")
|
|
||||||
@NotNull(message = "产品单价不能为空")
|
|
||||||
private BigDecimal price;
|
|
||||||
|
|
||||||
@Schema(description = "销售价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320")
|
|
||||||
@NotNull(message = "销售价格不能为空")
|
|
||||||
private BigDecimal salesPrice;
|
|
||||||
|
|
||||||
@Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320")
|
|
||||||
@NotNull(message = "数量不能为空")
|
|
||||||
private BigDecimal num;
|
|
||||||
|
|
||||||
@Schema(description = "折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320")
|
|
||||||
@NotNull(message = "折扣不能为空")
|
|
||||||
private BigDecimal discount;
|
|
||||||
|
|
||||||
@Schema(description = "小计(折扣后价格)", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320")
|
|
||||||
@NotNull(message = "小计(折扣后价格)不能为空")
|
|
||||||
private BigDecimal subtotal;
|
|
||||||
|
|
||||||
@Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320")
|
|
||||||
@NotEmpty(message = "单位不能为空")
|
|
||||||
private String unit;
|
|
||||||
|
|
||||||
}
|
|
|
@ -8,15 +8,17 @@ import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.*;
|
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractRespVO;
|
||||||
|
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert;
|
import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
|
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
||||||
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessProductService;
|
|
||||||
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
|
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
|
||||||
import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
|
import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
|
||||||
import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
|
import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
|
||||||
|
@ -30,7 +32,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
@ -43,9 +44,9 @@ import java.util.stream.Stream;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
|
|
||||||
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
||||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
|
||||||
@Tag(name = "管理后台 - CRM 合同")
|
@Tag(name = "管理后台 - CRM 合同")
|
||||||
@RestController
|
@RestController
|
||||||
|
@ -62,11 +63,7 @@ public class CrmContractController {
|
||||||
@Resource
|
@Resource
|
||||||
private CrmBusinessService businessService;
|
private CrmBusinessService businessService;
|
||||||
@Resource
|
@Resource
|
||||||
@Lazy
|
|
||||||
private CrmBusinessProductService businessProductService;
|
|
||||||
@Resource
|
|
||||||
private CrmProductService productService;
|
private CrmProductService productService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private AdminUserApi adminUserApi;
|
private AdminUserApi adminUserApi;
|
||||||
|
|
||||||
|
@ -105,22 +102,9 @@ public class CrmContractController {
|
||||||
return success(null);
|
return success(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.1 拼接合同信息
|
// 2. 拼接合同信息
|
||||||
List<CrmContractRespVO> respVOList = buildContractDetailList(Collections.singletonList(contract));
|
List<CrmContractRespVO> respVOList = buildContractDetailList(singletonList(contract));
|
||||||
// 2.2 拼接产品信息
|
return success(respVOList.get(0));
|
||||||
// TODO @puhui999:下面这块也可以搞到 convert 里哈;可以在 ContractDetailList 加个开关,是不是查询商品信息;ps:jdk21 的方法不太能去用,因为 jdk8 项目要兼容;
|
|
||||||
CrmContractRespVO respVO = respVOList.get(0);
|
|
||||||
List<CrmBusinessProductDO> businessProductList = businessProductService.getBusinessProductListByContractId(id);
|
|
||||||
Map<Long, CrmBusinessProductDO> businessProductMap = convertMap(businessProductList, CrmBusinessProductDO::getProductId);
|
|
||||||
List<CrmProductDO> productList = productService.getProductListByIds(convertSet(businessProductList, CrmBusinessProductDO::getProductId));
|
|
||||||
respVO.setProductItems(convertList(productList, product -> {
|
|
||||||
CrmContractRespVO.CrmContractProductItemRespVO productItemRespVO = BeanUtils.toBean(product, CrmContractRespVO.CrmContractProductItemRespVO.class);
|
|
||||||
findAndThen(businessProductMap, product.getId(), businessProduct -> {
|
|
||||||
productItemRespVO.setCount(businessProduct.getCount()).setDiscountPercent(businessProduct.getDiscountPercent());
|
|
||||||
});
|
|
||||||
return productItemRespVO;
|
|
||||||
}));
|
|
||||||
return success(respVO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/page")
|
@GetMapping("/page")
|
||||||
|
@ -147,8 +131,24 @@ public class CrmContractController {
|
||||||
HttpServletResponse response) throws IOException {
|
HttpServletResponse response) throws IOException {
|
||||||
PageResult<CrmContractDO> pageResult = contractService.getContractPage(exportReqVO, getLoginUserId());
|
PageResult<CrmContractDO> pageResult = contractService.getContractPage(exportReqVO, getLoginUserId());
|
||||||
// 导出 Excel
|
// 导出 Excel
|
||||||
ExcelUtils.write(response, "合同.xls", "数据", CrmContractExcelVO.class,
|
ExcelUtils.write(response, "合同.xls", "数据", CrmContractRespVO.class,
|
||||||
BeanUtils.toBean(pageResult.getList(), CrmContractExcelVO.class));
|
BeanUtils.toBean(pageResult.getList(), CrmContractRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/transfer")
|
||||||
|
@Operation(summary = "合同转移")
|
||||||
|
@PreAuthorize("@ss.hasPermission('crm:contract:update')")
|
||||||
|
public CommonResult<Boolean> transferContract(@Valid @RequestBody CrmContractTransferReqVO reqVO) {
|
||||||
|
contractService.transferContract(reqVO, getLoginUserId());
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/submit")
|
||||||
|
@Operation(summary = "提交合同审批")
|
||||||
|
@PreAuthorize("@ss.hasPermission('crm:contract:update')")
|
||||||
|
public CommonResult<Boolean> submitContract(@RequestParam("id") Long id) {
|
||||||
|
contractService.submitContract(id, getLoginUserId());
|
||||||
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,23 +173,15 @@ public class CrmContractController {
|
||||||
// 4. 获取商机
|
// 4. 获取商机
|
||||||
Map<Long, CrmBusinessDO> businessMap = convertMap(businessService.getBusinessList(convertSet(contractList,
|
Map<Long, CrmBusinessDO> businessMap = convertMap(businessService.getBusinessList(convertSet(contractList,
|
||||||
CrmContractDO::getBusinessId)), CrmBusinessDO::getId);
|
CrmContractDO::getBusinessId)), CrmBusinessDO::getId);
|
||||||
return CrmContractConvert.INSTANCE.convertList(contractList, userMap, customerList, contactMap, businessMap);
|
// 5. 获取合同关联的商品
|
||||||
|
Map<Long, CrmContractProductDO> contractProductMap = null;
|
||||||
|
List<CrmProductDO> productList = null;
|
||||||
|
if (contractList.size() == 1) {
|
||||||
|
List<CrmContractProductDO> contractProductList = contractService.getContractProductListByContractId(contractList.get(0).getId());
|
||||||
|
contractProductMap = convertMap(contractProductList, CrmContractProductDO::getProductId);
|
||||||
|
productList = productService.getProductListByIds(convertSet(contractProductList, CrmContractProductDO::getProductId));
|
||||||
}
|
}
|
||||||
|
return CrmContractConvert.INSTANCE.convertList(contractList, userMap, customerList, contactMap, businessMap, contractProductMap, productList);
|
||||||
@PutMapping("/transfer")
|
|
||||||
@Operation(summary = "合同转移")
|
|
||||||
@PreAuthorize("@ss.hasPermission('crm:contract:update')")
|
|
||||||
public CommonResult<Boolean> transferContract(@Valid @RequestBody CrmContractTransferReqVO reqVO) {
|
|
||||||
contractService.transferContract(reqVO, getLoginUserId());
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/submit")
|
|
||||||
@Operation(summary = "提交合同审批")
|
|
||||||
@PreAuthorize("@ss.hasPermission('crm:contract:update')")
|
|
||||||
public CommonResult<Boolean> submitContract(@RequestParam("id") Long id) {
|
|
||||||
contractService.submitContract(id, getLoginUserId());
|
|
||||||
return success(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/check-contract-count")
|
@GetMapping("/check-contract-count")
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.crm.controller.admin.contract.vo;
|
|
||||||
|
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
// TODO @puhui999:合并到 RespVO 里哈;
|
|
||||||
/**
|
|
||||||
* CRM 合同 Excel VO
|
|
||||||
*
|
|
||||||
* @author dhb52
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class CrmContractExcelVO {
|
|
||||||
|
|
||||||
@ExcelProperty("合同编号")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@ExcelProperty("合同名称")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@ExcelProperty("客户编号")
|
|
||||||
private Long customerId;
|
|
||||||
|
|
||||||
@ExcelProperty("商机编号")
|
|
||||||
private Long businessId;
|
|
||||||
|
|
||||||
@ExcelProperty("工作流编号")
|
|
||||||
private Long processInstanceId;
|
|
||||||
|
|
||||||
@ExcelProperty("下单日期")
|
|
||||||
private LocalDateTime orderDate;
|
|
||||||
|
|
||||||
@ExcelProperty("负责人的用户编号")
|
|
||||||
private Long ownerUserId;
|
|
||||||
|
|
||||||
@ExcelProperty("合同编号")
|
|
||||||
private String no;
|
|
||||||
|
|
||||||
@ExcelProperty("开始时间")
|
|
||||||
private LocalDateTime startTime;
|
|
||||||
|
|
||||||
@ExcelProperty("结束时间")
|
|
||||||
private LocalDateTime endTime;
|
|
||||||
|
|
||||||
@ExcelProperty("合同金额")
|
|
||||||
private Integer price;
|
|
||||||
|
|
||||||
@ExcelProperty("整单折扣")
|
|
||||||
private Integer discountPercent;
|
|
||||||
|
|
||||||
@ExcelProperty("产品总金额")
|
|
||||||
private Integer productPrice;
|
|
||||||
|
|
||||||
@ExcelProperty("联系人编号")
|
|
||||||
private Long contactId;
|
|
||||||
|
|
||||||
@ExcelProperty("公司签约人")
|
|
||||||
private Long signUserId;
|
|
||||||
|
|
||||||
@ExcelProperty("最后跟进时间")
|
|
||||||
private LocalDateTime contactLastTime;
|
|
||||||
|
|
||||||
@ExcelProperty("备注")
|
|
||||||
private String remark;
|
|
||||||
|
|
||||||
@ExcelProperty("创建时间")
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
|
|
||||||
}
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.contract.vo;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||||
|
import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
|
||||||
import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum;
|
import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -14,7 +15,13 @@ import lombok.ToString;
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class CrmContractPageReqVO extends PageParam {
|
public class CrmContractPageReqVO extends PageParam {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过期类型 - 即将过期
|
||||||
|
*/
|
||||||
public static final Integer EXPIRY_TYPE_ABOUT_TO_EXPIRE = 1;
|
public static final Integer EXPIRY_TYPE_ABOUT_TO_EXPIRE = 1;
|
||||||
|
/**
|
||||||
|
* 过期类型 - 已过期
|
||||||
|
*/
|
||||||
public static final Integer EXPIRY_TYPE_EXPIRED = 2;
|
public static final Integer EXPIRY_TYPE_EXPIRED = 2;
|
||||||
|
|
||||||
@Schema(description = "合同编号", example = "XYZ008")
|
@Schema(description = "合同编号", example = "XYZ008")
|
||||||
|
@ -34,6 +41,7 @@ public class CrmContractPageReqVO extends PageParam {
|
||||||
private Integer sceneType; // 场景类型,为 null 时则表示全部
|
private Integer sceneType; // 场景类型,为 null 时则表示全部
|
||||||
|
|
||||||
@Schema(description = "审批状态", example = "20")
|
@Schema(description = "审批状态", example = "20")
|
||||||
|
@InEnum(CrmAuditStatusEnum.class)
|
||||||
private Integer auditStatus;
|
private Integer auditStatus;
|
||||||
|
|
||||||
@Schema(description = "过期类型", example = "1")
|
@Schema(description = "过期类型", example = "1")
|
||||||
|
|
|
@ -132,6 +132,7 @@ public class CrmContractRespVO {
|
||||||
@Schema(description = "产品列表")
|
@Schema(description = "产品列表")
|
||||||
private List<CrmContractProductItemRespVO> productItems;
|
private List<CrmContractProductItemRespVO> productItems;
|
||||||
|
|
||||||
|
// TODO @puhui999:可以直接叫 Item
|
||||||
@Schema(description = "产品列表")
|
@Schema(description = "产品列表")
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
|
|
|
@ -22,7 +22,6 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.Parameters;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
@ -31,7 +30,6 @@ import org.mapstruct.ap.internal.util.Collections;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
@ -253,19 +251,13 @@ public class CrmCustomerController {
|
||||||
ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list);
|
ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @puhui999:updateSupport 要不改成前端必须传递;哈哈哈,代码排版看着有点乱;
|
|
||||||
// TODO @puhui999:加一个选择负责人;允许空,空就进入公海;
|
|
||||||
@PostMapping("/import")
|
@PostMapping("/import")
|
||||||
@Operation(summary = "导入客户")
|
@Operation(summary = "导入客户")
|
||||||
@Parameters({
|
|
||||||
@Parameter(name = "file", description = "Excel 文件", required = true),
|
|
||||||
@Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true")
|
|
||||||
})
|
|
||||||
@PreAuthorize("@ss.hasPermission('system:customer:import')")
|
@PreAuthorize("@ss.hasPermission('system:customer:import')")
|
||||||
public CommonResult<CrmCustomerImportRespVO> importExcel(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport)
|
public CommonResult<CrmCustomerImportRespVO> importExcel(@Valid @RequestBody CrmCustomerImportReqVO importReqVO)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
List<CrmCustomerImportExcelVO> list = ExcelUtils.read(file, CrmCustomerImportExcelVO.class);
|
List<CrmCustomerImportExcelVO> list = ExcelUtils.read(importReqVO.getFile(), CrmCustomerImportExcelVO.class);
|
||||||
return success(customerService.importCustomerList(list, updateSupport, getLoginUserId()));
|
return success(customerService.importCustomerList(list, importReqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/transfer")
|
@PutMapping("/transfer")
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package cn.iocoder.yudao.module.crm.controller.admin.customer.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 客户导入 Request VO")
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class CrmCustomerImportReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "Excel 文件", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotNull(message = "Excel 文件不能为空")
|
||||||
|
private MultipartFile file;
|
||||||
|
|
||||||
|
@Schema(description = "是否支持更新", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||||
|
@NotNull(message = "是否支持更新不能为空")
|
||||||
|
private Boolean updateSupport;
|
||||||
|
|
||||||
|
@Schema(description = "负责人", example = "1")
|
||||||
|
private Long ownerUserId; // 为 null 则客户进入公海
|
||||||
|
|
||||||
|
}
|
|
@ -14,12 +14,18 @@ import lombok.ToString;
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class CrmReceivablePlanPageReqVO extends PageParam {
|
public class CrmReceivablePlanPageReqVO extends PageParam {
|
||||||
|
|
||||||
// 待回款
|
/**
|
||||||
public final static Integer REMIND_NEEDED = 1;
|
* 提醒类型 - 待回款
|
||||||
// 已逾期
|
*/
|
||||||
public final static Integer REMIND_EXPIRED = 2;
|
public final static Integer REMIND_TYPE_NEEDED = 1;
|
||||||
// 已回款
|
/**
|
||||||
public final static Integer REMIND_RECEIVED = 3;
|
* 提醒类型 - 已逾期
|
||||||
|
*/
|
||||||
|
public final static Integer REMIND_TYPE_EXPIRED = 2;
|
||||||
|
/**
|
||||||
|
* 提醒类型 - 已回款
|
||||||
|
*/
|
||||||
|
public final static Integer REMIND_TYPE_RECEIVED = 3;
|
||||||
|
|
||||||
@Schema(description = "客户编号", example = "18026")
|
@Schema(description = "客户编号", example = "18026")
|
||||||
private Long customerId;
|
private Long customerId;
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||||
|
import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
|
||||||
import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum;
|
import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -28,6 +29,7 @@ public class CrmReceivablePageReqVO extends PageParam {
|
||||||
private Integer sceneType; // 场景类型,为 null 时则表示全部
|
private Integer sceneType; // 场景类型,为 null 时则表示全部
|
||||||
|
|
||||||
@Schema(description = "审批状态", example = "20")
|
@Schema(description = "审批状态", example = "20")
|
||||||
|
@InEnum(CrmAuditStatusEnum.class)
|
||||||
private Integer auditStatus;
|
private Integer auditStatus;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package cn.iocoder.yudao.module.crm.convert.businessstatus;
|
package cn.iocoder.yudao.module.crm.convert.business;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusRespVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusRespVO;
|
|
@ -1,4 +1,4 @@
|
||||||
package cn.iocoder.yudao.module.crm.convert.businessstatustype;
|
package cn.iocoder.yudao.module.crm.convert.business;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeRespVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeRespVO;
|
|
@ -1,21 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.crm.convert.businessproduct;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.product.CrmBusinessProductSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
|
|
||||||
import org.mapstruct.Mapper;
|
|
||||||
import org.mapstruct.factory.Mappers;
|
|
||||||
|
|
||||||
// TODO @lzxhqs:看看是不是用 BeanUtils 替代了
|
|
||||||
/**
|
|
||||||
* @author lzxhqs
|
|
||||||
* @version 1.0
|
|
||||||
* @title CrmBusinessProductConvert
|
|
||||||
* @description
|
|
||||||
* @create 2024/1/12
|
|
||||||
*/
|
|
||||||
@Mapper
|
|
||||||
public interface CrmBusinessProductConvert {
|
|
||||||
CrmBusinessProductConvert INSTANCE = Mappers.getMapper(CrmBusinessProductConvert.class);
|
|
||||||
|
|
||||||
CrmBusinessProductDO convert(CrmBusinessProductSaveReqVO product);
|
|
||||||
}
|
|
|
@ -1,12 +1,16 @@
|
||||||
package cn.iocoder.yudao.module.crm.convert.contract;
|
package cn.iocoder.yudao.module.crm.convert.contract;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractRespVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractRespVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
||||||
import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
|
import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
|
||||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
|
@ -34,7 +38,8 @@ public interface CrmContractConvert {
|
||||||
|
|
||||||
default List<CrmContractRespVO> convertList(List<CrmContractDO> contractList, Map<Long, AdminUserRespDTO> userMap,
|
default List<CrmContractRespVO> convertList(List<CrmContractDO> contractList, Map<Long, AdminUserRespDTO> userMap,
|
||||||
List<CrmCustomerDO> customerList, Map<Long, CrmContactDO> contactMap,
|
List<CrmCustomerDO> customerList, Map<Long, CrmContactDO> contactMap,
|
||||||
Map<Long, CrmBusinessDO> businessMap) {
|
Map<Long, CrmBusinessDO> businessMap, Map<Long, CrmContractProductDO> contractProductMap,
|
||||||
|
List<CrmProductDO> productList) {
|
||||||
List<CrmContractRespVO> respVOList = BeanUtils.toBean(contractList, CrmContractRespVO.class);
|
List<CrmContractRespVO> respVOList = BeanUtils.toBean(contractList, CrmContractRespVO.class);
|
||||||
// 拼接关联字段
|
// 拼接关联字段
|
||||||
Map<Long, CrmCustomerDO> customerMap = convertMap(customerList, CrmCustomerDO::getId);
|
Map<Long, CrmCustomerDO> customerMap = convertMap(customerList, CrmCustomerDO::getId);
|
||||||
|
@ -46,7 +51,20 @@ public interface CrmContractConvert {
|
||||||
findAndThen(contactMap, contract.getContactId(), contact -> contract.setContactName(contact.getName()));
|
findAndThen(contactMap, contract.getContactId(), contact -> contract.setContactName(contact.getName()));
|
||||||
findAndThen(businessMap, contract.getBusinessId(), business -> contract.setBusinessName(business.getName()));
|
findAndThen(businessMap, contract.getBusinessId(), business -> contract.setBusinessName(business.getName()));
|
||||||
});
|
});
|
||||||
|
if (CollUtil.isNotEmpty(respVOList) && respVOList.size() == 1) {
|
||||||
|
setContractRespVOProductItems(respVOList.get(0), contractProductMap, productList);
|
||||||
|
}
|
||||||
return respVOList;
|
return respVOList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void setContractRespVOProductItems(CrmContractRespVO respVO, Map<Long, CrmContractProductDO> contractProductMap,
|
||||||
|
List<CrmProductDO> productList) {
|
||||||
|
respVO.setProductItems(CollectionUtils.convertList(productList, product -> {
|
||||||
|
CrmContractRespVO.CrmContractProductItemRespVO productItemRespVO = BeanUtils.toBean(product, CrmContractRespVO.CrmContractProductItemRespVO.class);
|
||||||
|
findAndThen(contractProductMap, product.getId(), contractProduct ->
|
||||||
|
productItemRespVO.setCount(contractProduct.getCount()).setDiscountPercent(contractProduct.getDiscountPercent()));
|
||||||
|
return productItemRespVO;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package cn.iocoder.yudao.module.crm.dal.dataobject.business;
|
package cn.iocoder.yudao.module.crm.dal.dataobject.business;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
|
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
||||||
import cn.iocoder.yudao.module.crm.enums.DictTypeConstants;
|
|
||||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
@ -41,19 +39,10 @@ public class CrmBusinessProductDO extends BaseDO {
|
||||||
* 关联 {@link CrmProductDO#getId()}
|
* 关联 {@link CrmProductDO#getId()}
|
||||||
*/
|
*/
|
||||||
private Long productId;
|
private Long productId;
|
||||||
// TODO 芋艿:需要在看下 CRM
|
|
||||||
/**
|
|
||||||
* 合同编号
|
|
||||||
*
|
|
||||||
* 关联 {@link CrmContractDO#getId()}
|
|
||||||
*/
|
|
||||||
private Long contractId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 产品单价
|
* 产品单价
|
||||||
*/
|
*/
|
||||||
private Integer price;
|
private Integer price;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 销售价格, 单位:分
|
* 销售价格, 单位:分
|
||||||
*/
|
*/
|
||||||
|
@ -71,11 +60,4 @@ public class CrmBusinessProductDO extends BaseDO {
|
||||||
*/
|
*/
|
||||||
private Integer totalPrice;
|
private Integer totalPrice;
|
||||||
|
|
||||||
/**
|
|
||||||
* 单位
|
|
||||||
*
|
|
||||||
* 字典 {@link DictTypeConstants#CRM_PRODUCT_UNIT}
|
|
||||||
*/
|
|
||||||
private Integer unit;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
package cn.iocoder.yudao.module.crm.dal.dataobject.contract;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合同产品关联表 DO
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
@TableName("crm_contract_product")
|
||||||
|
@KeySequence("crm_contract_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class CrmContractProductDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
|
@TableId
|
||||||
|
private Long id;
|
||||||
|
/**
|
||||||
|
* 产品编号
|
||||||
|
*
|
||||||
|
* 关联 {@link CrmProductDO#getId()}
|
||||||
|
*/
|
||||||
|
private Long productId;
|
||||||
|
/**
|
||||||
|
* 合同编号
|
||||||
|
*
|
||||||
|
* 关联 {@link CrmContractDO#getId()}
|
||||||
|
*/
|
||||||
|
private Long contractId;
|
||||||
|
/**
|
||||||
|
* 产品单价
|
||||||
|
*/
|
||||||
|
private Integer price;
|
||||||
|
/**
|
||||||
|
* 销售价格, 单位:分
|
||||||
|
*/
|
||||||
|
private Integer salesPrice;
|
||||||
|
/**
|
||||||
|
* 数量
|
||||||
|
*/
|
||||||
|
private Integer count;
|
||||||
|
/**
|
||||||
|
* 折扣
|
||||||
|
*/
|
||||||
|
private Integer discountPercent;
|
||||||
|
/**
|
||||||
|
* 总计价格(折扣后价格)
|
||||||
|
*
|
||||||
|
* TODO @puhui999:可以写下计算公式哈;
|
||||||
|
*/
|
||||||
|
private Integer totalPrice;
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +0,0 @@
|
||||||
/**
|
|
||||||
* 合同
|
|
||||||
*/
|
|
||||||
package cn.iocoder.yudao.module.crm.dal.dataobject.contract;
|
|
|
@ -30,4 +30,52 @@ public interface CrmBiRankingMapper {
|
||||||
*/
|
*/
|
||||||
List<CrmBiRanKRespVO> selectReceivablePriceRank(CrmBiRankReqVO rankReqVO);
|
List<CrmBiRanKRespVO> selectReceivablePriceRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询签约合同数量排行榜
|
||||||
|
*
|
||||||
|
* @param rankReqVO 参数
|
||||||
|
* @return 签约合同数量排行榜
|
||||||
|
*/
|
||||||
|
List<CrmBiRanKRespVO> selectContractCountRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询产品销量排行榜
|
||||||
|
*
|
||||||
|
* @param rankReqVO 参数
|
||||||
|
* @return 产品销量排行榜
|
||||||
|
*/
|
||||||
|
List<CrmBiRanKRespVO> selectProductSalesRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询新增客户数排行榜
|
||||||
|
*
|
||||||
|
* @param rankReqVO 参数
|
||||||
|
* @return 新增客户数排行榜
|
||||||
|
*/
|
||||||
|
List<CrmBiRanKRespVO> selectCustomerCountRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询联系人数量排行榜
|
||||||
|
*
|
||||||
|
* @param rankReqVO 参数
|
||||||
|
* @return 联系人数量排行榜
|
||||||
|
*/
|
||||||
|
List<CrmBiRanKRespVO> selectContactsCountRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询跟进次数排行榜
|
||||||
|
*
|
||||||
|
* @param rankReqVO 参数
|
||||||
|
* @return 跟进次数排行榜
|
||||||
|
*/
|
||||||
|
List<CrmBiRanKRespVO> selectFollowCountRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询跟进客户数排行榜
|
||||||
|
*
|
||||||
|
* @param rankReqVO 参数
|
||||||
|
* @return 跟进客户数排行榜
|
||||||
|
*/
|
||||||
|
List<CrmBiRanKRespVO> selectFollowCustomerCountRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,12 @@ package cn.iocoder.yudao.module.crm.dal.mysql.business;
|
||||||
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商机产品 Mapper
|
* 商机产品 Mapper
|
||||||
*
|
*
|
||||||
|
@ -13,12 +16,18 @@ import org.apache.ibatis.annotations.Mapper;
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface CrmBusinessProductMapper extends BaseMapperX<CrmBusinessProductDO> {
|
public interface CrmBusinessProductMapper extends BaseMapperX<CrmBusinessProductDO> {
|
||||||
|
|
||||||
default void deleteByBusinessId(Long id) { // TODO @lzxhqs:第一个方法,和类之间最好空一行;
|
// TODO @puhui999:用不到的方法,看看是不是删除哈
|
||||||
delete(CrmBusinessProductDO::getBusinessId, id);
|
default void deleteByBusinessId(Long getBusinessId) { // TODO @lzxhqs:第一个方法,和类之间最好空一行;
|
||||||
|
delete(CrmBusinessProductDO::getBusinessId, getBusinessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
default CrmBusinessProductDO selectByBusinessId(Long id) {
|
default CrmBusinessProductDO selectByBusinessId(Long getBusinessId) {
|
||||||
return selectOne(CrmBusinessProductDO::getBusinessId, id);
|
return selectOne(CrmBusinessProductDO::getBusinessId, getBusinessId);
|
||||||
|
}
|
||||||
|
|
||||||
|
default List<CrmBusinessProductDO> selectListByBusinessId(Long businessId) {
|
||||||
|
// TODO @puhui999:可以简化,selectList(CrmBusinessProductDO::getBusinessId, businessId)
|
||||||
|
return selectList(new LambdaQueryWrapperX<CrmBusinessProductDO>().eq(CrmBusinessProductDO::getBusinessId, businessId));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,18 +59,15 @@ public interface CrmContractMapper extends BaseMapperX<CrmContractDO> {
|
||||||
// Backlog: 即将到期的合同
|
// Backlog: 即将到期的合同
|
||||||
LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
|
LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
|
||||||
LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now());
|
LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now());
|
||||||
if (CrmContractPageReqVO.EXPIRY_TYPE_ABOUT_TO_EXPIRE.equals(pageReqVO.getExpiryType())) {
|
if (CrmContractPageReqVO.EXPIRY_TYPE_ABOUT_TO_EXPIRE.equals(pageReqVO.getExpiryType())) { // 即将到期
|
||||||
// 即将到期
|
|
||||||
// TODO: @芋艿 需要配置 提前提醒天数
|
// TODO: @芋艿 需要配置 提前提醒天数
|
||||||
int REMIND_DAYS = 20;
|
int REMIND_DAYS = 20;
|
||||||
query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.APPROVE.getStatus())
|
query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.APPROVE.getStatus())
|
||||||
.between(CrmContractDO::getEndTime, beginOfToday, endOfToday.plusDays(REMIND_DAYS));
|
.between(CrmContractDO::getEndTime, beginOfToday, endOfToday.plusDays(REMIND_DAYS));
|
||||||
} else if (CrmContractPageReqVO.EXPIRY_TYPE_EXPIRED.equals(pageReqVO.getExpiryType())) {
|
} else if (CrmContractPageReqVO.EXPIRY_TYPE_EXPIRED.equals(pageReqVO.getExpiryType())) { // 已到期
|
||||||
// 已到期
|
|
||||||
query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.APPROVE.getStatus())
|
query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.APPROVE.getStatus())
|
||||||
.lt(CrmContractDO::getEndTime, endOfToday);
|
.lt(CrmContractDO::getEndTime, endOfToday);
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectJoinPage(pageReqVO, CrmContractDO.class, query);
|
return selectJoinPage(pageReqVO, CrmContractDO.class, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package cn.iocoder.yudao.module.crm.dal.mysql.contract;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合同产品 Mapper
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CrmContractProductMapper extends BaseMapperX<CrmContractProductDO> {
|
||||||
|
|
||||||
|
// TODO @puhui999:用不到的方法,看看是不是删除哈
|
||||||
|
default void deleteByContractId(Long contractId) { // TODO @lzxhqs:第一个方法,和类之间最好空一行;
|
||||||
|
delete(CrmContractProductDO::getContractId, contractId);
|
||||||
|
}
|
||||||
|
|
||||||
|
default CrmContractProductDO selectByContractId(Long contractId) {
|
||||||
|
return selectOne(CrmContractProductDO::getContractId, contractId);
|
||||||
|
}
|
||||||
|
|
||||||
|
default List<CrmContractProductDO> selectListByContractId(Long contractId) {
|
||||||
|
return selectList(new LambdaQueryWrapperX<CrmContractProductDO>().eq(CrmContractProductDO::getContractId, contractId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.crm.dal.mysql.product;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
||||||
|
@ -10,9 +9,6 @@ import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
|
||||||
import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils;
|
import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CRM 产品 Mapper
|
* CRM 产品 Mapper
|
||||||
*
|
*
|
||||||
|
@ -38,9 +34,4 @@ public interface CrmProductMapper extends BaseMapperX<CrmProductDO> {
|
||||||
return selectOne(CrmProductDO::getNo, no);
|
return selectOne(CrmProductDO::getNo, no);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @puhui999:selectBatchIds
|
|
||||||
default List<CrmProductDO> selectListByIds(Collection<Long> ids) {
|
|
||||||
return selectList(new LambdaQueryWrapperX<CrmProductDO>().in(CrmProductDO::getId, ids));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,23 +52,21 @@ public interface CrmReceivablePlanMapper extends BaseMapperX<CrmReceivablePlanDO
|
||||||
// Backlog: 回款提醒类型
|
// Backlog: 回款提醒类型
|
||||||
LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
|
LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
|
||||||
LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now());
|
LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now());
|
||||||
if (CrmReceivablePlanPageReqVO.REMIND_NEEDED.equals(pageReqVO.getRemindType())) {
|
if (CrmReceivablePlanPageReqVO.REMIND_TYPE_NEEDED.equals(pageReqVO.getRemindType())) { // 待回款
|
||||||
// 待回款
|
|
||||||
query.isNull(CrmReceivablePlanDO::getReceivableId)
|
query.isNull(CrmReceivablePlanDO::getReceivableId)
|
||||||
.gt(CrmReceivablePlanDO::getReturnTime, beginOfToday)
|
.gt(CrmReceivablePlanDO::getReturnTime, beginOfToday)
|
||||||
|
// TODO @dhb52:这里看看怎么改成不要使用 to_days
|
||||||
.apply("to_days(return_time) <= to_days(now())+ remind_days");
|
.apply("to_days(return_time) <= to_days(now())+ remind_days");
|
||||||
} else if (CrmReceivablePlanPageReqVO.REMIND_EXPIRED.equals(pageReqVO.getRemindType())) {
|
} else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_EXPIRED.equals(pageReqVO.getRemindType())) { // 已逾期
|
||||||
// 已逾期
|
|
||||||
query.isNull(CrmReceivablePlanDO::getReceivableId)
|
query.isNull(CrmReceivablePlanDO::getReceivableId)
|
||||||
.lt(CrmReceivablePlanDO::getReturnTime, endOfToday);
|
.lt(CrmReceivablePlanDO::getReturnTime, endOfToday);
|
||||||
} else if (CrmReceivablePlanPageReqVO.REMIND_RECEIVED.equals(pageReqVO.getRemindType())) {
|
} else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_RECEIVED.equals(pageReqVO.getRemindType())) { // 已回款
|
||||||
// 已回款
|
|
||||||
query.isNotNull(CrmReceivablePlanDO::getReceivableId)
|
query.isNotNull(CrmReceivablePlanDO::getReceivableId)
|
||||||
.gt(CrmReceivablePlanDO::getReturnTime, beginOfToday)
|
.gt(CrmReceivablePlanDO::getReturnTime, beginOfToday)
|
||||||
|
// TODO @dhb52:这里看看怎么改成不要使用 to_days
|
||||||
.apply("to_days(return_time) <= to_days(now()) + remind_days");
|
.apply("to_days(return_time) <= to_days(now()) + remind_days");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return selectJoinPage(pageReqVO, CrmReceivablePlanDO.class, query);
|
return selectJoinPage(pageReqVO, CrmReceivablePlanDO.class, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,4 +29,52 @@ public interface CrmBiRankingService {
|
||||||
*/
|
*/
|
||||||
List<CrmBiRanKRespVO> getReceivablePriceRank(CrmBiRankReqVO rankReqVO);
|
List<CrmBiRanKRespVO> getReceivablePriceRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得签约合同数量排行榜
|
||||||
|
*
|
||||||
|
* @param rankReqVO 排行参数
|
||||||
|
* @return 签约合同数量排行榜
|
||||||
|
*/
|
||||||
|
List<CrmBiRanKRespVO> getContractCountRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得产品销量排行榜
|
||||||
|
*
|
||||||
|
* @param rankReqVO 排行参数
|
||||||
|
* @return 产品销量排行榜
|
||||||
|
*/
|
||||||
|
List<CrmBiRanKRespVO> getProductSalesRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得新增客户数排行榜
|
||||||
|
*
|
||||||
|
* @param rankReqVO 排行参数
|
||||||
|
* @return 新增客户数排行榜
|
||||||
|
*/
|
||||||
|
List<CrmBiRanKRespVO> getCustomerCountRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得联系人数量排行榜
|
||||||
|
*
|
||||||
|
* @param rankReqVO 排行参数
|
||||||
|
* @return 联系人数量排行榜
|
||||||
|
*/
|
||||||
|
List<CrmBiRanKRespVO> getContactsCountRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得跟进次数排行榜
|
||||||
|
*
|
||||||
|
* @param rankReqVO 排行参数
|
||||||
|
* @return 跟进次数排行榜
|
||||||
|
*/
|
||||||
|
List<CrmBiRanKRespVO> getFollowCountRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得跟进客户数排行榜
|
||||||
|
*
|
||||||
|
* @param rankReqVO 排行参数
|
||||||
|
* @return 跟进客户数排行榜
|
||||||
|
*/
|
||||||
|
List<CrmBiRanKRespVO> getFollowCustomerCountRank(CrmBiRankReqVO rankReqVO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,36 @@ public class CrmBiRankingServiceImpl implements CrmBiRankingService {
|
||||||
return getRank(rankReqVO, biRankingMapper::selectReceivablePriceRank);
|
return getRank(rankReqVO, biRankingMapper::selectReceivablePriceRank);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CrmBiRanKRespVO> getContractCountRank(CrmBiRankReqVO rankReqVO) {
|
||||||
|
return getRank(rankReqVO, biRankingMapper::selectContractCountRank);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CrmBiRanKRespVO> getProductSalesRank(CrmBiRankReqVO rankReqVO) {
|
||||||
|
return getRank(rankReqVO, biRankingMapper::selectProductSalesRank);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CrmBiRanKRespVO> getCustomerCountRank(CrmBiRankReqVO rankReqVO) {
|
||||||
|
return getRank(rankReqVO, biRankingMapper::selectCustomerCountRank);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CrmBiRanKRespVO> getContactsCountRank(CrmBiRankReqVO rankReqVO) {
|
||||||
|
return getRank(rankReqVO, biRankingMapper::selectContactsCountRank);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CrmBiRanKRespVO> getFollowCountRank(CrmBiRankReqVO rankReqVO) {
|
||||||
|
return getRank(rankReqVO, biRankingMapper::selectFollowCountRank);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CrmBiRanKRespVO> getFollowCustomerCountRank(CrmBiRankReqVO rankReqVO) {
|
||||||
|
return getRank(rankReqVO, biRankingMapper::selectFollowCustomerCountRank);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得排行版数据
|
* 获得排行版数据
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.crm.service.business;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 商机产品关联表 Service 接口
|
|
||||||
*
|
|
||||||
* @author lzxhqs
|
|
||||||
*/
|
|
||||||
public interface CrmBusinessProductService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量新增商机产品关联数据
|
|
||||||
*
|
|
||||||
* @param list 商机产品集合
|
|
||||||
*/
|
|
||||||
void createBusinessProductBatch(List<CrmBusinessProductDO> list);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量更新商机产品表
|
|
||||||
*
|
|
||||||
* @param list 商机产品数据集合
|
|
||||||
*/
|
|
||||||
void updateBusinessProductBatch(List<CrmBusinessProductDO> list);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量删除
|
|
||||||
*
|
|
||||||
* @param list 需要删除的商机产品集合
|
|
||||||
*/
|
|
||||||
void deleteBusinessProductBatch(List<CrmBusinessProductDO> list);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据商机编号,删除商机产品关联数据
|
|
||||||
*
|
|
||||||
* @param businessId 商机id
|
|
||||||
*/
|
|
||||||
void deleteBusinessProductByBusinessId(Long businessId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据商机编号,获取商机产品关联数据集合
|
|
||||||
*
|
|
||||||
* @param businessId 商机编号
|
|
||||||
*/
|
|
||||||
List<CrmBusinessProductDO> getBusinessProductListByBusinessId(Long businessId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据合同编号,获得合同关联的商品列表
|
|
||||||
*
|
|
||||||
* @param contractId 合同编号
|
|
||||||
* @return 关联的商品列表
|
|
||||||
*/
|
|
||||||
List<CrmBusinessProductDO> getBusinessProductListByContractId(Long contractId);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.crm.service.business;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
|
|
||||||
import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessProductMapper;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 商机产品关联表 Service 实现类
|
|
||||||
*
|
|
||||||
* @author lzxhqs
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@Validated
|
|
||||||
public class CrmBusinessProductServiceImpl implements CrmBusinessProductService {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private CrmBusinessProductMapper businessProductMapper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void createBusinessProductBatch(List<CrmBusinessProductDO> list) {
|
|
||||||
businessProductMapper.insertBatch(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateBusinessProductBatch(List<CrmBusinessProductDO> list) {
|
|
||||||
businessProductMapper.updateBatch(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO @puhui999:这个方法,可以直接调用 deleteList 方法,然后传递 ids 就好了;
|
|
||||||
@Override
|
|
||||||
public void deleteBusinessProductBatch(List<CrmBusinessProductDO> list) {
|
|
||||||
businessProductMapper.deleteBatchIds(CollectionUtils.convertList(list, CrmBusinessProductDO::getId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteBusinessProductByBusinessId(Long businessId) {
|
|
||||||
businessProductMapper.deleteByBusinessId(businessId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CrmBusinessProductDO> getBusinessProductListByContractId(Long contractId) {
|
|
||||||
return businessProductMapper.selectList(CrmBusinessProductDO::getContractId, contractId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<CrmBusinessProductDO> getBusinessProductListByBusinessId(Long businessId) {
|
|
||||||
return businessProductMapper.selectList(CrmBusinessProductDO::getBusinessId, businessId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusi
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.service.business.bo.CrmBusinessUpdateProductReqBO;
|
||||||
import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
|
import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
@ -50,6 +51,21 @@ public interface CrmBusinessService {
|
||||||
*/
|
*/
|
||||||
void deleteBusiness(Long id);
|
void deleteBusiness(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商机转移
|
||||||
|
*
|
||||||
|
* @param reqVO 请求
|
||||||
|
* @param userId 用户编号
|
||||||
|
*/
|
||||||
|
void transferBusiness(CrmBusinessTransferReqVO reqVO, Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新商机关联商品
|
||||||
|
*
|
||||||
|
* @param updateProductReqBO 请求
|
||||||
|
*/
|
||||||
|
void updateBusinessProduct(CrmBusinessUpdateProductReqBO updateProductReqBO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得商机
|
* 获得商机
|
||||||
*
|
*
|
||||||
|
@ -105,14 +121,6 @@ public interface CrmBusinessService {
|
||||||
*/
|
*/
|
||||||
PageResult<CrmBusinessDO> getBusinessPageByContact(CrmBusinessPageReqVO pageReqVO);
|
PageResult<CrmBusinessDO> getBusinessPageByContact(CrmBusinessPageReqVO pageReqVO);
|
||||||
|
|
||||||
/**
|
|
||||||
* 商机转移
|
|
||||||
*
|
|
||||||
* @param reqVO 请求
|
|
||||||
* @param userId 用户编号
|
|
||||||
*/
|
|
||||||
void transferBusiness(CrmBusinessTransferReqVO reqVO, Long userId);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取关联客户的商机数量
|
* 获取关联客户的商机数量
|
||||||
*
|
*
|
||||||
|
|
|
@ -5,25 +5,28 @@ import cn.hutool.core.collection.ListUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessSaveReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessSaveReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.product.CrmBusinessProductSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.convert.business.CrmBusinessConvert;
|
import cn.iocoder.yudao.module.crm.convert.business.CrmBusinessConvert;
|
||||||
import cn.iocoder.yudao.module.crm.convert.businessproduct.CrmBusinessProductConvert;
|
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessMapper;
|
import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessMapper;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessProductMapper;
|
||||||
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
|
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
|
||||||
import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
|
import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
|
||||||
import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
|
import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
|
||||||
|
import cn.iocoder.yudao.module.crm.service.business.bo.CrmBusinessUpdateProductReqBO;
|
||||||
import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService;
|
import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService;
|
||||||
import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
|
import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
|
||||||
import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
|
import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
|
||||||
import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
|
import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
|
||||||
import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
|
import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
|
||||||
|
import cn.iocoder.yudao.module.crm.service.product.CrmProductService;
|
||||||
import com.mzt.logapi.context.LogRecordContext;
|
import com.mzt.logapi.context.LogRecordContext;
|
||||||
import com.mzt.logapi.service.impl.DiffParseFunction;
|
import com.mzt.logapi.service.impl.DiffParseFunction;
|
||||||
import com.mzt.logapi.starter.annotation.LogRecord;
|
import com.mzt.logapi.starter.annotation.LogRecord;
|
||||||
|
@ -35,11 +38,12 @@ import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||||
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_CONTRACT_EXISTS;
|
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
|
||||||
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS;
|
|
||||||
import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
|
import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,9 +57,9 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CrmBusinessMapper businessMapper;
|
private CrmBusinessMapper businessMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CrmBusinessProductService businessProductService;
|
private CrmBusinessProductMapper businessProductMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
@Lazy // 延迟加载,避免循环依赖
|
@Lazy // 延迟加载,避免循环依赖
|
||||||
private CrmContractService contractService;
|
private CrmContractService contractService;
|
||||||
|
@ -63,6 +67,8 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
||||||
private CrmPermissionService permissionService;
|
private CrmPermissionService permissionService;
|
||||||
@Resource
|
@Resource
|
||||||
private CrmContactBusinessService contactBusinessService;
|
private CrmContactBusinessService contactBusinessService;
|
||||||
|
@Resource
|
||||||
|
private CrmProductService productService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@ -71,14 +77,17 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
||||||
public Long createBusiness(CrmBusinessSaveReqVO createReqVO, Long userId) {
|
public Long createBusiness(CrmBusinessSaveReqVO createReqVO, Long userId) {
|
||||||
createReqVO.setId(null);
|
createReqVO.setId(null);
|
||||||
// 1. 插入商机
|
// 1. 插入商机
|
||||||
CrmBusinessDO business = BeanUtils.toBean(createReqVO, CrmBusinessDO.class)
|
CrmBusinessDO business = BeanUtils.toBean(createReqVO, CrmBusinessDO.class).setOwnerUserId(userId);
|
||||||
.setOwnerUserId(userId);
|
|
||||||
businessMapper.insert(business);
|
businessMapper.insert(business);
|
||||||
// TODO 商机待定:插入商机与产品的关联表;校验商品存在
|
// 1.2 插入商机关联商品
|
||||||
if (CollUtil.isNotEmpty(createReqVO.getProducts())) {
|
if (CollUtil.isNotEmpty(createReqVO.getProductItems())) { // 如果有的话
|
||||||
createBusinessProducts(createReqVO.getProducts(), business.getId(), false);
|
List<CrmBusinessProductDO> productList = buildBusinessProductList(createReqVO.getProductItems(), business.getId());
|
||||||
|
businessProductMapper.insertBatch(productList);
|
||||||
|
// 更新合同商品总金额
|
||||||
|
businessMapper.updateById(new CrmBusinessDO().setId(business.getId()).setProductPrice(
|
||||||
|
getSumValue(productList, CrmBusinessProductDO::getTotalPrice, Integer::sum)));
|
||||||
}
|
}
|
||||||
// TODO 商机待定:在联系人的详情页,如果直接【新建商机】,则需要关联下。这里要搞个 CrmContactBusinessDO 表
|
// TODO @puhui999:在联系人的详情页,如果直接【新建商机】,则需要关联下。这里要搞个 CrmContactBusinessDO 表
|
||||||
createContactBusiness(business.getId(), createReqVO.getContactId());
|
createContactBusiness(business.getId(), createReqVO.getContactId());
|
||||||
|
|
||||||
// 2. 创建数据权限
|
// 2. 创建数据权限
|
||||||
|
@ -86,19 +95,12 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
||||||
permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType())
|
permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType())
|
||||||
.setBizId(business.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
|
.setBizId(business.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
|
||||||
|
|
||||||
// 4. 记录操作日志上下文
|
// 3. 记录操作日志上下文
|
||||||
LogRecordContext.putVariable("business", business);
|
LogRecordContext.putVariable("business", business);
|
||||||
return business.getId();
|
return business.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @lzxhqs:CrmContactBusinessService 调用这个;这样逻辑才能收敛哈;
|
// TODO @lzxhqs:CrmContactBusinessService 调用这个;这样逻辑才能收敛哈;
|
||||||
/**
|
|
||||||
* @param businessId 商机id
|
|
||||||
* @param contactId 联系人id
|
|
||||||
* @throws
|
|
||||||
* @description 联系人与商机的关联
|
|
||||||
* @author lzxhqs
|
|
||||||
*/
|
|
||||||
private void createContactBusiness(Long businessId, Long contactId) {
|
private void createContactBusiness(Long businessId, Long contactId) {
|
||||||
CrmContactBusinessDO contactBusiness = new CrmContactBusinessDO();
|
CrmContactBusinessDO contactBusiness = new CrmContactBusinessDO();
|
||||||
contactBusiness.setBusinessId(businessId);
|
contactBusiness.setBusinessId(businessId);
|
||||||
|
@ -106,37 +108,6 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
||||||
contactBusinessService.insert(contactBusiness);
|
contactBusinessService.insert(contactBusiness);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @lzxhqs:这个方法注释格式不对;删除@description,然后把 插入商机产品关联表 作为方法注释;
|
|
||||||
/**
|
|
||||||
* 插入商机产品关联表
|
|
||||||
*
|
|
||||||
* @param products 产品集合
|
|
||||||
* @param businessId 商机id
|
|
||||||
* @param updateFlag 更新标识 true 代表更新
|
|
||||||
* @author lzxhqs
|
|
||||||
*/
|
|
||||||
private void createBusinessProducts(List<CrmBusinessProductSaveReqVO> products, Long businessId, Boolean updateFlag) {
|
|
||||||
List<CrmBusinessProductDO> list = CollectionUtils.convertList(products, product ->
|
|
||||||
CrmBusinessProductConvert.INSTANCE.convert(product).setBusinessId(businessId));
|
|
||||||
if (Boolean.TRUE.equals(updateFlag)) {
|
|
||||||
// 根据商机 id从商机产品关联表中获取已存在的数据集合
|
|
||||||
List<CrmBusinessProductDO> oldProducts = businessProductService.getBusinessProductListByBusinessId(businessId);
|
|
||||||
List<List<CrmBusinessProductDO>> diffList = CollectionUtils.diffList(oldProducts, list, (oldValue, newValue) ->
|
|
||||||
ObjectUtil.equal(oldValue.getProductId(), newValue.getProductId()));
|
|
||||||
if (CollUtil.isNotEmpty(diffList.getFirst())) {
|
|
||||||
businessProductService.createBusinessProductBatch(diffList.getFirst());
|
|
||||||
}
|
|
||||||
if (CollUtil.isNotEmpty(diffList.get(1))) {
|
|
||||||
businessProductService.updateBusinessProductBatch(diffList.get(1));
|
|
||||||
}
|
|
||||||
if (CollUtil.isNotEmpty(diffList.get(2))) {
|
|
||||||
businessProductService.deleteBusinessProductBatch(diffList.get(2));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
businessProductService.createBusinessProductBatch(list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
|
@LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
|
||||||
|
@ -146,16 +117,12 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
||||||
// 1. 校验存在
|
// 1. 校验存在
|
||||||
CrmBusinessDO oldBusiness = validateBusinessExists(updateReqVO.getId());
|
CrmBusinessDO oldBusiness = validateBusinessExists(updateReqVO.getId());
|
||||||
|
|
||||||
// 2. 更新商机
|
// 2.1 更新商机
|
||||||
CrmBusinessDO updateObj = BeanUtils.toBean(updateReqVO, CrmBusinessDO.class);
|
CrmBusinessDO updateObj = BeanUtils.toBean(updateReqVO, CrmBusinessDO.class);
|
||||||
businessMapper.updateById(updateObj);
|
businessMapper.updateById(updateObj);
|
||||||
// TODO 商机待定:插入商机与产品的关联表;校验商品存在
|
// 2.2 更新商机关联商品
|
||||||
// TODO @lzxhqs:createBusinessProducts 可以抽成两个方法,一个新增;一个修改,修改需要把 businessProductService.deleteByBusinessId(updateReqVO.getId()); 一起处理进去;
|
List<CrmBusinessProductDO> productList = buildBusinessProductList(updateReqVO.getProductItems(), updateObj.getId());
|
||||||
if (CollUtil.isNotEmpty(updateReqVO.getProducts())) {
|
updateBusinessProduct(productList, updateObj.getId());
|
||||||
createBusinessProducts(updateReqVO.getProducts(), updateReqVO.getId(), true);
|
|
||||||
} else {
|
|
||||||
businessProductService.deleteBusinessProductByBusinessId(updateReqVO.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO @商机待定:如果状态发生变化,插入商机状态变更记录表
|
// TODO @商机待定:如果状态发生变化,插入商机状态变更记录表
|
||||||
// 3. 记录操作日志上下文
|
// 3. 记录操作日志上下文
|
||||||
|
@ -188,6 +155,44 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
||||||
LogRecordContext.putVariable("businessName", business.getName());
|
LogRecordContext.putVariable("businessName", business.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateBusinessProduct(List<CrmBusinessProductDO> newProductList, Long businessId) {
|
||||||
|
List<CrmBusinessProductDO> oldProducts = businessProductMapper.selectListByBusinessId(businessId);
|
||||||
|
List<List<CrmBusinessProductDO>> diffList = CollectionUtils.diffList(oldProducts, newProductList, (oldValue, newValue) -> {
|
||||||
|
boolean condition = ObjectUtil.equal(oldValue.getProductId(), newValue.getProductId());
|
||||||
|
if (condition) {
|
||||||
|
newValue.setId(oldValue.getId()); // 更新需要原始编号
|
||||||
|
}
|
||||||
|
return condition;
|
||||||
|
});
|
||||||
|
if (CollUtil.isNotEmpty(diffList.get(0))) {
|
||||||
|
businessProductMapper.insertBatch(diffList.get(0));
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(diffList.get(1))) {
|
||||||
|
businessProductMapper.updateBatch(diffList.get(1));
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(diffList.get(2))) {
|
||||||
|
businessProductMapper.deleteBatchIds(convertSet(diffList.get(2), CrmBusinessProductDO::getId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CrmBusinessProductDO> buildBusinessProductList(List<CrmBusinessSaveReqVO.CrmBusinessProductItem> productItems,
|
||||||
|
Long businessId) {
|
||||||
|
// 校验商品存在
|
||||||
|
Set<Long> productIds = convertSet(productItems, CrmBusinessSaveReqVO.CrmBusinessProductItem::getId);
|
||||||
|
List<CrmProductDO> productList = productService.getProductList(productIds);
|
||||||
|
if (CollUtil.isEmpty(productIds) || productList.size() != productIds.size()) {
|
||||||
|
throw exception(PRODUCT_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId);
|
||||||
|
return convertList(productItems, productItem -> {
|
||||||
|
CrmProductDO product = productMap.get(productItem.getId());
|
||||||
|
return BeanUtils.toBean(product, CrmBusinessProductDO.class)
|
||||||
|
.setId(null).setProductId(productItem.getId()).setBusinessId(businessId)
|
||||||
|
.setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent())
|
||||||
|
.setTotalPrice(MoneyUtils.calculator(product.getPrice(), productItem.getCount(), productItem.getDiscountPercent()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除校验合同是关联合同
|
* 删除校验合同是关联合同
|
||||||
*
|
*
|
||||||
|
@ -228,6 +233,14 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
||||||
LogRecordContext.putVariable("business", business);
|
LogRecordContext.putVariable("business", business);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBusinessProduct(CrmBusinessUpdateProductReqBO updateProductReqBO) {
|
||||||
|
// 更新商机关联商品
|
||||||
|
List<CrmBusinessProductDO> productList = buildBusinessProductList(
|
||||||
|
BeanUtils.toBean(updateProductReqBO.getProductItems(), CrmBusinessSaveReqVO.CrmBusinessProductItem.class), updateProductReqBO.getId());
|
||||||
|
updateBusinessProduct(productList, updateProductReqBO.getId());
|
||||||
|
}
|
||||||
|
|
||||||
//======================= 查询相关 =======================
|
//======================= 查询相关 =======================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package cn.iocoder.yudao.module.crm.service.business.bo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新商机商品 Update Req BO
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CrmBusinessUpdateProductReqBO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商机编号
|
||||||
|
*/
|
||||||
|
@NotNull(message = "商机编号不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
// TODO @芋艿:再想想
|
||||||
|
@NotEmpty(message = "产品列表不能为空")
|
||||||
|
private List<CrmBusinessProductItem> productItems;
|
||||||
|
|
||||||
|
@Schema(description = "产品列表")
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class CrmBusinessProductItem {
|
||||||
|
|
||||||
|
@Schema(description = "产品编号", example = "20529")
|
||||||
|
@NotNull(message = "产品编号不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
|
||||||
|
@NotNull(message = "产品数量不能为空")
|
||||||
|
private Integer count;
|
||||||
|
|
||||||
|
@Schema(description = "产品折扣")
|
||||||
|
private Integer discountPercent;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -11,20 +11,22 @@ import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO;
|
import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO;
|
||||||
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
|
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.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert;
|
import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
|
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper;
|
import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractProductMapper;
|
||||||
import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
|
import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
|
||||||
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
|
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
|
||||||
import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
|
import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
|
||||||
import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
|
import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
|
||||||
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessProductService;
|
|
||||||
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
|
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
|
||||||
|
import cn.iocoder.yudao.module.crm.service.business.bo.CrmBusinessUpdateProductReqBO;
|
||||||
import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
|
import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
|
||||||
import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
|
import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
|
||||||
import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
|
import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
|
||||||
|
@ -59,16 +61,19 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_E
|
||||||
@Validated
|
@Validated
|
||||||
public class CrmContractServiceImpl implements CrmContractService {
|
public class CrmContractServiceImpl implements CrmContractService {
|
||||||
|
|
||||||
public static final String CONTRACT_APPROVE = "contract-approve"; // 合同审批流程标识
|
/**
|
||||||
|
* BPM 合同审批流程标识
|
||||||
|
*/
|
||||||
|
public static final String CONTRACT_APPROVE = "contract-approve";
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CrmContractMapper contractMapper;
|
private CrmContractMapper contractMapper;
|
||||||
|
@Resource
|
||||||
|
private CrmContractProductMapper contractProductMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CrmPermissionService crmPermissionService;
|
private CrmPermissionService crmPermissionService;
|
||||||
@Resource
|
@Resource
|
||||||
private CrmBusinessProductService businessProductService;
|
|
||||||
@Resource
|
|
||||||
private CrmProductService productService;
|
private CrmProductService productService;
|
||||||
@Resource
|
@Resource
|
||||||
private CrmCustomerService customerService;
|
private CrmCustomerService customerService;
|
||||||
|
@ -89,11 +94,18 @@ public class CrmContractServiceImpl implements CrmContractService {
|
||||||
// 1.1 插入合同
|
// 1.1 插入合同
|
||||||
CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null);
|
CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null);
|
||||||
contractMapper.insert(contract);
|
contractMapper.insert(contract);
|
||||||
// 1.2 插入商机关联商品
|
// 1.2 插入合同关联商品
|
||||||
if (CollUtil.isNotEmpty(createReqVO.getProductItems())) { // 如果有的话
|
if (CollUtil.isNotEmpty(createReqVO.getProductItems())) { // 如果有的话
|
||||||
List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO, contract.getId());
|
List<CrmContractProductDO> productList = convertContractProductList(createReqVO, contract.getId());
|
||||||
businessProductService.createBusinessProductBatch(businessProduct);
|
contractProductMapper.insertBatch(productList);
|
||||||
// 更新合同商品总金额
|
// 更新合同商品总金额
|
||||||
|
contractMapper.updateById(new CrmContractDO().setId(contract.getId()).setProductPrice(
|
||||||
|
getSumValue(productList, CrmContractProductDO::getTotalPrice, Integer::sum)));
|
||||||
|
// 如果存在合同关联了商机则更新商机商品关联
|
||||||
|
if (contract.getBusinessId() != null) {
|
||||||
|
businessService.updateBusinessProduct(new CrmBusinessUpdateProductReqBO().setId(contract.getBusinessId())
|
||||||
|
.setProductItems(BeanUtils.toBean(createReqVO.getProductItems(), CrmBusinessUpdateProductReqBO.CrmBusinessProductItem.class)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 创建数据权限
|
// 2. 创建数据权限
|
||||||
|
@ -137,29 +149,29 @@ public class CrmContractServiceImpl implements CrmContractService {
|
||||||
if (CollUtil.isEmpty(updateReqVO.getProductItems())) {
|
if (CollUtil.isEmpty(updateReqVO.getProductItems())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<CrmBusinessProductDO> newProductList = convertBusinessProductList(updateReqVO, contractId);
|
List<CrmContractProductDO> newProductList = convertContractProductList(updateReqVO, contractId);
|
||||||
List<CrmBusinessProductDO> oldProductList = businessProductService.getBusinessProductListByContractId(contractId);
|
List<CrmContractProductDO> oldProductList = contractProductMapper.selectListByContractId(contractId);
|
||||||
List<List<CrmBusinessProductDO>> diffList = diffList(oldProductList, newProductList, (oldObj, newObj) -> {
|
List<List<CrmContractProductDO>> diffList = diffList(oldProductList, newProductList, (oldObj, newObj) -> {
|
||||||
if (ObjUtil.notEqual(oldObj.getProductId(), newObj.getProductId())) {
|
boolean match = ObjUtil.equal(oldObj.getProductId(), newObj.getProductId());
|
||||||
return false;
|
if (match) {
|
||||||
}
|
|
||||||
newObj.setId(oldObj.getId()); // 设置一下老的编号更新时需要使用
|
newObj.setId(oldObj.getId()); // 设置一下老的编号更新时需要使用
|
||||||
return true;
|
}
|
||||||
|
return match;
|
||||||
});
|
});
|
||||||
if (CollUtil.isNotEmpty(diffList.getFirst())) {
|
if (CollUtil.isNotEmpty(diffList.get(0))) {
|
||||||
businessProductService.createBusinessProductBatch(diffList.getFirst());
|
contractProductMapper.insertBatch(diffList.get(0));
|
||||||
}
|
}
|
||||||
if (CollUtil.isNotEmpty(diffList.get(1))) {
|
if (CollUtil.isNotEmpty(diffList.get(1))) {
|
||||||
businessProductService.updateBusinessProductBatch(diffList.get(1));
|
contractProductMapper.updateBatch(diffList.get(1));
|
||||||
}
|
}
|
||||||
if (CollUtil.isNotEmpty(diffList.get(2))) {
|
if (CollUtil.isNotEmpty(diffList.get(2))) {
|
||||||
businessProductService.deleteBusinessProductBatch(diffList.get(2));
|
contractProductMapper.deleteBatchIds(convertList(diffList.get(2), CrmContractProductDO::getId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @合同待定:缺一个取消合同的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum
|
// TODO @合同待定:缺一个取消合同的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum
|
||||||
|
|
||||||
private List<CrmBusinessProductDO> convertBusinessProductList(CrmContractSaveReqVO reqVO, Long contractId) {
|
private List<CrmContractProductDO> convertContractProductList(CrmContractSaveReqVO reqVO, Long contractId) {
|
||||||
// 校验商品存在
|
// 校验商品存在
|
||||||
Set<Long> productIds = convertSet(reqVO.getProductItems(), CrmContractSaveReqVO.CrmContractProductItem::getId);
|
Set<Long> productIds = convertSet(reqVO.getProductItems(), CrmContractSaveReqVO.CrmContractProductItem::getId);
|
||||||
List<CrmProductDO> productList = productService.getProductList(productIds);
|
List<CrmProductDO> productList = productService.getProductList(productIds);
|
||||||
|
@ -169,8 +181,8 @@ public class CrmContractServiceImpl implements CrmContractService {
|
||||||
Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId);
|
Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId);
|
||||||
return convertList(reqVO.getProductItems(), productItem -> {
|
return convertList(reqVO.getProductItems(), productItem -> {
|
||||||
CrmProductDO product = productMap.get(productItem.getId());
|
CrmProductDO product = productMap.get(productItem.getId());
|
||||||
return BeanUtils.toBean(product, CrmBusinessProductDO.class)
|
return BeanUtils.toBean(product, CrmContractProductDO.class)
|
||||||
.setId(null).setBusinessId(reqVO.getBusinessId()).setProductId(productItem.getId()).setContractId(contractId)
|
.setId(null).setProductId(productItem.getId()).setContractId(contractId)
|
||||||
.setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent())
|
.setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent())
|
||||||
.setTotalPrice(MoneyUtils.calculator(product.getPrice(), productItem.getCount(), productItem.getDiscountPercent()));
|
.setTotalPrice(MoneyUtils.calculator(product.getPrice(), productItem.getCount(), productItem.getDiscountPercent()));
|
||||||
});
|
});
|
||||||
|
@ -248,7 +260,8 @@ public class CrmContractServiceImpl implements CrmContractService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
// TODO @puhui999:操作日志;
|
@LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_SUBMIT_SUB_TYPE, bizNo = "{{#id}}",
|
||||||
|
success = CRM_CONTRACT_SUBMIT_SUCCESS)
|
||||||
public void submitContract(Long id, Long userId) {
|
public void submitContract(Long id, Long userId) {
|
||||||
// 1. 校验合同是否在审批
|
// 1. 校验合同是否在审批
|
||||||
CrmContractDO contract = validateContractExists(id);
|
CrmContractDO contract = validateContractExists(id);
|
||||||
|
@ -263,15 +276,43 @@ public class CrmContractServiceImpl implements CrmContractService {
|
||||||
// 3. 更新合同工作流编号
|
// 3. 更新合同工作流编号
|
||||||
contractMapper.updateById(new CrmContractDO().setId(id).setProcessInstanceId(processInstanceId)
|
contractMapper.updateById(new CrmContractDO().setId(id).setProcessInstanceId(processInstanceId)
|
||||||
.setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus()));
|
.setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus()));
|
||||||
|
|
||||||
|
// 3. 记录日志
|
||||||
|
LogRecordContext.putVariable("contractName", contract.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateContractAuditStatus(BpmResultListenerRespDTO event) {
|
public void updateContractAuditStatus(BpmResultListenerRespDTO event) {
|
||||||
// TODO @puhui999:可能要判断下状态是否符合预期
|
// 判断下状态是否符合预期
|
||||||
|
if (!isEndResult(event.getResult())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 状态转换
|
||||||
|
if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.APPROVE.getResult())) {
|
||||||
|
event.setResult(CrmAuditStatusEnum.APPROVE.getStatus());
|
||||||
|
}
|
||||||
|
if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.REJECT.getResult())) {
|
||||||
|
event.setResult(CrmAuditStatusEnum.REJECT.getStatus());
|
||||||
|
}
|
||||||
|
if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult())) {
|
||||||
|
event.setResult(CrmAuditStatusEnum.CANCEL.getStatus());
|
||||||
|
}
|
||||||
|
// 更新合同状态
|
||||||
contractMapper.updateById(new CrmContractDO().setId(Long.parseLong(event.getBusinessKey()))
|
contractMapper.updateById(new CrmContractDO().setId(Long.parseLong(event.getBusinessKey()))
|
||||||
.setAuditStatus(event.getResult()));
|
.setAuditStatus(event.getResult()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断该结果是否处于 End 最终结果
|
||||||
|
*
|
||||||
|
* @param result 结果
|
||||||
|
* @return 是否
|
||||||
|
*/
|
||||||
|
public static boolean isEndResult(Integer result) {
|
||||||
|
return ObjectUtils.equalsAny(result, BpmProcessInstanceResultEnum.APPROVE.getResult(),
|
||||||
|
BpmProcessInstanceResultEnum.REJECT.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult());
|
||||||
|
}
|
||||||
|
|
||||||
//======================= 查询相关 =======================
|
//======================= 查询相关 =======================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -313,6 +354,12 @@ public class CrmContractServiceImpl implements CrmContractService {
|
||||||
public Long getContractCountByBusinessId(Long businessId) {
|
public Long getContractCountByBusinessId(Long businessId) {
|
||||||
return contractMapper.selectCountByBusinessId(businessId);
|
return contractMapper.selectCountByBusinessId(businessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CrmContractProductDO> getContractProductListByContractId(Long contactId) {
|
||||||
|
return contractProductMapper.selectListByContractId(contactId);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO @合同待定:需要新增一个 ContractConfigDO 表,合同配置,重点是到期提醒;
|
// TODO @合同待定:需要新增一个 ContractConfigDO 表,合同配置,重点是到期提醒;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
package cn.iocoder.yudao.module.crm.service.contract.listener;
|
package cn.iocoder.yudao.module.crm.service.contract.listener;
|
||||||
|
|
||||||
import cn.hutool.core.util.ObjUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
|
||||||
import cn.iocoder.yudao.module.bpm.api.listener.BpmResultListenerApi;
|
import cn.iocoder.yudao.module.bpm.api.listener.BpmResultListenerApi;
|
||||||
import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO;
|
import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO;
|
||||||
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
|
||||||
import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
|
|
||||||
import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
|
import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
|
||||||
import cn.iocoder.yudao.module.crm.service.contract.CrmContractServiceImpl;
|
import cn.iocoder.yudao.module.crm.service.contract.CrmContractServiceImpl;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
@ -30,31 +26,7 @@ public class CrmContractResultListener implements BpmResultListenerApi {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(BpmResultListenerRespDTO event) {
|
public void onEvent(BpmResultListenerRespDTO event) {
|
||||||
boolean currentTaskFinish = isEndResult(event.getResult());
|
|
||||||
if (!currentTaskFinish) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.APPROVE.getResult())) {
|
|
||||||
event.setResult(CrmAuditStatusEnum.APPROVE.getStatus());
|
|
||||||
}
|
|
||||||
if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.REJECT.getResult())) {
|
|
||||||
event.setResult(CrmAuditStatusEnum.REJECT.getStatus());
|
|
||||||
}
|
|
||||||
if (ObjUtil.equal(event.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult())) {
|
|
||||||
event.setResult(CrmAuditStatusEnum.CANCEL.getStatus());
|
|
||||||
}
|
|
||||||
contractService.updateContractAuditStatus(event);
|
contractService.updateContractAuditStatus(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断该结果是否处于 End 最终结果
|
|
||||||
*
|
|
||||||
* @param result 结果
|
|
||||||
* @return 是否
|
|
||||||
*/
|
|
||||||
public static boolean isEndResult(Integer result) {
|
|
||||||
return ObjectUtils.equalsAny(result, BpmProcessInstanceResultEnum.APPROVE.getResult(),
|
|
||||||
BpmProcessInstanceResultEnum.REJECT.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,11 +110,10 @@ public interface CrmCustomerService {
|
||||||
* 批量导入客户
|
* 批量导入客户
|
||||||
*
|
*
|
||||||
* @param importCustomers 导入客户列表
|
* @param importCustomers 导入客户列表
|
||||||
* @param isUpdateSupport 是否支持更新
|
* @param importReqVO 请求
|
||||||
* @param userId 用户编号
|
|
||||||
* @return 导入结果
|
* @return 导入结果
|
||||||
*/
|
*/
|
||||||
CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, Boolean isUpdateSupport, Long userId);
|
CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, CrmCustomerImportReqVO importReqVO);
|
||||||
|
|
||||||
// ==================== 公海相关操作 ====================
|
// ==================== 公海相关操作 ====================
|
||||||
|
|
||||||
|
|
|
@ -244,8 +244,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers,
|
public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, CrmCustomerImportReqVO importReqVO) {
|
||||||
Boolean isUpdateSupport, Long userId) {
|
|
||||||
if (CollUtil.isEmpty(importCustomers)) {
|
if (CollUtil.isEmpty(importCustomers)) {
|
||||||
throw exception(CUSTOMER_IMPORT_LIST_IS_EMPTY);
|
throw exception(CUSTOMER_IMPORT_LIST_IS_EMPTY);
|
||||||
}
|
}
|
||||||
|
@ -264,19 +263,21 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
||||||
CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName());
|
CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName());
|
||||||
if (existCustomer == null) {
|
if (existCustomer == null) {
|
||||||
// 1.1 插入客户信息
|
// 1.1 插入客户信息
|
||||||
CrmCustomerDO customer = initCustomer(importCustomer, userId);
|
CrmCustomerDO customer = initCustomer(importCustomer, importReqVO.getOwnerUserId());
|
||||||
customerMapper.insert(customer);
|
customerMapper.insert(customer);
|
||||||
respVO.getCreateCustomerNames().add(importCustomer.getName());
|
respVO.getCreateCustomerNames().add(importCustomer.getName());
|
||||||
// 1.2 创建数据权限
|
// 1.2 创建数据权限
|
||||||
|
if (importReqVO.getOwnerUserId() != null) {
|
||||||
permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
|
permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
|
||||||
.setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
|
.setBizId(customer.getId()).setUserId(importReqVO.getOwnerUserId()).setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
|
||||||
|
}
|
||||||
// 1.3 记录操作日志
|
// 1.3 记录操作日志
|
||||||
getSelf().importCustomerLog(customer, false);
|
getSelf().importCustomerLog(customer, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 情况二:如果存在,判断是否允许更新
|
// 情况二:如果存在,判断是否允许更新
|
||||||
if (!isUpdateSupport) {
|
if (!importReqVO.getUpdateSupport()) {
|
||||||
respVO.getFailureCustomerNames().put(importCustomer.getName(),
|
respVO.getFailureCustomerNames().put(importCustomer.getName(),
|
||||||
StrUtil.format(CUSTOMER_NAME_EXISTS.getMsg(), importCustomer.getName()));
|
StrUtil.format(CUSTOMER_NAME_EXISTS.getMsg(), importCustomer.getName()));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -160,7 +160,7 @@ public class CrmProductServiceImpl implements CrmProductService {
|
||||||
if (CollUtil.isEmpty(ids)) {
|
if (CollUtil.isEmpty(ids)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
return productMapper.selectListByIds(ids);
|
return productMapper.selectBatchIds(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
||||||
#{userId}
|
#{userId}
|
||||||
</foreach>
|
</foreach>
|
||||||
AND order_date between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime}
|
AND order_date between #{times[0],javaType=java.time.LocalDateTime} and
|
||||||
|
#{times[1],javaType=java.time.LocalDateTime}
|
||||||
GROUP BY owner_user_id
|
GROUP BY owner_user_id
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
@ -22,12 +23,104 @@
|
||||||
FROM crm_receivable
|
FROM crm_receivable
|
||||||
WHERE deleted = 0
|
WHERE deleted = 0
|
||||||
AND audit_status = 20
|
AND audit_status = 20
|
||||||
and owner_user_id in
|
AND owner_user_id in
|
||||||
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
||||||
#{userId}
|
#{userId}
|
||||||
</foreach>
|
</foreach>
|
||||||
AND return_time between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime}
|
AND return_time between #{times[0],javaType=java.time.LocalDateTime} and
|
||||||
|
#{times[1],javaType=java.time.LocalDateTime}
|
||||||
GROUP BY owner_user_id
|
GROUP BY owner_user_id
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectContractCountRank"
|
||||||
|
resultType="cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRanKRespVO">
|
||||||
|
SELECT COUNT(1) AS count, owner_user_id
|
||||||
|
FROM crm_contract
|
||||||
|
WHERE deleted = 0
|
||||||
|
AND audit_status = 20
|
||||||
|
AND owner_user_id in
|
||||||
|
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
||||||
|
#{userId}
|
||||||
|
</foreach>
|
||||||
|
AND order_date between #{times[0],javaType=java.time.LocalDateTime} and
|
||||||
|
#{times[1],javaType=java.time.LocalDateTime}
|
||||||
|
GROUP BY owner_user_id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- TODO 待定 这里是否需要关联 crm_contract_product 表,计算销售额 -->
|
||||||
|
<select id="selectProductSalesRank"
|
||||||
|
resultType="cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRanKRespVO">
|
||||||
|
SELECT COUNT(1) AS count, owner_user_id
|
||||||
|
FROM crm_contract
|
||||||
|
WHERE deleted = 0
|
||||||
|
AND audit_status = 20
|
||||||
|
AND owner_user_id in
|
||||||
|
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
||||||
|
#{userId}
|
||||||
|
</foreach>
|
||||||
|
AND order_date between #{times[0],javaType=java.time.LocalDateTime} and
|
||||||
|
#{times[1],javaType=java.time.LocalDateTime}
|
||||||
|
GROUP BY owner_user_id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectCustomerCountRank"
|
||||||
|
resultType="cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRanKRespVO">
|
||||||
|
SELECT COUNT(1) AS count, owner_user_id
|
||||||
|
FROM crm_customer
|
||||||
|
WHERE deleted = 0
|
||||||
|
AND owner_user_id in
|
||||||
|
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
||||||
|
#{userId}
|
||||||
|
</foreach>
|
||||||
|
AND create_time between #{times[0],javaType=java.time.LocalDateTime} and
|
||||||
|
#{times[1],javaType=java.time.LocalDateTime}
|
||||||
|
GROUP BY owner_user_id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectContactsCountRank"
|
||||||
|
resultType="cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRanKRespVO">
|
||||||
|
SELECT COUNT(1) AS count, owner_user_id
|
||||||
|
FROM crm_contact
|
||||||
|
WHERE deleted = 0
|
||||||
|
AND owner_user_id in
|
||||||
|
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
||||||
|
#{userId}
|
||||||
|
</foreach>
|
||||||
|
AND create_time between #{times[0],javaType=java.time.LocalDateTime} and
|
||||||
|
#{times[1],javaType=java.time.LocalDateTime}
|
||||||
|
GROUP BY owner_user_id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectFollowCountRank"
|
||||||
|
resultType="cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRanKRespVO">
|
||||||
|
SELECT COUNT(1) AS count, cc.owner_user_id
|
||||||
|
FROM crm_follow_up_record AS cfur
|
||||||
|
LEFT JOIN crm_contact AS cc ON FIND_IN_SET(cc.id, cfur.contact_ids)
|
||||||
|
WHERE cfur.deleted = 0
|
||||||
|
AND cc.deleted = 0
|
||||||
|
AND cc.owner_user_id in
|
||||||
|
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
||||||
|
#{userId}
|
||||||
|
</foreach>
|
||||||
|
AND cfur.create_time between #{times[0],javaType=java.time.LocalDateTime} and
|
||||||
|
#{times[1],javaType=java.time.LocalDateTime}
|
||||||
|
GROUP BY cc.owner_user_id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectFollowCustomerCountRank"
|
||||||
|
resultType="cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRanKRespVO">
|
||||||
|
SELECT COUNT(DISTINCT cc.id) AS count, cc.owner_user_id
|
||||||
|
FROM crm_follow_up_record AS cfur
|
||||||
|
LEFT JOIN crm_contact AS cc ON FIND_IN_SET(cc.id, cfur.contact_ids)
|
||||||
|
WHERE cfur.deleted = 0
|
||||||
|
AND cc.deleted = 0
|
||||||
|
AND cc.owner_user_id in
|
||||||
|
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
||||||
|
#{userId}
|
||||||
|
</foreach>
|
||||||
|
AND cfur.create_time between #{times[0],javaType=java.time.LocalDateTime} and
|
||||||
|
#{times[1],javaType=java.time.LocalDateTime}
|
||||||
|
GROUP BY cc.owner_user_id
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
/**
|
||||||
|
* 属于 erp 模块的 framework 封装
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
package cn.iocoder.yudao.module.erp.framework;
|
|
@ -0,0 +1,24 @@
|
||||||
|
package cn.iocoder.yudao.module.erp.framework.web.config;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration;
|
||||||
|
import org.springdoc.core.models.GroupedOpenApi;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* erp 模块的 web 组件的 Configuration
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
public class ErpWebConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* erp 模块的 API 分组
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public GroupedOpenApi tradeGroupedOpenApi() {
|
||||||
|
return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("erp");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* trade 模块的 web 配置
|
||||||
|
*/
|
||||||
|
package cn.iocoder.yudao.module.erp.framework.web;
|
|
@ -8,14 +8,17 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
||||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||||
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
|
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.*;
|
||||||
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileRespVO;
|
|
||||||
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileUploadReqVO;
|
|
||||||
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
|
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
|
||||||
import cn.iocoder.yudao.module.infra.service.file.FileService;
|
import cn.iocoder.yudao.module.infra.service.file.FileService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.annotation.security.PermitAll;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
@ -23,12 +26,6 @@ import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import jakarta.annotation.security.PermitAll;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 文件存储")
|
@Tag(name = "管理后台 - 文件存储")
|
||||||
|
@ -42,7 +39,7 @@ public class FileController {
|
||||||
private FileService fileService;
|
private FileService fileService;
|
||||||
|
|
||||||
@PostMapping("/upload")
|
@PostMapping("/upload")
|
||||||
@Operation(summary = "上传文件")
|
@Operation(summary = "上传文件", description = "模式一:后端上传文件")
|
||||||
@OperateLog(logArgs = false) // 上传文件,没有记录操作日志的必要
|
@OperateLog(logArgs = false) // 上传文件,没有记录操作日志的必要
|
||||||
public CommonResult<String> uploadFile(FileUploadReqVO uploadReqVO) throws Exception {
|
public CommonResult<String> uploadFile(FileUploadReqVO uploadReqVO) throws Exception {
|
||||||
MultipartFile file = uploadReqVO.getFile();
|
MultipartFile file = uploadReqVO.getFile();
|
||||||
|
@ -50,6 +47,18 @@ public class FileController {
|
||||||
return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream())));
|
return success(fileService.createFile(file.getOriginalFilename(), path, IoUtil.readBytes(file.getInputStream())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/presigned-url")
|
||||||
|
@Operation(summary = "获取文件预签名地址", description = "模式二:前端上传文件:用于前端直接上传七牛、阿里云 OSS 等文件存储器")
|
||||||
|
public CommonResult<FilePresignedUrlRespVO> getFilePresignedUrl(@RequestParam("path") String path) throws Exception {
|
||||||
|
return success(fileService.getFilePresignedUrl(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/create")
|
||||||
|
@Operation(summary = "创建文件", description = "模式二:前端上传文件:配合 presigned-url 接口,记录上传了上传的文件")
|
||||||
|
public CommonResult<Long> createFile(@Valid @RequestBody FileCreateReqVO createReqVO) {
|
||||||
|
return success(fileService.createFile(createReqVO));
|
||||||
|
}
|
||||||
|
|
||||||
@DeleteMapping("/delete")
|
@DeleteMapping("/delete")
|
||||||
@Operation(summary = "删除文件")
|
@Operation(summary = "删除文件")
|
||||||
@Parameter(name = "id", description = "编号", required = true)
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package cn.iocoder.yudao.module.infra.controller.admin.file.vo.file;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 文件创建 Request VO")
|
||||||
|
@Data
|
||||||
|
public class FileCreateReqVO {
|
||||||
|
|
||||||
|
@NotNull(message = "文件配置编号不能为空")
|
||||||
|
@Schema(description = "文件配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11")
|
||||||
|
private Long configId;
|
||||||
|
|
||||||
|
@NotNull(message = "文件路径不能为空")
|
||||||
|
@Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao.jpg")
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
@NotNull(message = "原文件名不能为空")
|
||||||
|
@Schema(description = "原文件名", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao.jpg")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@NotNull(message = "文件 URL不能为空")
|
||||||
|
@Schema(description = "文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao.jpg")
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
@Schema(description = "文件 MIME 类型", example = "application/octet-stream")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@Schema(description = "文件大小", example = "2048", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private Integer size;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package cn.iocoder.yudao.module.infra.controller.admin.file.vo.file;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Schema(description = "管理后台 - 文件预签名地址 Response VO")
|
||||||
|
@Data
|
||||||
|
public class FilePresignedUrlRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11")
|
||||||
|
private Long configId;
|
||||||
|
|
||||||
|
@Schema(description = "文件上传 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://s3.cn-south-1.qiniucs.com/ruoyi-vue-pro/758d3a5387507358c7236de4c8f96de1c7f5097ff6a7722b34772fb7b76b140f.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS%2F20240217%2Fcn-south-1%2Fs3%2Faws4_request&X-Amz-Date=20240217T123222Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=a29f33770ab79bf523ccd4034d0752ac545f3c2a3b17baa1eb4e280cfdccfda5")
|
||||||
|
private String uploadUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为什么要返回 url 字段?
|
||||||
|
*
|
||||||
|
* 前端上传完文件后,需要使用该 URL 进行访问
|
||||||
|
*/
|
||||||
|
@Schema(description = "文件访问 URL", requiredMode = Schema.RequiredMode.REQUIRED,
|
||||||
|
example = "https://test.yudao.iocoder.cn/758d3a5387507358c7236de4c8f96de1c7f5097ff6a7722b34772fb7b76b140f.png")
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
package cn.iocoder.yudao.module.infra.service.file;
|
package cn.iocoder.yudao.module.infra.service.file;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileCreateReqVO;
|
||||||
|
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePresignedUrlRespVO;
|
||||||
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
|
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,6 +31,14 @@ public interface FileService {
|
||||||
*/
|
*/
|
||||||
String createFile(String name, String path, byte[] content);
|
String createFile(String name, String path, byte[] content);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建文件
|
||||||
|
*
|
||||||
|
* @param createReqVO 创建信息
|
||||||
|
* @return 编号
|
||||||
|
*/
|
||||||
|
Long createFile(FileCreateReqVO createReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除文件
|
* 删除文件
|
||||||
*
|
*
|
||||||
|
@ -45,4 +55,12 @@ public interface FileService {
|
||||||
*/
|
*/
|
||||||
byte[] getFileContent(Long configId, String path) throws Exception;
|
byte[] getFileContent(Long configId, String path) throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成文件预签名地址信息
|
||||||
|
*
|
||||||
|
* @param path 文件路径
|
||||||
|
* @return 预签名地址信息
|
||||||
|
*/
|
||||||
|
FilePresignedUrlRespVO getFilePresignedUrl(String path) throws Exception;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,19 @@ import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.io.FileUtils;
|
import cn.iocoder.yudao.framework.common.util.io.FileUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.framework.file.core.client.FileClient;
|
import cn.iocoder.yudao.framework.file.core.client.FileClient;
|
||||||
|
import cn.iocoder.yudao.framework.file.core.client.s3.FilePresignedUrlRespDTO;
|
||||||
import cn.iocoder.yudao.framework.file.core.utils.FileTypeUtils;
|
import cn.iocoder.yudao.framework.file.core.utils.FileTypeUtils;
|
||||||
|
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
|
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePresignedUrlRespVO;
|
||||||
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
|
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
|
||||||
import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper;
|
import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_NOT_EXISTS;
|
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_NOT_EXISTS;
|
||||||
|
|
||||||
|
@ -66,6 +69,13 @@ public class FileServiceImpl implements FileService {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long createFile(FileCreateReqVO createReqVO) {
|
||||||
|
FileDO file = BeanUtils.toBean(createReqVO, FileDO.class);
|
||||||
|
fileMapper.insert(file);
|
||||||
|
return file.getId();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteFile(Long id) throws Exception {
|
public void deleteFile(Long id) throws Exception {
|
||||||
// 校验存在
|
// 校验存在
|
||||||
|
@ -95,4 +105,12 @@ public class FileServiceImpl implements FileService {
|
||||||
return client.getContent(path);
|
return client.getContent(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FilePresignedUrlRespVO getFilePresignedUrl(String path) throws Exception {
|
||||||
|
FileClient fileClient = fileConfigService.getMasterFileClient();
|
||||||
|
FilePresignedUrlRespDTO presignedObjectUrl = fileClient.getPresignedObjectUrl(path);
|
||||||
|
return BeanUtils.toBean(presignedObjectUrl, FilePresignedUrlRespVO.class,
|
||||||
|
object -> object.setConfigId(fileClient.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,11 +88,11 @@
|
||||||
<!-- </dependency>-->
|
<!-- </dependency>-->
|
||||||
|
|
||||||
<!-- CRM 相关模块。默认注释,保证编译速度 -->
|
<!-- CRM 相关模块。默认注释,保证编译速度 -->
|
||||||
<dependency>
|
<!-- <dependency>-->
|
||||||
<groupId>cn.iocoder.boot</groupId>
|
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||||
<artifactId>yudao-module-crm-biz</artifactId>
|
<!-- <artifactId>yudao-module-crm-biz</artifactId>-->
|
||||||
<version>${revision}</version>
|
<!-- <version>${revision}</version>-->
|
||||||
</dependency>
|
<!-- </dependency>-->
|
||||||
|
|
||||||
<!-- ERP 相关模块。默认注释,保证编译速度 -->
|
<!-- ERP 相关模块。默认注释,保证编译速度 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -35,6 +35,12 @@ public class DefaultController {
|
||||||
"[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
|
"[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/admin-api/erp/**")
|
||||||
|
public CommonResult<Boolean> erp404() {
|
||||||
|
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||||
|
"[ERP 模块 yudao-module-erp - 已禁用][参考 https://doc.iocoder.cn/erp/build/ 开启]");
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping(value = {"/admin-api/report/**"})
|
@RequestMapping(value = {"/admin-api/report/**"})
|
||||||
public CommonResult<Boolean> report404() {
|
public CommonResult<Boolean> report404() {
|
||||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||||
|
|
Loading…
Reference in New Issue