commit
bb9173f7f0
|
@ -35,6 +35,22 @@ public class MoneyUtils {
|
|||
return calculateRatePrice(price, rate, 0, RoundingMode.FLOOR).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算百分比金额
|
||||
*
|
||||
* @param price 金额(单位分)
|
||||
* @param count 数量
|
||||
* @param percent 折扣(单位分),列如 60.2%,则传入 6020
|
||||
* @return 商品总价
|
||||
*/
|
||||
public static Integer calculator(Integer price, Integer count, Integer percent) {
|
||||
price = price * count;
|
||||
if (percent == null) {
|
||||
return price;
|
||||
}
|
||||
return MoneyUtils.calculateRatePriceFloor(price, (double) (percent / 100));
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算百分比金额
|
||||
*
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package cn.iocoder.yudao.module.bpm.api.listener;
|
||||
|
||||
import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO;
|
||||
|
||||
/**
|
||||
* 业务流程实例的结果发生变化的监听器 Api
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
public interface BpmResultListenerApi {
|
||||
|
||||
/**
|
||||
* 监听的流程定义 Key
|
||||
*
|
||||
* @return 返回监听的流程定义 Key
|
||||
*/
|
||||
String getProcessDefinitionKey();
|
||||
|
||||
/**
|
||||
* 处理事件
|
||||
*
|
||||
* @param event 事件
|
||||
*/
|
||||
void onEvent(BpmResultListenerRespDTO event);
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package cn.iocoder.yudao.module.bpm.api.listener.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 业务流程实例的结果 Response DTO
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Data
|
||||
public class BpmResultListenerRespDTO {
|
||||
|
||||
/**
|
||||
* 流程实例的编号
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 流程实例的 key
|
||||
*/
|
||||
private String processDefinitionKey;
|
||||
/**
|
||||
* 流程实例的结果
|
||||
*/
|
||||
private Integer result;
|
||||
/**
|
||||
* 流程实例对应的业务标识
|
||||
* 例如说,请假
|
||||
*/
|
||||
private String businessKey;
|
||||
|
||||
}
|
|
@ -43,7 +43,7 @@ public class BpmModelController {
|
|||
return success(model);
|
||||
}
|
||||
|
||||
// TODO @puhui999:这个接口的目的是啥呀?
|
||||
// TODO @puhui999:这个接口的目的是啥呀?业务表单预览流程🤣
|
||||
@GetMapping("/get-by-key")
|
||||
@Operation(summary = "获得模型")
|
||||
@Parameter(name = "key", description = "流程标识", required = true, example = "oa_leave")
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package cn.iocoder.yudao.module.bpm.framework.bpm.listener;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
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.framework.bpm.core.event.BpmProcessInstanceResultEvent;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 业务流程结果监听器实现类
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Component
|
||||
public class BpmServiceResultListener implements ApplicationListener<BpmProcessInstanceResultEvent> {
|
||||
|
||||
@Resource
|
||||
private List<BpmResultListenerApi> bpmResultListenerApis;
|
||||
|
||||
@Override
|
||||
public final void onApplicationEvent(BpmProcessInstanceResultEvent event) {
|
||||
bpmResultListenerApis.forEach(bpmResultListenerApi -> {
|
||||
if (!StrUtil.equals(event.getProcessDefinitionKey(), bpmResultListenerApi.getProcessDefinitionKey())) {
|
||||
return;
|
||||
}
|
||||
bpmResultListenerApi.onEvent(BeanUtils.toBean(event, BpmResultListenerRespDTO.class));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -12,6 +12,7 @@ public interface ErrorCodeConstants {
|
|||
// ========== 合同管理 1-020-000-000 ==========
|
||||
ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在");
|
||||
ErrorCode CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED = new ErrorCode(1_020_000_001, "更新合同失败,原因:禁止编辑");
|
||||
ErrorCode CONTRACT_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_000_002, "合同提交审核失败,原因:合同没处在未提交状态");
|
||||
|
||||
// ========== 线索管理 1-020-001-000 ==========
|
||||
ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在");
|
||||
|
|
|
@ -39,6 +39,8 @@ public interface LogRecordConstants {
|
|||
String CRM_CUSTOMER_POOL_SUCCESS = "将客户【{{#customerName}}】放入了公海";
|
||||
String CRM_CUSTOMER_RECEIVE_SUB_TYPE = "{{#ownerUserName != null ? '分配客户' : '领取客户'}}";
|
||||
String CRM_CUSTOMER_RECEIVE_SUCCESS = "{{#ownerUserName != null ? '将客户【' + #customer.name + '】分配给【' + #ownerUserName + '】' : '领取客户【' + #customer.name + '】'}}";
|
||||
String CRM_CUSTOMER_IMPORT_SUB_TYPE = "{{#isUpdate ? '导入并更新客户' : '导入客户'}}";
|
||||
String CRM_CUSTOMER_IMPORT_SUCCESS = "{{#isUpdate ? '导入并更新了客户【'+ #customer.name +'】' : '导入了客户【'+ #customer.name +'】'}}";
|
||||
|
||||
// ======================= CRM_CUSTOMER_LIMIT_CONFIG 客户限制配置 =======================
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ public class CrmBusinessController {
|
|||
@PutMapping("/transfer")
|
||||
@Operation(summary = "商机转移")
|
||||
@PreAuthorize("@ss.hasPermission('crm:business:update')")
|
||||
public CommonResult<Boolean> transfer(@Valid @RequestBody CrmBusinessTransferReqVO reqVO) {
|
||||
public CommonResult<Boolean> transferBusiness(@Valid @RequestBody CrmBusinessTransferReqVO reqVO) {
|
||||
businessService.transferBusiness(reqVO, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ public class CrmClueController {
|
|||
@PutMapping("/transfer")
|
||||
@Operation(summary = "线索转移")
|
||||
@PreAuthorize("@ss.hasPermission('crm:clue:update')")
|
||||
public CommonResult<Boolean> transfer(@Valid @RequestBody CrmClueTransferReqVO reqVO) {
|
||||
public CommonResult<Boolean> transferClue(@Valid @RequestBody CrmClueTransferReqVO reqVO) {
|
||||
clueService.transferClue(reqVO, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ public class CrmContactController {
|
|||
List<CrmCustomerDO> customerList = customerService.getCustomerList(
|
||||
Collections.singletonList(contact.getCustomerId()));
|
||||
// 3. 直属上级
|
||||
List<CrmContactDO> parentContactList = contactService.getContactList(
|
||||
List<CrmContactDO> parentContactList = contactService.getContactListByIds(
|
||||
Collections.singletonList(contact.getParentId()), getLoginUserId());
|
||||
return success(CrmContactConvert.INSTANCE.convert(contact, userMap, customerList, parentContactList));
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ public class CrmContactController {
|
|||
@Parameter(name = "ids", description = "编号", required = true, example = "[1024]")
|
||||
@PreAuthorize("@ss.hasPermission('crm:contact:query')")
|
||||
public CommonResult<List<CrmContactRespVO>> getContactListByIds(@RequestParam("ids") List<Long> ids) {
|
||||
return success(BeanUtils.toBean(contactService.getContactList(ids, getLoginUserId()), CrmContactRespVO.class));
|
||||
return success(BeanUtils.toBean(contactService.getContactListByIds(ids, getLoginUserId()), CrmContactRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/simple-all-list")
|
||||
|
@ -170,7 +170,7 @@ public class CrmContactController {
|
|||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(contactList,
|
||||
contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId())));
|
||||
// 3. 直属上级
|
||||
List<CrmContactDO> parentContactList = contactService.getContactList(
|
||||
List<CrmContactDO> parentContactList = contactService.getContactListByIds(
|
||||
convertSet(contactList, CrmContactDO::getParentId), getLoginUserId());
|
||||
return CrmContactConvert.INSTANCE.convertPage(pageResult, userMap, crmCustomerDOList, parentContactList);
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ public class CrmContactController {
|
|||
@PutMapping("/transfer")
|
||||
@Operation(summary = "联系人转移")
|
||||
@PreAuthorize("@ss.hasPermission('crm:contact:update')")
|
||||
public CommonResult<Boolean> transfer(@Valid @RequestBody CrmContactTransferReqVO reqVO) {
|
||||
public CommonResult<Boolean> transferContact(@Valid @RequestBody CrmContactTransferReqVO reqVO) {
|
||||
contactService.transferContact(reqVO, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
|
|
@ -10,10 +10,18 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
|||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.*;
|
||||
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.CrmBusinessProductDO;
|
||||
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.customer.CrmCustomerDO;
|
||||
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.contact.CrmContactService;
|
||||
import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
|
||||
import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
|
||||
import cn.iocoder.yudao.module.crm.service.product.CrmProductService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
@ -28,13 +36,14 @@ import org.springframework.validation.annotation.Validated;
|
|||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap;
|
||||
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.framework.common.util.collection.MapUtils.findAndThen;
|
||||
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
|
@ -48,6 +57,15 @@ public class CrmContractController {
|
|||
private CrmContractService contractService;
|
||||
@Resource
|
||||
private CrmCustomerService customerService;
|
||||
@Resource
|
||||
private CrmContactService contactService;
|
||||
@Resource
|
||||
private CrmBusinessService businessService;
|
||||
@Resource
|
||||
@Lazy
|
||||
private CrmBusinessProductService businessProductService;
|
||||
@Resource
|
||||
private CrmProductService productService;
|
||||
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
@ -82,7 +100,19 @@ public class CrmContractController {
|
|||
@PreAuthorize("@ss.hasPermission('crm:contract:query')")
|
||||
public CommonResult<CrmContractRespVO> getContract(@RequestParam("id") Long id) {
|
||||
CrmContractDO contract = contractService.getContract(id);
|
||||
return success(BeanUtils.toBean(contract, CrmContractRespVO.class));
|
||||
List<CrmContractRespVO> respVOList = buildContractDetail(Collections.singletonList(contract));
|
||||
CrmContractRespVO respVO = respVOList.getFirst();
|
||||
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")
|
||||
|
@ -90,15 +120,15 @@ public class CrmContractController {
|
|||
@PreAuthorize("@ss.hasPermission('crm:contract:query')")
|
||||
public CommonResult<PageResult<CrmContractRespVO>> getContractPage(@Valid CrmContractPageReqVO pageVO) {
|
||||
PageResult<CrmContractDO> pageResult = contractService.getContractPage(pageVO, getLoginUserId());
|
||||
return success(buildContractDetailPage(pageResult));
|
||||
return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetail(pageResult.getList())));
|
||||
}
|
||||
|
||||
@GetMapping("/page-by-customer")
|
||||
@Operation(summary = "获得联系人分页,基于指定客户")
|
||||
@Operation(summary = "获得合同分页,基于指定客户")
|
||||
public CommonResult<PageResult<CrmContractRespVO>> getContractPageByCustomer(@Valid CrmContractPageReqVO pageVO) {
|
||||
Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空");
|
||||
PageResult<CrmContractDO> pageResult = contractService.getContractPageByCustomerId(pageVO);
|
||||
return success(buildContractDetailPage(pageResult));
|
||||
return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetail(pageResult.getList())));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
|
@ -114,40 +144,43 @@ public class CrmContractController {
|
|||
}
|
||||
|
||||
/**
|
||||
* 构建详细的合同分页结果
|
||||
* 构建详细的合同结果
|
||||
*
|
||||
* @param pageResult 简单的合同分页结果
|
||||
* @return 详细的合同分页结果
|
||||
* @param contractList 原始合同信息
|
||||
* @return 细的合同结果
|
||||
*/
|
||||
private PageResult<CrmContractRespVO> buildContractDetailPage(PageResult<CrmContractDO> pageResult) {
|
||||
List<CrmContractDO> contactList = pageResult.getList();
|
||||
if (CollUtil.isEmpty(contactList)) {
|
||||
return PageResult.empty(pageResult.getTotal());
|
||||
private List<CrmContractRespVO> buildContractDetail(List<CrmContractDO> contractList) {
|
||||
if (CollUtil.isEmpty(contractList)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 1. 获取客户列表
|
||||
List<CrmCustomerDO> customerList = customerService.getCustomerList(
|
||||
convertSet(contactList, CrmContractDO::getCustomerId));
|
||||
convertSet(contractList, CrmContractDO::getCustomerId));
|
||||
// 2. 获取创建人、负责人列表
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(contactList,
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(contractList,
|
||||
contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId())));
|
||||
return CrmContractConvert.INSTANCE.convertPage(pageResult, userMap, customerList);
|
||||
// 3. 获取联系人
|
||||
Map<Long, CrmContactDO> contactMap = convertMap(contactService.getContactListByIds(convertSet(contractList,
|
||||
CrmContractDO::getContactId)), CrmContactDO::getId);
|
||||
// 4. 获取商机
|
||||
Map<Long, CrmBusinessDO> businessMap = convertMap(businessService.getBusinessList(convertSet(contractList,
|
||||
CrmContractDO::getBusinessId)), CrmBusinessDO::getId);
|
||||
return CrmContractConvert.INSTANCE.convertList(contractList, userMap, customerList, contactMap, businessMap);
|
||||
}
|
||||
|
||||
// TODO @puhui999:transferContract
|
||||
@PutMapping("/transfer")
|
||||
@Operation(summary = "合同转移")
|
||||
@PreAuthorize("@ss.hasPermission('crm:contract:update')")
|
||||
public CommonResult<Boolean> transfer(@Valid @RequestBody CrmContractTransferReqVO reqVO) {
|
||||
public CommonResult<Boolean> transferContract(@Valid @RequestBody CrmContractTransferReqVO reqVO) {
|
||||
contractService.transferContract(reqVO, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// TODO @puhui999:方法名不对哈;要不改成 submit?提交审核的意思
|
||||
@PutMapping("/approve")
|
||||
@Operation(summary = "发起合同审批流程")
|
||||
@PutMapping("/submit")
|
||||
@Operation(summary = "提交合同审批")
|
||||
@PreAuthorize("@ss.hasPermission('crm:contract:update')")
|
||||
public CommonResult<Boolean> transfer(@RequestParam("id") Long id) {
|
||||
contractService.handleApprove(id, getLoginUserId());
|
||||
public CommonResult<Boolean> submitContract(@RequestParam("id") Long id) {
|
||||
contractService.submitContract(id, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,10 +3,13 @@ package cn.iocoder.yudao.module.crm.controller.admin.contract.vo;
|
|||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
|
@ -26,10 +29,16 @@ public class CrmContractRespVO {
|
|||
@Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336")
|
||||
@ExcelProperty("客户编号")
|
||||
private Long customerId;
|
||||
@Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336")
|
||||
@ExcelProperty("客户名称")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "商机编号", example = "10864")
|
||||
@ExcelProperty("商机编号")
|
||||
private Long businessId;
|
||||
@Schema(description = "商机名称", example = "10864")
|
||||
@ExcelProperty("商机名称")
|
||||
private String businessName;
|
||||
|
||||
@Schema(description = "工作流编号", example = "1043")
|
||||
@ExcelProperty("工作流编号")
|
||||
|
@ -74,10 +83,16 @@ public class CrmContractRespVO {
|
|||
@Schema(description = "联系人编号", example = "18546")
|
||||
@ExcelProperty("联系人编号")
|
||||
private Long contactId;
|
||||
@Schema(description = "联系人编号", example = "18546")
|
||||
@ExcelProperty("联系人编号")
|
||||
private String contactName;
|
||||
|
||||
@Schema(description = "公司签约人", example = "14036")
|
||||
@ExcelProperty("公司签约人")
|
||||
private Long signUserId;
|
||||
@Schema(description = "公司签约人", example = "14036")
|
||||
@ExcelProperty("公司签约人")
|
||||
private String signUserName;
|
||||
|
||||
@Schema(description = "最后跟进时间")
|
||||
@ExcelProperty("最后跟进时间")
|
||||
|
@ -101,10 +116,6 @@ public class CrmContractRespVO {
|
|||
@ExcelProperty("创建人名字")
|
||||
private String creatorName;
|
||||
|
||||
@Schema(description = "客户名字", example = "test")
|
||||
@ExcelProperty("客户名字")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "负责人", example = "test")
|
||||
@ExcelProperty("负责人")
|
||||
private String ownerUserName;
|
||||
|
@ -113,4 +124,36 @@ public class CrmContractRespVO {
|
|||
@ExcelProperty("审批状态")
|
||||
private Integer auditStatus;
|
||||
|
||||
@Schema(description = "产品列表")
|
||||
private List<CrmContractProductItemRespVO> productItems;
|
||||
|
||||
@Schema(description = "产品列表")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class CrmContractProductItemRespVO {
|
||||
|
||||
@Schema(description = "产品编号", example = "20529")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "产品编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
|
||||
private String no;
|
||||
|
||||
@Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
|
||||
private Integer unit;
|
||||
|
||||
@Schema(description = "价格,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
|
||||
private Integer price;
|
||||
|
||||
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
|
||||
private Integer count;
|
||||
|
||||
@Schema(description = "产品折扣")
|
||||
private Integer discountPercent;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -89,14 +89,11 @@ public class CrmContractSaveReqVO {
|
|||
@DiffLogField(name = "备注")
|
||||
private String remark;
|
||||
|
||||
// TODO @puhui999:这个字段,按道理不用传递?
|
||||
@Schema(description = "审批状态", example = "1")
|
||||
private Integer auditStatus;
|
||||
|
||||
@Schema(description = "产品列表")
|
||||
private List<CrmContractProductItem> productItems;
|
||||
|
||||
@Schema(description = "商品属性")
|
||||
@Schema(description = "产品列表")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
|
|
|
@ -235,7 +235,7 @@ public class CrmCustomerController {
|
|||
@PutMapping("/transfer")
|
||||
@Operation(summary = "转移客户")
|
||||
@PreAuthorize("@ss.hasPermission('crm:customer:update')")
|
||||
public CommonResult<Boolean> transfer(@Valid @RequestBody CrmCustomerTransferReqVO reqVO) {
|
||||
public CommonResult<Boolean> transferCustomer(@Valid @RequestBody CrmCustomerTransferReqVO reqVO) {
|
||||
customerService.transferCustomer(reqVO, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ public class CrmFollowUpRecordController {
|
|||
public CommonResult<PageResult<CrmFollowUpRecordRespVO>> getFollowUpRecordPage(@Valid CrmFollowUpRecordPageReqVO pageReqVO) {
|
||||
PageResult<CrmFollowUpRecordDO> pageResult = followUpRecordService.getFollowUpRecordPage(pageReqVO);
|
||||
/// 拼接数据
|
||||
Map<Long, CrmContactDO> contactMap = convertMap(contactService.getContactList(
|
||||
Map<Long, CrmContactDO> contactMap = convertMap(contactService.getContactListByIds(
|
||||
convertSetByFlatMap(pageResult.getList(), item -> item.getContactIds().stream())), CrmContactDO::getId);
|
||||
Map<Long, CrmBusinessDO> businessMap = convertMap(businessService.getBusinessList(
|
||||
convertSetByFlatMap(pageResult.getList(), item -> item.getBusinessIds().stream())), CrmBusinessDO::getId);
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package cn.iocoder.yudao.module.crm.convert.contract;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractRespVO;
|
||||
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.contact.CrmContactDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
||||
import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
|
||||
|
@ -31,17 +32,21 @@ public interface CrmContractConvert {
|
|||
@Mapping(target = "bizId", source = "reqVO.id")
|
||||
CrmPermissionTransferReqBO convert(CrmContractTransferReqVO reqVO, Long userId);
|
||||
|
||||
default PageResult<CrmContractRespVO> convertPage(PageResult<CrmContractDO> pageResult, Map<Long, AdminUserRespDTO> userMap,
|
||||
List<CrmCustomerDO> customerList) {
|
||||
PageResult<CrmContractRespVO> voPageResult = BeanUtils.toBean(pageResult, CrmContractRespVO.class);
|
||||
default List<CrmContractRespVO> convertList(List<CrmContractDO> contractList, Map<Long, AdminUserRespDTO> userMap,
|
||||
List<CrmCustomerDO> customerList, Map<Long, CrmContactDO> contactMap,
|
||||
Map<Long, CrmBusinessDO> businessMap) {
|
||||
List<CrmContractRespVO> respVOList = BeanUtils.toBean(contractList, CrmContractRespVO.class);
|
||||
// 拼接关联字段
|
||||
Map<Long, CrmCustomerDO> customerMap = convertMap(customerList, CrmCustomerDO::getId);
|
||||
voPageResult.getList().forEach(contract -> {
|
||||
respVOList.forEach(contract -> {
|
||||
findAndThen(userMap, contract.getOwnerUserId(), user -> contract.setOwnerUserName(user.getNickname()));
|
||||
findAndThen(userMap, Long.parseLong(contract.getCreator()), user -> contract.setCreatorName(user.getNickname()));
|
||||
findAndThen(userMap, contract.getSignUserId(), user -> contract.setSignUserName(user.getNickname()));
|
||||
findAndThen(customerMap, contract.getCustomerId(), customer -> contract.setCustomerName(customer.getName()));
|
||||
findAndThen(contactMap, contract.getContactId(), contact -> contract.setContactName(contact.getName()));
|
||||
findAndThen(businessMap, contract.getBusinessId(), business -> contract.setBusinessName(business.getName()));
|
||||
});
|
||||
return voPageResult;
|
||||
return respVOList;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package cn.iocoder.yudao.module.crm.dal.dataobject.business;
|
||||
|
||||
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.enums.DictTypeConstants;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
|
@ -40,6 +41,12 @@ public class CrmBusinessProductDO extends BaseDO {
|
|||
* 关联 {@link CrmProductDO#getId()}
|
||||
*/
|
||||
private Long productId;
|
||||
/**
|
||||
* 合同编号
|
||||
*
|
||||
* 关联 {@link CrmContractDO#getId()}
|
||||
*/
|
||||
private Long contractId;
|
||||
|
||||
/**
|
||||
* 产品单价
|
||||
|
|
|
@ -45,7 +45,7 @@ public class CrmProductDO extends BaseDO {
|
|||
/**
|
||||
* 价格,单位:分
|
||||
*/
|
||||
private Long price;
|
||||
private Integer price;
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
|
|
|
@ -101,10 +101,9 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
|
|||
return selectJoinPage(pageReqVO, CrmCustomerDO.class, query);
|
||||
}
|
||||
|
||||
default List<CrmCustomerDO> selectListByLockAndDealStatusAndNotPool(Boolean lockStatus, Boolean dealStatus) {
|
||||
default List<CrmCustomerDO> selectListByLockAndNotPool(Boolean lockStatus) {
|
||||
return selectList(new LambdaQueryWrapper<CrmCustomerDO>()
|
||||
.eq(CrmCustomerDO::getLockStatus, lockStatus)
|
||||
.eq(CrmCustomerDO::getDealStatus, dealStatus)
|
||||
.gt(CrmCustomerDO::getOwnerUserId, 0));
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.dal.mysql.product;
|
|||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
||||
|
@ -9,6 +10,9 @@ import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
|
|||
import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* CRM 产品 Mapper
|
||||
*
|
||||
|
@ -34,4 +38,8 @@ public interface CrmProductMapper extends BaseMapperX<CrmProductDO> {
|
|||
return selectOne(CrmProductDO::getNo, no);
|
||||
}
|
||||
|
||||
default List<CrmProductDO> selectListByIds(Collection<Long> ids) {
|
||||
return selectList(new LambdaQueryWrapperX<CrmProductDO>().in(CrmProductDO::getId, ids));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
|
|||
import java.util.List;
|
||||
|
||||
// TODO @lzxhqs:方法名上,带下 BusinessProduct;主要考虑不精简的原因,是因为一个逻辑,可能会出现一些超越它自身方法,省略不容易懂;
|
||||
|
||||
/**
|
||||
* 商机产品关联表 Service 接口
|
||||
*
|
||||
|
@ -14,31 +15,45 @@ public interface CrmBusinessProductService {
|
|||
|
||||
/**
|
||||
* 批量新增商机产品关联数据
|
||||
*
|
||||
* @param list 商机产品集合
|
||||
*/
|
||||
void insertBatch(List<CrmBusinessProductDO> list);
|
||||
void createBusinessProductBatch(List<CrmBusinessProductDO> list);
|
||||
|
||||
/**
|
||||
* 根据商机id获取商机产品关联数据集合
|
||||
*
|
||||
* @param businessId 商机id
|
||||
*/
|
||||
List<CrmBusinessProductDO> selectListByBusinessId(Long businessId);
|
||||
List<CrmBusinessProductDO> getBusinessProductListByBusinessId(Long businessId);
|
||||
|
||||
/**
|
||||
* 批量更新商机产品表
|
||||
*
|
||||
* @param list 商机产品数据集合
|
||||
*/
|
||||
void updateBatch(List<CrmBusinessProductDO> list);
|
||||
void updateBusinessProductBatch(List<CrmBusinessProductDO> list);
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
*
|
||||
* @param list 需要删除的商机产品集合
|
||||
*/
|
||||
void deleteBatch(List<CrmBusinessProductDO> list);
|
||||
void deleteBusinessProductBatch(List<CrmBusinessProductDO> list);
|
||||
|
||||
/**
|
||||
* 根据商机id删除商机产品关联数据
|
||||
*
|
||||
* @param businessId 商机id
|
||||
*/
|
||||
void deleteByBusinessId(Long businessId);
|
||||
void deleteBusinessProductByBusinessId(Long businessId);
|
||||
|
||||
/**
|
||||
* 获得合同关联的商品列表
|
||||
*
|
||||
* @param contractId 合同编号
|
||||
* @return 关联的商品列表
|
||||
*/
|
||||
List<CrmBusinessProductDO> getBusinessProductListByContractId(Long contractId);
|
||||
|
||||
}
|
||||
|
|
|
@ -22,29 +22,34 @@ public class CrmBusinessProductServiceImpl implements CrmBusinessProductService
|
|||
private CrmBusinessProductMapper businessProductMapper;
|
||||
|
||||
@Override
|
||||
public void insertBatch(List<CrmBusinessProductDO> list) {
|
||||
public void createBusinessProductBatch(List<CrmBusinessProductDO> list) {
|
||||
businessProductMapper.insertBatch(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CrmBusinessProductDO> selectListByBusinessId(Long businessId) {
|
||||
public List<CrmBusinessProductDO> getBusinessProductListByBusinessId(Long businessId) {
|
||||
return businessProductMapper.selectList(CrmBusinessProductDO::getBusinessId, businessId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBatch(List<CrmBusinessProductDO> list) {
|
||||
public void updateBusinessProductBatch(List<CrmBusinessProductDO> list) {
|
||||
businessProductMapper.updateBatch(list);
|
||||
}
|
||||
|
||||
// TODO @lzxhqs:这个方法,可以直接调用 deleteList 方法,然后传递 ids 就好了;
|
||||
@Override
|
||||
public void deleteBatch(List<CrmBusinessProductDO> list) {
|
||||
public void deleteBusinessProductBatch(List<CrmBusinessProductDO> list) {
|
||||
businessProductMapper.deleteBatchIds(CollectionUtils.convertList(list, CrmBusinessProductDO::getId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByBusinessId(Long businessId) {
|
||||
public void deleteBusinessProductByBusinessId(Long businessId) {
|
||||
businessProductMapper.deleteByBusinessId(businessId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CrmBusinessProductDO> getBusinessProductListByContractId(Long contractId) {
|
||||
return businessProductMapper.selectList(CrmBusinessProductDO::getContractId, contractId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -120,20 +120,20 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
|||
CrmBusinessProductConvert.INSTANCE.convert(product).setBusinessId(businessId));
|
||||
if (Boolean.TRUE.equals(updateFlag)) {
|
||||
// 根据商机 id从商机产品关联表中获取已存在的数据集合
|
||||
List<CrmBusinessProductDO> oldProducts = businessProductService.selectListByBusinessId(businessId);
|
||||
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.insertBatch(diffList.getFirst());
|
||||
businessProductService.createBusinessProductBatch(diffList.getFirst());
|
||||
}
|
||||
if (CollUtil.isNotEmpty(diffList.get(1))) {
|
||||
businessProductService.updateBatch(diffList.get(1));
|
||||
businessProductService.updateBusinessProductBatch(diffList.get(1));
|
||||
}
|
||||
if (CollUtil.isNotEmpty(diffList.get(2))) {
|
||||
businessProductService.deleteBatch(diffList.get(2));
|
||||
businessProductService.deleteBusinessProductBatch(diffList.get(2));
|
||||
}
|
||||
} else {
|
||||
businessProductService.insertBatch(list);
|
||||
businessProductService.createBusinessProductBatch(list);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
|||
if (CollUtil.isNotEmpty(updateReqVO.getProducts())) {
|
||||
createBusinessProducts(updateReqVO.getProducts(), updateReqVO.getId(), true);
|
||||
} else {
|
||||
businessProductService.deleteByBusinessId(updateReqVO.getId());
|
||||
businessProductService.deleteBusinessProductByBusinessId(updateReqVO.getId());
|
||||
}
|
||||
|
||||
// TODO @商机待定:如果状态发生变化,插入商机状态变更记录表
|
||||
|
@ -196,7 +196,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
|||
*/
|
||||
private void validateContractExists(Long businessId) {
|
||||
// TODO @lzxhqs:保持风格的统一,selectCountByBusinessId 改成 getContractCountByBusinessId;另外,可以不用声明 count,因为就一次性使用,直接把 197 和 198 合并成一行;
|
||||
Long count = contractService.selectCountByBusinessId(businessId);
|
||||
Long count = contractService.getContractCountByBusinessId(businessId);
|
||||
if (count > 0) {
|
||||
throw exception(BUSINESS_CONTRACT_EXISTS);
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ public interface CrmContactService {
|
|||
* @param userId 用户编号
|
||||
* @return 联系人列表
|
||||
*/
|
||||
List<CrmContactDO> getContactList(Collection<Long> ids, Long userId);
|
||||
List<CrmContactDO> getContactListByIds(Collection<Long> ids, Long userId);
|
||||
|
||||
/**
|
||||
* 获得联系人列表
|
||||
|
@ -88,7 +88,7 @@ public interface CrmContactService {
|
|||
* @param ids 编号
|
||||
* @return 联系人列表
|
||||
*/
|
||||
List<CrmContactDO> getContactList(Collection<Long> ids);
|
||||
List<CrmContactDO> getContactListByIds(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得联系人列表
|
||||
|
|
|
@ -25,6 +25,7 @@ import com.mzt.logapi.context.LogRecordContext;
|
|||
import com.mzt.logapi.service.impl.DiffParseFunction;
|
||||
import com.mzt.logapi.starter.annotation.LogRecord;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
@ -56,6 +57,7 @@ public class CrmContactServiceImpl implements CrmContactService {
|
|||
@Resource
|
||||
private CrmPermissionService permissionService;
|
||||
@Resource
|
||||
@Lazy
|
||||
private CrmContractService contractService;
|
||||
@Resource
|
||||
private CrmContactBusinessService contactBusinessService;
|
||||
|
@ -208,7 +210,7 @@ public class CrmContactServiceImpl implements CrmContactService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<CrmContactDO> getContactList(Collection<Long> ids, Long userId) {
|
||||
public List<CrmContactDO> getContactListByIds(Collection<Long> ids, Long userId) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return ListUtil.empty();
|
||||
}
|
||||
|
@ -216,7 +218,7 @@ public class CrmContactServiceImpl implements CrmContactService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<CrmContactDO> getContactList(Collection<Long> ids) {
|
||||
public List<CrmContactDO> getContactListByIds(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return ListUtil.empty();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package cn.iocoder.yudao.module.crm.service.contract;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.bpm.api.listener.dto.BpmResultListenerRespDTO;
|
||||
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.CrmContractTransferReqVO;
|
||||
|
@ -63,8 +64,14 @@ public interface CrmContractService {
|
|||
* @param id 合同编号
|
||||
* @param userId 用户编号
|
||||
*/
|
||||
void handleApprove(Long id, Long userId);
|
||||
void submitContract(Long id, Long userId);
|
||||
|
||||
/**
|
||||
* 更新合同流程审批结果
|
||||
*
|
||||
* @param event 审批结果
|
||||
*/
|
||||
void updateContractAuditStatus(BpmResultListenerRespDTO event);
|
||||
/**
|
||||
* 获得合同
|
||||
*
|
||||
|
@ -118,13 +125,12 @@ public interface CrmContractService {
|
|||
*/
|
||||
Long getContractCountByCustomerId(Long customerId);
|
||||
|
||||
// TODO @puhui999:要不改成 getContractCountByBusinessId
|
||||
/**
|
||||
* 根据商机ID获取关联客户的合同数量
|
||||
*
|
||||
* @param businessId 商机编号
|
||||
* @return 数量
|
||||
*/
|
||||
Long selectCountByBusinessId(Long businessId);
|
||||
Long getContractCountByBusinessId(Long businessId);
|
||||
|
||||
}
|
||||
|
|
|
@ -2,10 +2,13 @@ package cn.iocoder.yudao.module.crm.service.contract;
|
|||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
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.ObjectUtils;
|
||||
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.dto.BpmProcessInstanceCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO;
|
||||
|
@ -87,8 +90,11 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||
CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null);
|
||||
contractMapper.insert(contract);
|
||||
// 1.2 插入商机关联商品
|
||||
List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO);
|
||||
businessProductService.insertBatch(businessProduct);
|
||||
if (CollUtil.isNotEmpty(createReqVO.getProductItems())) { // 如果有的话
|
||||
List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO, contract.getId());
|
||||
businessProductService.createBusinessProductBatch(businessProduct);
|
||||
// 更新合同商品总金额
|
||||
}
|
||||
|
||||
// 2. 创建数据权限
|
||||
crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId)
|
||||
|
@ -106,9 +112,11 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||
success = CRM_CONTRACT_UPDATE_SUCCESS)
|
||||
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
|
||||
public void updateContract(CrmContractSaveReqVO updateReqVO) {
|
||||
// TODO @合同待定:只有草稿、审批中,可以编辑;
|
||||
if (ObjUtil.notEqual(updateReqVO.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus()) ||
|
||||
ObjUtil.notEqual(updateReqVO.getAuditStatus(), CrmAuditStatusEnum.PROCESS.getStatus())) {
|
||||
Assert.notNull(updateReqVO.getId(), "合同编号不能为空");
|
||||
CrmContractDO contract = validateContractExists(updateReqVO.getId());
|
||||
// 只有草稿、审批中,可以编辑;
|
||||
if (!ObjectUtils.equalsAny(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(),
|
||||
CrmAuditStatusEnum.PROCESS.getStatus())) {
|
||||
throw exception(CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED);
|
||||
}
|
||||
validateRelationDataExists(updateReqVO);
|
||||
|
@ -117,21 +125,41 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||
// 更新合同
|
||||
CrmContractDO updateObj = BeanUtils.toBean(updateReqVO, CrmContractDO.class);
|
||||
contractMapper.updateById(updateObj);
|
||||
|
||||
// TODO puhui999: @芋艿:合同变更关联的商机后商品怎么处理?
|
||||
// TODO @puhui999:和商品 spu、sku 编辑一样;新增的插入;修改的更新;删除的删除
|
||||
//List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(updateReqVO);
|
||||
//businessProductService.selectListByBusinessId()
|
||||
//diffList()
|
||||
// 更新合同关联商品
|
||||
updateContractProduct(updateReqVO, updateObj.getId());
|
||||
|
||||
// 3. 记录操作日志上下文
|
||||
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContract, CrmContractSaveReqVO.class));
|
||||
LogRecordContext.putVariable("contractName", oldContract.getName());
|
||||
}
|
||||
|
||||
private void updateContractProduct(CrmContractSaveReqVO updateReqVO, Long contractId) {
|
||||
if (CollUtil.isEmpty(updateReqVO.getProductItems())) {
|
||||
return;
|
||||
}
|
||||
List<CrmBusinessProductDO> newProductList = convertBusinessProductList(updateReqVO, contractId);
|
||||
List<CrmBusinessProductDO> oldProductList = businessProductService.getBusinessProductListByContractId(contractId);
|
||||
List<List<CrmBusinessProductDO>> diffList = diffList(oldProductList, newProductList, (oldObj, newObj) -> {
|
||||
if (ObjUtil.notEqual(oldObj.getProductId(), newObj.getProductId())) {
|
||||
return false;
|
||||
}
|
||||
newObj.setId(oldObj.getId()); // 设置一下老的编号更新时需要使用
|
||||
return true;
|
||||
});
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO @合同待定:缺一个取消合同的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum
|
||||
|
||||
private List<CrmBusinessProductDO> convertBusinessProductList(CrmContractSaveReqVO reqVO) {
|
||||
private List<CrmBusinessProductDO> convertBusinessProductList(CrmContractSaveReqVO reqVO, Long contractId) {
|
||||
// 校验商品存在
|
||||
Set<Long> productIds = convertSet(reqVO.getProductItems(), CrmContractSaveReqVO.CrmContractProductItem::getId);
|
||||
List<CrmProductDO> productList = productService.getProductList(productIds);
|
||||
|
@ -140,29 +168,14 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||
}
|
||||
Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId);
|
||||
return convertList(reqVO.getProductItems(), productItem -> {
|
||||
// TODO @puhui999:这里可以改成直接 return,不用弄一个 businessProduct 变量哈;
|
||||
CrmBusinessProductDO businessProduct = BeanUtils.toBean(productMap.get(productItem.getId()), CrmBusinessProductDO.class);
|
||||
businessProduct.setId(null).setBusinessId(reqVO.getBusinessId()).setProductId(productItem.getId())
|
||||
.setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent()).setTotalPrice(calculator(businessProduct));
|
||||
return businessProduct;
|
||||
CrmProductDO product = productMap.get(productItem.getId());
|
||||
return BeanUtils.toBean(product, CrmBusinessProductDO.class)
|
||||
.setId(null).setBusinessId(reqVO.getBusinessId()).setProductId(productItem.getId()).setContractId(contractId)
|
||||
.setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent())
|
||||
.setTotalPrice(MoneyUtils.calculator(product.getPrice(), productItem.getCount(), productItem.getDiscountPercent()));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算商品总价
|
||||
*
|
||||
* @param businessProduct 关联商品
|
||||
* @return 商品总价
|
||||
*/
|
||||
// TODO @puhui999:这个逻辑的计算,是不是可以封装到 calculateRatePriceFloor 里;
|
||||
private Integer calculator(CrmBusinessProductDO businessProduct) {
|
||||
int price = businessProduct.getPrice() * businessProduct.getCount();
|
||||
if (businessProduct.getDiscountPercent() == null) {
|
||||
return price;
|
||||
}
|
||||
return MoneyUtils.calculateRatePriceFloor(price, (double) (businessProduct.getDiscountPercent() / 100));
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验关联数据是否存在
|
||||
*
|
||||
|
@ -235,9 +248,12 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void handleApprove(Long id, Long userId) {
|
||||
// TODO @puhui999:需要做状态检查
|
||||
|
||||
public void submitContract(Long id, Long userId) {
|
||||
// 1. 校验合同是否在审批
|
||||
CrmContractDO contract = validateContractExists(id);
|
||||
if (ObjUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus())) {
|
||||
throw exception(CONTRACT_SUBMIT_FAIL_NOT_DRAFT);
|
||||
}
|
||||
// 创建合同审批流程实例
|
||||
String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
|
||||
.setProcessDefinitionKey(CONTRACT_APPROVE).setBusinessKey(String.valueOf(id)));
|
||||
|
@ -247,6 +263,12 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||
.setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateContractAuditStatus(BpmResultListenerRespDTO event) {
|
||||
contractMapper.updateById(new CrmContractDO().setId(Long.parseLong(event.getBusinessKey()))
|
||||
.setAuditStatus(event.getResult()));
|
||||
}
|
||||
|
||||
//======================= 查询相关 =======================
|
||||
|
||||
@Override
|
||||
|
@ -285,7 +307,7 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Long selectCountByBusinessId(Long businessId) {
|
||||
public Long getContractCountByBusinessId(Long businessId) {
|
||||
return contractMapper.selectCountByBusinessId(businessId);
|
||||
}
|
||||
// TODO @合同待定:需要新增一个 ContractConfigDO 表,合同配置,重点是到期提醒;
|
||||
|
|
|
@ -1,5 +1,59 @@
|
|||
package cn.iocoder.yudao.module.crm.service.contract.listener;
|
||||
|
||||
public class CrmContractResultListener {
|
||||
// TODO puhui999: @芋艿: 艿艿写一下这个,没研究明白哈哈
|
||||
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.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.CrmContractServiceImpl;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 合同审批的结果的监听器实现类
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Component
|
||||
public class CrmContractResultListener implements BpmResultListenerApi {
|
||||
|
||||
@Resource
|
||||
private CrmContractService contractService;
|
||||
|
||||
@Override
|
||||
public String getProcessDefinitionKey() {
|
||||
return CrmContractServiceImpl.CONTRACT_APPROVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断该结果是否处于 End 最终结果
|
||||
*
|
||||
* @param result 结果
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isEndResult(Integer result) {
|
||||
return ObjectUtils.equalsAny(result, BpmProcessInstanceResultEnum.APPROVE.getResult(),
|
||||
BpmProcessInstanceResultEnum.REJECT.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -93,8 +93,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||
validateCustomerExceedOwnerLimit(createReqVO.getOwnerUserId(), 1);
|
||||
|
||||
// 2. 插入客户
|
||||
CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class).setOwnerUserId(userId)
|
||||
.setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
|
||||
CrmCustomerDO customer = initCustomer(createReqVO, userId);
|
||||
customerMapper.insert(customer);
|
||||
|
||||
// 3. 创建数据权限
|
||||
|
@ -232,7 +231,6 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||
return customer.getId();
|
||||
}
|
||||
|
||||
// TODO @puhui999:操作日志
|
||||
@Override
|
||||
public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers,
|
||||
Boolean isUpdateSupport, Long userId) {
|
||||
|
@ -253,14 +251,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||
// 判断如果不存在,在进行插入
|
||||
CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName());
|
||||
if (existCustomer == null) {
|
||||
// TODO @puhui999:可以搞个 initCustomer 方法;这样可以把 create 和导入复用下这个方法;
|
||||
CrmCustomerDO customer = BeanUtils.toBean(importCustomer, CrmCustomerDO.class).setOwnerUserId(userId)
|
||||
.setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
|
||||
CrmCustomerDO customer = initCustomer(importCustomer, userId);
|
||||
customerMapper.insert(customer);
|
||||
respVO.getCreateCustomerNames().add(importCustomer.getName());
|
||||
// 创建数据权限
|
||||
permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
|
||||
.setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
|
||||
// 记录操作日志
|
||||
getSelf().importCustomerLog(customer, false);
|
||||
return;
|
||||
}
|
||||
// 如果存在,判断是否允许更新
|
||||
|
@ -273,10 +271,25 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||
updateCustomer.setId(existCustomer.getId());
|
||||
customerMapper.updateById(updateCustomer);
|
||||
respVO.getUpdateCustomerNames().add(importCustomer.getName());
|
||||
// 记录操作日志
|
||||
getSelf().importCustomerLog(updateCustomer, true);
|
||||
});
|
||||
return respVO;
|
||||
}
|
||||
|
||||
private static CrmCustomerDO initCustomer(Object customer, Long userId) {
|
||||
return BeanUtils.toBean(customer, CrmCustomerDO.class).setOwnerUserId(userId)
|
||||
.setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
|
||||
}
|
||||
|
||||
@LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_IMPORT_SUB_TYPE, bizNo = "{{#customer.id}}",
|
||||
success = CRM_CUSTOMER_IMPORT_SUCCESS)
|
||||
public void importCustomerLog(CrmCustomerDO customer, boolean isUpdate) {
|
||||
// 记录操作日志上下文
|
||||
LogRecordContext.putVariable("customer", customer);
|
||||
LogRecordContext.putVariable("isUpdate", isUpdate);
|
||||
}
|
||||
|
||||
private void validateCustomerForCreate(CrmCustomerImportExcelVO importCustomer) {
|
||||
// 校验客户名称不能为空
|
||||
if (StrUtil.isEmptyIfStr(importCustomer.getName())) {
|
||||
|
@ -367,15 +380,15 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||
if (poolConfig == null || !poolConfig.getEnabled()) {
|
||||
return 0;
|
||||
}
|
||||
// 1.1 获取没有锁定的不在公海的客户且没有成交的
|
||||
List<CrmCustomerDO> notDealCustomerList = customerMapper.selectListByLockAndDealStatusAndNotPool(Boolean.FALSE, Boolean.FALSE);
|
||||
// 1.2 获取没有锁定的不在公海的客户且成交的
|
||||
// TODO @puhui999:下面也搞到 sql 里去哈;写 or 查询,问题不大的;
|
||||
List<CrmCustomerDO> dealCustomerList = customerMapper.selectListByLockAndDealStatusAndNotPool(Boolean.FALSE, Boolean.TRUE);
|
||||
// 1.1 获取没有锁定的不在公海的客户
|
||||
List<CrmCustomerDO> customerList = customerMapper.selectListByLockAndNotPool(Boolean.FALSE);
|
||||
List<CrmCustomerDO> poolCustomerList = new ArrayList<>();
|
||||
poolCustomerList.addAll(filterList(notDealCustomerList, customer ->
|
||||
(poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime())) <= 0));
|
||||
poolCustomerList.addAll(filterList(dealCustomerList, customer -> {
|
||||
poolCustomerList.addAll(filterList(customerList, customer ->
|
||||
!customer.getDealStatus() && (poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime())) <= 0));
|
||||
poolCustomerList.addAll(filterList(customerList, customer -> {
|
||||
if (!customer.getDealStatus()) { // 这里只处理成交的
|
||||
return false;
|
||||
}
|
||||
LocalDateTime lastTime = ObjUtil.defaultIfNull(customer.getContactLastTime(), customer.getCreateTime());
|
||||
return (poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime)) <= 0;
|
||||
}));
|
||||
|
|
|
@ -69,4 +69,13 @@ public interface CrmProductService {
|
|||
* @return 产品
|
||||
*/
|
||||
CrmProductDO getProductByCategoryId(Long categoryId);
|
||||
|
||||
/**
|
||||
* 获得产品列表
|
||||
*
|
||||
* @param ids 产品编号
|
||||
* @return 产品列表
|
||||
*/
|
||||
List<CrmProductDO> getProductListByIds(Collection<Long> ids);
|
||||
|
||||
}
|
||||
|
|
|
@ -155,4 +155,12 @@ public class CrmProductServiceImpl implements CrmProductService {
|
|||
return productMapper.selectOne(new LambdaQueryWrapper<CrmProductDO>().eq(CrmProductDO::getCategoryId, categoryId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CrmProductDO> getProductListByIds(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return productMapper.selectListByIds(ids);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue