mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 10:18:42 +08:00 
			
		
		
		
	Merge branch 'develop' of https://gitee.com/puhui999/ruoyi-vue-pro into develop
# Conflicts: # yudao-module-erp/yudao-module-erp-biz/src/test/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImplTest.java
This commit is contained in:
		| @@ -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.CrmBusinessStatusTypeRespVO; | ||||
| 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.businessstatustype.CrmBusinessStatusTypeConvert; | ||||
| import cn.iocoder.yudao.module.crm.convert.business.CrmBusinessStatusConvert; | ||||
| 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.CrmBusinessStatusTypeDO; | ||||
| import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusService; | ||||
|   | ||||
| @@ -1,18 +1,18 @@ | ||||
| package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; | ||||
|  | ||||
| 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.framework.operatelog.core.CrmCustomerParseFunction; | ||||
| import com.mzt.logapi.starter.annotation.DiffLogField; | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
| import org.springframework.format.annotation.DateTimeFormat; | ||||
|  | ||||
| import java.math.BigDecimal; | ||||
| import java.time.LocalDateTime; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| 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 = "商机金额") | ||||
|     private Integer price; | ||||
|  | ||||
|     // TODO @lzxhqs:折扣使用 Integer 类型,存储时,默认 * 100;展示的时候,前端需要 / 100;避免精度丢失问题 | ||||
|     @Schema(description = "整单折扣") | ||||
|     @DiffLogField(name = "整单折扣") | ||||
|     private Integer discountPercent; | ||||
| @@ -75,11 +74,29 @@ public class CrmBusinessSaveReqVO { | ||||
|     @InEnum(CrmBizEndStatus.class) | ||||
|     private Integer endStatus; | ||||
|  | ||||
|     // TODO @lzxhqs:不设置默认 new ArrayList<>();一般 pojo 不设置默认值哈 | ||||
|     @Schema(description = "商机产品列表") | ||||
|     private List<CrmBusinessProductSaveReqVO> products = new ArrayList<>(); | ||||
|  | ||||
|     @Schema(description = "联系人编号", example = "110") | ||||
|     private Long contactId; // 使用场景,在【联系人详情】添加商机时,如果需要关联两者,需要传递 contactId 字段 | ||||
|  | ||||
|     @Schema(description = "产品列表") | ||||
|     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; | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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.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.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.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.contract.CrmContractProductDO; | ||||
| 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; | ||||
| @@ -30,7 +32,6 @@ import io.swagger.v3.oas.annotations.tags.Tag; | ||||
| import jakarta.annotation.Resource; | ||||
| import jakarta.servlet.http.HttpServletResponse; | ||||
| import jakarta.validation.Valid; | ||||
| import org.springframework.context.annotation.Lazy; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
| @@ -43,7 +44,6 @@ 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.*; | ||||
| 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; | ||||
|  | ||||
| @@ -62,11 +62,7 @@ public class CrmContractController { | ||||
|     @Resource | ||||
|     private CrmBusinessService businessService; | ||||
|     @Resource | ||||
|     @Lazy | ||||
|     private CrmBusinessProductService businessProductService; | ||||
|     @Resource | ||||
|     private CrmProductService productService; | ||||
|  | ||||
|     @Resource | ||||
|     private AdminUserApi adminUserApi; | ||||
|  | ||||
| @@ -105,22 +101,9 @@ public class CrmContractController { | ||||
|             return success(null); | ||||
|         } | ||||
|  | ||||
|         // 2.1 拼接合同信息 | ||||
|         // 2. 拼接合同信息 | ||||
|         List<CrmContractRespVO> respVOList = buildContractDetailList(Collections.singletonList(contract)); | ||||
|         // 2.2 拼接产品信息 | ||||
|         // 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); | ||||
|         return success(respVOList.get(0)); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/page") | ||||
| @@ -147,8 +130,24 @@ public class CrmContractController { | ||||
|                                     HttpServletResponse response) throws IOException { | ||||
|         PageResult<CrmContractDO> pageResult = contractService.getContractPage(exportReqVO, getLoginUserId()); | ||||
|         // 导出 Excel | ||||
|         ExcelUtils.write(response, "合同.xls", "数据", CrmContractExcelVO.class, | ||||
|                 BeanUtils.toBean(pageResult.getList(), CrmContractExcelVO.class)); | ||||
|         ExcelUtils.write(response, "合同.xls", "数据", CrmContractRespVO.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 +172,15 @@ public class CrmContractController { | ||||
|         // 4. 获取商机 | ||||
|         Map<Long, CrmBusinessDO> businessMap = convertMap(businessService.getBusinessList(convertSet(contractList, | ||||
|                 CrmContractDO::getBusinessId)), CrmBusinessDO::getId); | ||||
|         return CrmContractConvert.INSTANCE.convertList(contractList, userMap, customerList, contactMap, businessMap); | ||||
|     } | ||||
|  | ||||
|     @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); | ||||
|         // 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); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
| } | ||||
| @@ -21,7 +21,6 @@ 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; | ||||
| import io.swagger.v3.oas.annotations.Parameter; | ||||
| import io.swagger.v3.oas.annotations.Parameters; | ||||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||||
| import jakarta.annotation.Resource; | ||||
| import jakarta.servlet.http.HttpServletResponse; | ||||
| @@ -30,7 +29,6 @@ import org.mapstruct.ap.internal.util.Collections; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
| import org.springframework.web.multipart.MultipartFile; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.time.LocalDateTime; | ||||
| @@ -218,19 +216,13 @@ public class CrmCustomerController { | ||||
|         ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list); | ||||
|     } | ||||
|  | ||||
|     // TODO @puhui999:updateSupport 要不改成前端必须传递;哈哈哈,代码排版看着有点乱; | ||||
|     // TODO @puhui999:加一个选择负责人;允许空,空就进入公海; | ||||
|     @PostMapping("/import") | ||||
|     @Operation(summary = "导入客户") | ||||
|     @Parameters({ | ||||
|             @Parameter(name = "file", description = "Excel 文件", required = true), | ||||
|             @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") | ||||
|     }) | ||||
|     @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 { | ||||
|         List<CrmCustomerImportExcelVO> list = ExcelUtils.read(file, CrmCustomerImportExcelVO.class); | ||||
|         return success(customerService.importCustomerList(list, updateSupport, getLoginUserId())); | ||||
|         List<CrmCustomerImportExcelVO> list = ExcelUtils.read(importReqVO.getFile(), CrmCustomerImportExcelVO.class); | ||||
|         return success(customerService.importCustomerList(list, importReqVO)); | ||||
|     } | ||||
|  | ||||
|     @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 则客户进入公海 | ||||
|  | ||||
| } | ||||
| @@ -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.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.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; | ||||
|  | ||||
| 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.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.contract.CrmContractProductDO; | ||||
| 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.system.api.user.dto.AdminUserRespDTO; | ||||
| import org.mapstruct.Mapper; | ||||
| @@ -34,7 +38,8 @@ public interface CrmContractConvert { | ||||
|  | ||||
|     default List<CrmContractRespVO> convertList(List<CrmContractDO> contractList, Map<Long, AdminUserRespDTO> userMap, | ||||
|                                                 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); | ||||
|         // 拼接关联字段 | ||||
|         Map<Long, CrmCustomerDO> customerMap = convertMap(customerList, CrmCustomerDO::getId); | ||||
| @@ -46,7 +51,21 @@ public interface CrmContractConvert { | ||||
|             findAndThen(contactMap, contract.getContactId(), contact -> contract.setContactName(contact.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; | ||||
|     } | ||||
|  | ||||
|     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; | ||||
|  | ||||
| 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; | ||||
| import com.baomidou.mybatisplus.annotation.TableId; | ||||
| import com.baomidou.mybatisplus.annotation.TableName; | ||||
| @@ -41,19 +39,10 @@ public class CrmBusinessProductDO extends BaseDO { | ||||
|      * 关联 {@link CrmProductDO#getId()} | ||||
|      */ | ||||
|     private Long productId; | ||||
|     // TODO 芋艿:需要在看下 CRM | ||||
|     /** | ||||
|      * 合同编号 | ||||
|      * | ||||
|      * 关联 {@link CrmContractDO#getId()} | ||||
|      */ | ||||
|     private Long contractId; | ||||
|  | ||||
|     /** | ||||
|      * 产品单价 | ||||
|      */ | ||||
|     private Integer price; | ||||
|  | ||||
|     /** | ||||
|      * 销售价格, 单位:分 | ||||
|      */ | ||||
| @@ -71,11 +60,4 @@ public class CrmBusinessProductDO extends BaseDO { | ||||
|      */ | ||||
|     private Integer totalPrice; | ||||
|  | ||||
|     /** | ||||
|      * 单位 | ||||
|      * | ||||
|      * 字典 {@link DictTypeConstants#CRM_PRODUCT_UNIT} | ||||
|      */ | ||||
|     private Integer unit; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,63 @@ | ||||
| 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; | ||||
|     /** | ||||
|      * 总计价格(折扣后价格) | ||||
|      */ | ||||
|     private Integer totalPrice; | ||||
|  | ||||
| } | ||||
| @@ -1,4 +0,0 @@ | ||||
| /** | ||||
|  * 合同 | ||||
|  */ | ||||
| package cn.iocoder.yudao.module.crm.dal.dataobject.contract; | ||||
| @@ -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.query.LambdaQueryWrapperX; | ||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO; | ||||
| import org.apache.ibatis.annotations.Mapper; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 商机产品 Mapper | ||||
|  * | ||||
| @@ -21,4 +24,8 @@ public interface CrmBusinessProductMapper extends BaseMapperX<CrmBusinessProduct | ||||
|         return selectOne(CrmBusinessProductDO::getBusinessId, id); | ||||
|     } | ||||
|  | ||||
|     default List<CrmBusinessProductDO> selectListByBusinessId(Long businessId) { | ||||
|         return selectList(new LambdaQueryWrapperX<CrmBusinessProductDO>().eq(CrmBusinessProductDO::getBusinessId, businessId)); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,31 @@ | ||||
| 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> { | ||||
|  | ||||
|     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.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; | ||||
| @@ -10,9 +9,6 @@ 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 | ||||
|  * | ||||
| @@ -38,9 +34,4 @@ public interface CrmProductMapper extends BaseMapperX<CrmProductDO> { | ||||
|         return selectOne(CrmProductDO::getNo, no); | ||||
|     } | ||||
|  | ||||
|     // TODO @puhui999:selectBatchIds | ||||
|     default List<CrmProductDO> selectListByIds(Collection<Long> ids) { | ||||
|         return selectList(new LambdaQueryWrapperX<CrmProductDO>().in(CrmProductDO::getId, ids)); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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.contact.CrmContactDO; | ||||
| 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 jakarta.validation.Valid; | ||||
|  | ||||
| @@ -50,6 +51,21 @@ public interface CrmBusinessService { | ||||
|      */ | ||||
|     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); | ||||
|  | ||||
|     /** | ||||
|      * 商机转移 | ||||
|      * | ||||
|      * @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.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| 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.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.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.businessproduct.CrmBusinessProductConvert; | ||||
| 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.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.CrmBusinessProductMapper; | ||||
| import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; | ||||
| 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.service.business.bo.CrmBusinessUpdateProductReqBO; | ||||
| 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.followup.bo.CrmUpdateFollowUpReqBO; | ||||
| 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.product.CrmProductService; | ||||
| import com.mzt.logapi.context.LogRecordContext; | ||||
| import com.mzt.logapi.service.impl.DiffParseFunction; | ||||
| import com.mzt.logapi.starter.annotation.LogRecord; | ||||
| @@ -35,11 +38,12 @@ import org.springframework.validation.annotation.Validated; | ||||
|  | ||||
| import java.util.Collection; | ||||
| 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.util.collection.CollectionUtils.convertSet; | ||||
| import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_CONTRACT_EXISTS; | ||||
| import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS; | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||||
| import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; | ||||
| import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; | ||||
|  | ||||
| /** | ||||
| @@ -53,9 +57,9 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { | ||||
|  | ||||
|     @Resource | ||||
|     private CrmBusinessMapper businessMapper; | ||||
|  | ||||
|     @Resource | ||||
|     private CrmBusinessProductService businessProductService; | ||||
|     private CrmBusinessProductMapper businessProductMapper; | ||||
|  | ||||
|     @Resource | ||||
|     @Lazy // 延迟加载,避免循环依赖 | ||||
|     private CrmContractService contractService; | ||||
| @@ -63,6 +67,8 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { | ||||
|     private CrmPermissionService permissionService; | ||||
|     @Resource | ||||
|     private CrmContactBusinessService contactBusinessService; | ||||
|     @Resource | ||||
|     private CrmProductService productService; | ||||
|  | ||||
|     @Override | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
| @@ -71,12 +77,15 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { | ||||
|     public Long createBusiness(CrmBusinessSaveReqVO createReqVO, Long userId) { | ||||
|         createReqVO.setId(null); | ||||
|         // 1. 插入商机 | ||||
|         CrmBusinessDO business = BeanUtils.toBean(createReqVO, CrmBusinessDO.class) | ||||
|                 .setOwnerUserId(userId); | ||||
|         CrmBusinessDO business = BeanUtils.toBean(createReqVO, CrmBusinessDO.class).setOwnerUserId(userId); | ||||
|         businessMapper.insert(business); | ||||
|         // TODO 商机待定:插入商机与产品的关联表;校验商品存在 | ||||
|         if (CollUtil.isNotEmpty(createReqVO.getProducts())) { | ||||
|             createBusinessProducts(createReqVO.getProducts(), business.getId(), false); | ||||
|         // 1.2 插入商机关联商品 | ||||
|         if (CollUtil.isNotEmpty(createReqVO.getProductItems())) { // 如果有的话 | ||||
|             List<CrmBusinessProductDO> productList = convertBusinessProductList(createReqVO.getProductItems(), business.getId()); | ||||
|             businessProductMapper.insertBatch(productList); | ||||
|             // 更新合同商品总金额 | ||||
|             businessMapper.updateById(new CrmBusinessDO().setId(business.getId()).setProductPrice( | ||||
|                     getSumValue(productList, CrmBusinessProductDO::getTotalPrice, Integer::sum))); | ||||
|         } | ||||
|         // TODO 商机待定:在联系人的详情页,如果直接【新建商机】,则需要关联下。这里要搞个 CrmContactBusinessDO 表 | ||||
|         createContactBusiness(business.getId(), createReqVO.getContactId()); | ||||
| @@ -92,13 +101,6 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { | ||||
|     } | ||||
|  | ||||
|     // TODO @lzxhqs:CrmContactBusinessService 调用这个;这样逻辑才能收敛哈; | ||||
|     /** | ||||
|      * @param businessId 商机id | ||||
|      * @param contactId  联系人id | ||||
|      * @throws | ||||
|      * @description 联系人与商机的关联 | ||||
|      * @author lzxhqs | ||||
|      */ | ||||
|     private void createContactBusiness(Long businessId, Long contactId) { | ||||
|         CrmContactBusinessDO contactBusiness = new CrmContactBusinessDO(); | ||||
|         contactBusiness.setBusinessId(businessId); | ||||
| @@ -106,37 +108,6 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { | ||||
|         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 | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
|     @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", | ||||
| @@ -146,16 +117,12 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { | ||||
|         // 1. 校验存在 | ||||
|         CrmBusinessDO oldBusiness = validateBusinessExists(updateReqVO.getId()); | ||||
|  | ||||
|         // 2. 更新商机 | ||||
|         // 2.1 更新商机 | ||||
|         CrmBusinessDO updateObj = BeanUtils.toBean(updateReqVO, CrmBusinessDO.class); | ||||
|         businessMapper.updateById(updateObj); | ||||
|         // TODO 商机待定:插入商机与产品的关联表;校验商品存在 | ||||
|         // TODO @lzxhqs:createBusinessProducts 可以抽成两个方法,一个新增;一个修改,修改需要把 businessProductService.deleteByBusinessId(updateReqVO.getId()); 一起处理进去; | ||||
|         if (CollUtil.isNotEmpty(updateReqVO.getProducts())) { | ||||
|             createBusinessProducts(updateReqVO.getProducts(), updateReqVO.getId(), true); | ||||
|         } else { | ||||
|             businessProductService.deleteBusinessProductByBusinessId(updateReqVO.getId()); | ||||
|         } | ||||
|         // 2.2 更新商机关联商品 | ||||
|         List<CrmBusinessProductDO> productList = convertBusinessProductList(updateReqVO.getProductItems(), updateObj.getId()); | ||||
|         updateBusinessProduct(productList, updateObj.getId()); | ||||
|  | ||||
|         // TODO @商机待定:如果状态发生变化,插入商机状态变更记录表 | ||||
|         // 3. 记录操作日志上下文 | ||||
| @@ -188,6 +155,43 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { | ||||
|         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> convertBusinessProductList(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 +232,14 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { | ||||
|         LogRecordContext.putVariable("business", business); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void updateBusinessProduct(CrmBusinessUpdateProductReqBO updateProductReqBO) { | ||||
|         // 更新商机关联商品 | ||||
|         List<CrmBusinessProductDO> productList = convertBusinessProductList( | ||||
|                 BeanUtils.toBean(updateProductReqBO.getProductItems(), CrmBusinessSaveReqVO.CrmBusinessProductItem.class), updateProductReqBO.getId()); | ||||
|         updateBusinessProduct(productList, updateProductReqBO.getId()); | ||||
|     } | ||||
|  | ||||
|     //======================= 查询相关 ======================= | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -0,0 +1,48 @@ | ||||
| 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; | ||||
|  | ||||
|     @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; | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageR | ||||
| 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.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.service.followup.bo.CrmUpdateFollowUpReqBO; | ||||
| import jakarta.validation.Valid; | ||||
| @@ -134,4 +135,12 @@ public interface CrmContractService { | ||||
|      */ | ||||
|     Long getContractCountByBusinessId(Long businessId); | ||||
|  | ||||
|     /** | ||||
|      * 获取合同商品列表 | ||||
|      * | ||||
|      * @param contactId 合同编号 | ||||
|      * @return 合同商品列表 | ||||
|      */ | ||||
|     List<CrmContractProductDO> getContractProductListByContractId(Long contactId); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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.task.BpmProcessInstanceApi; | ||||
| 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.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.dal.dataobject.business.CrmBusinessProductDO; | ||||
| 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.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.CrmBizTypeEnum; | ||||
| 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.service.business.CrmBusinessProductService; | ||||
| 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.followup.bo.CrmUpdateFollowUpReqBO; | ||||
| import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; | ||||
| @@ -63,12 +65,12 @@ public class CrmContractServiceImpl implements CrmContractService { | ||||
|  | ||||
|     @Resource | ||||
|     private CrmContractMapper contractMapper; | ||||
|     @Resource | ||||
|     private CrmContractProductMapper contractProductMapper; | ||||
|  | ||||
|     @Resource | ||||
|     private CrmPermissionService crmPermissionService; | ||||
|     @Resource | ||||
|     private CrmBusinessProductService businessProductService; | ||||
|     @Resource | ||||
|     private CrmProductService productService; | ||||
|     @Resource | ||||
|     private CrmCustomerService customerService; | ||||
| @@ -89,11 +91,18 @@ public class CrmContractServiceImpl implements CrmContractService { | ||||
|         // 1.1 插入合同 | ||||
|         CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null); | ||||
|         contractMapper.insert(contract); | ||||
|         // 1.2 插入商机关联商品 | ||||
|         // 1.2 插入合同关联商品 | ||||
|         if (CollUtil.isNotEmpty(createReqVO.getProductItems())) { // 如果有的话 | ||||
|             List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO, contract.getId()); | ||||
|             businessProductService.createBusinessProductBatch(businessProduct); | ||||
|             List<CrmContractProductDO> productList = convertContractProductList(createReqVO, contract.getId()); | ||||
|             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. 创建数据权限 | ||||
| @@ -137,29 +146,29 @@ public class CrmContractServiceImpl implements CrmContractService { | ||||
|         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; | ||||
|         List<CrmContractProductDO> newProductList = convertContractProductList(updateReqVO, contractId); | ||||
|         List<CrmContractProductDO> oldProductList = contractProductMapper.selectListByContractId(contractId); | ||||
|         List<List<CrmContractProductDO>> diffList = diffList(oldProductList, newProductList, (oldObj, newObj) -> { | ||||
|             boolean equal = ObjUtil.equal(oldObj.getProductId(), newObj.getProductId()); | ||||
|             if (equal) { | ||||
|                 newObj.setId(oldObj.getId()); // 设置一下老的编号更新时需要使用 | ||||
|             } | ||||
|             newObj.setId(oldObj.getId()); // 设置一下老的编号更新时需要使用 | ||||
|             return true; | ||||
|             return equal; | ||||
|         }); | ||||
|         if (CollUtil.isNotEmpty(diffList.getFirst())) { | ||||
|             businessProductService.createBusinessProductBatch(diffList.getFirst()); | ||||
|         if (CollUtil.isNotEmpty(diffList.get(0))) { | ||||
|             contractProductMapper.insertBatch(diffList.get(0)); | ||||
|         } | ||||
|         if (CollUtil.isNotEmpty(diffList.get(1))) { | ||||
|             businessProductService.updateBusinessProductBatch(diffList.get(1)); | ||||
|             contractProductMapper.updateBatch(diffList.get(1)); | ||||
|         } | ||||
|         if (CollUtil.isNotEmpty(diffList.get(2))) { | ||||
|             businessProductService.deleteBusinessProductBatch(diffList.get(2)); | ||||
|             contractProductMapper.deleteBatchIds(convertList(diffList.get(2), CrmContractProductDO::getId)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 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); | ||||
|         List<CrmProductDO> productList = productService.getProductList(productIds); | ||||
| @@ -169,8 +178,8 @@ public class CrmContractServiceImpl implements CrmContractService { | ||||
|         Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId); | ||||
|         return convertList(reqVO.getProductItems(), productItem -> { | ||||
|             CrmProductDO product = productMap.get(productItem.getId()); | ||||
|             return BeanUtils.toBean(product, CrmBusinessProductDO.class) | ||||
|                     .setId(null).setBusinessId(reqVO.getBusinessId()).setProductId(productItem.getId()).setContractId(contractId) | ||||
|             return BeanUtils.toBean(product, CrmContractProductDO.class) | ||||
|                     .setId(null).setProductId(productItem.getId()).setContractId(contractId) | ||||
|                     .setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent()) | ||||
|                     .setTotalPrice(MoneyUtils.calculator(product.getPrice(), productItem.getCount(), productItem.getDiscountPercent())); | ||||
|         }); | ||||
| @@ -248,7 +257,8 @@ public class CrmContractServiceImpl implements CrmContractService { | ||||
|  | ||||
|     @Override | ||||
|     @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) { | ||||
|         // 1. 校验合同是否在审批 | ||||
|         CrmContractDO contract = validateContractExists(id); | ||||
| @@ -263,15 +273,43 @@ public class CrmContractServiceImpl implements CrmContractService { | ||||
|         // 3. 更新合同工作流编号 | ||||
|         contractMapper.updateById(new CrmContractDO().setId(id).setProcessInstanceId(processInstanceId) | ||||
|                 .setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus())); | ||||
|  | ||||
|         // 3. 记录日志 | ||||
|         LogRecordContext.putVariable("contractName", contract.getName()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     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())) | ||||
|                 .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 | ||||
| @@ -313,5 +351,11 @@ public class CrmContractServiceImpl implements CrmContractService { | ||||
|     public Long getContractCountByBusinessId(Long businessId) { | ||||
|         return contractMapper.selectCountByBusinessId(businessId); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<CrmContractProductDO> getContractProductListByContractId(Long contactId) { | ||||
|         return contractProductMapper.selectListByContractId(contactId); | ||||
|     } | ||||
|  | ||||
|     // TODO @合同待定:需要新增一个 ContractConfigDO 表,合同配置,重点是到期提醒; | ||||
| } | ||||
|   | ||||
| @@ -1,11 +1,7 @@ | ||||
| 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.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; | ||||
| @@ -30,31 +26,7 @@ public class CrmContractResultListener implements BpmResultListenerApi { | ||||
|  | ||||
|     @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()); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -110,11 +110,10 @@ public interface CrmCustomerService { | ||||
|      * 批量导入客户 | ||||
|      * | ||||
|      * @param importCustomers 导入客户列表 | ||||
|      * @param isUpdateSupport 是否支持更新 | ||||
|      * @param userId          用户编号 | ||||
|      * @param importReqVO     请求 | ||||
|      * @return 导入结果 | ||||
|      */ | ||||
|     CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, Boolean isUpdateSupport, Long userId); | ||||
|     CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, CrmCustomerImportReqVO importReqVO); | ||||
|  | ||||
|     // ==================== 公海相关操作 ==================== | ||||
|  | ||||
|   | ||||
| @@ -108,7 +108,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { | ||||
|     /** | ||||
|      * 初始化客户的通用字段 | ||||
|      * | ||||
|      * @param customer 客户信息 | ||||
|      * @param customer    客户信息 | ||||
|      * @param ownerUserId 负责人编号 | ||||
|      * @return 客户信息 DO | ||||
|      */ | ||||
| @@ -244,8 +244,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, | ||||
|                                                       Boolean isUpdateSupport, Long userId) { | ||||
|     public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, CrmCustomerImportReqVO importReqVO) { | ||||
|         if (CollUtil.isEmpty(importCustomers)) { | ||||
|             throw exception(CUSTOMER_IMPORT_LIST_IS_EMPTY); | ||||
|         } | ||||
| @@ -264,19 +263,21 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { | ||||
|             CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName()); | ||||
|             if (existCustomer == null) { | ||||
|                 // 1.1 插入客户信息 | ||||
|                 CrmCustomerDO customer = initCustomer(importCustomer, userId); | ||||
|                 CrmCustomerDO customer = initCustomer(importCustomer, importReqVO.getOwnerUserId()); | ||||
|                 customerMapper.insert(customer); | ||||
|                 respVO.getCreateCustomerNames().add(importCustomer.getName()); | ||||
|                 // 1.2 创建数据权限 | ||||
|                 permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) | ||||
|                         .setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 | ||||
|                 if (importReqVO.getOwnerUserId() != null) { | ||||
|                     // 1.2 创建数据权限 | ||||
|                     permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) | ||||
|                             .setBizId(customer.getId()).setUserId(importReqVO.getOwnerUserId()).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 | ||||
|                 } | ||||
|                 // 1.3 记录操作日志 | ||||
|                 getSelf().importCustomerLog(customer, false); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // 情况二:如果存在,判断是否允许更新 | ||||
|             if (!isUpdateSupport) { | ||||
|             if (!importReqVO.getUpdateSupport()) { | ||||
|                 respVO.getFailureCustomerNames().put(importCustomer.getName(), | ||||
|                         StrUtil.format(CUSTOMER_NAME_EXISTS.getMsg(), importCustomer.getName())); | ||||
|                 return; | ||||
|   | ||||
| @@ -160,7 +160,7 @@ public class CrmProductServiceImpl implements CrmProductService { | ||||
|         if (CollUtil.isEmpty(ids)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|         return productMapper.selectListByIds(ids); | ||||
|         return productMapper.selectBatchIds(ids); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV