From e53a0ca8845229fb298c4d77da0f09315a6a5a4f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 23 Feb 2024 18:50:22 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20CRM=EF=BC=9Acode=20review=20?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/collection/CollectionUtils.java | 4 +- .../framework/ip/core/utils/AreaUtils.java | 32 +++++---- .../framework/ip/core/utils/IPUtils.java | 4 +- .../ip/core/utils/AreaUtilsTest.java | 2 +- .../yudao-spring-boot-starter-excel/pom.xml | 2 +- .../excel/core/convert/AreaConvert.java | 2 +- .../core/handler/SelectSheetWriteHandler.java | 56 +++++++++------- .../framework/excel/core/util/ExcelUtils.java | 10 +-- .../module/crm/enums/ErrorCodeConstants.java | 1 + ....java => CrmReceivableReturnTypeEnum.java} | 12 +--- .../admin/customer/CrmCustomerController.java | 35 +++++----- .../receivable/CrmReceivableController.java | 1 - .../CrmReceivablePlanController.java | 2 - .../vo/plan/CrmReceivablePlanRespVO.java | 59 ++++++++--------- .../vo/plan/CrmReceivablePlanSaveReqVO.java | 35 ++++------ .../vo/receivable/CrmReceivableSaveReqVO.java | 4 +- .../receivable/CrmReceivableDO.java | 4 +- .../receivable/CrmReceivablePlanDO.java | 65 +++++++++++-------- .../dal/mysql/contract/CrmContractMapper.java | 7 +- .../crm/dal/redis/RedisKeyConstants.java | 18 +++++ .../crm/dal/redis/no/CrmNoRedisDAO.java | 52 +++++++++++++++ .../contract/CrmContractServiceImpl.java | 15 +++-- .../CrmReceivablePlanServiceImpl.java | 10 +-- .../receivable/CrmReceivableServiceImpl.java | 5 +- .../module/crm/util/CrmAuditStatusUtils.java | 15 +---- .../erp/dal/redis/RedisKeyConstants.java | 2 +- .../erp/dal/redis/no/ErpNoRedisDAO.java | 2 +- .../module/system/api/dict/DictDataApi.java | 15 ++++- .../system/api/dict/DictDataApiImpl.java | 13 +--- .../controller/admin/ip/AreaController.java | 2 +- .../controller/app/ip/AppAreaController.java | 2 +- .../system/service/dict/DictDataService.java | 2 +- .../service/dict/DictDataServiceImpl.java | 4 +- 33 files changed, 277 insertions(+), 217 deletions(-) rename yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/{CrmReturnTypeEnum.java => CrmReceivableReturnTypeEnum.java} (77%) create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/RedisKeyConstants.java create mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java index 8ffd21ccc..cb4ddec34 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java @@ -257,11 +257,11 @@ public class CollectionUtils { return !CollectionUtil.isEmpty(from) ? from.get(0) : null; } - public static T findFirst(List from, Predicate predicate) { + public static T findFirst(Collection from, Predicate predicate) { return findFirst(from, predicate, Function.identity()); } - public static U findFirst(List from, Predicate predicate, Function func) { + public static U findFirst(Collection from, Predicate predicate, Function func) { if (CollUtil.isEmpty(from)) { return null; } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java b/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java index adcfc345b..99a1ac994 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java @@ -4,7 +4,6 @@ import cn.hutool.core.io.resource.ResourceUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.text.csv.CsvRow; import cn.hutool.core.text.csv.CsvUtil; -import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.ip.core.Area; import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; @@ -72,26 +71,25 @@ public class AreaUtils { * @param id 区域编号 * @return 区域 */ - public static Area getArea(Integer id) { + public static Area parseArea(Integer id) { return areas.get(id); } /** * 获得指定区域对应的编号 * - * @param path 区域编号 - * @return 编号 + * @param pathStr 区域路径,例如说:河南省/石家庄市/新华区 + * @return 区域 */ - public static Area getArea(String path) { - String[] paths = path.split("/"); + public static Area parseArea(String pathStr) { + String[] paths = pathStr.split("/"); Area area = null; - for (int i = 0; i < paths.length; i++) { - final int finalI = i; + for (String path : paths) { if (area == null) { - area = findFirst(convertList(areas.values(), a -> a), item -> ObjUtil.equal(paths[finalI], item.getName())); - continue; + area = findFirst(areas.values(), item -> item.getName().equals(path)); + } else { + area = findFirst(area.getChildren(), item -> item.getName().equals(path)); } - area = findFirst(area.getChildren(), item -> ObjUtil.equal(paths[finalI], item.getName())); } return area; } @@ -102,9 +100,9 @@ public class AreaUtils { * @param areas 地区树 * @return 所有节点的全路径名称 */ - public static List getAllAreaNodePaths(List areas) { + public static List getAreaNodePathList(List areas) { List paths = new ArrayList<>(); - areas.forEach(area -> traverse(area, "", paths)); + areas.forEach(area -> getAreaNodePathList(area, "", paths)); return paths; } @@ -113,9 +111,9 @@ public class AreaUtils { * * @param node 父节点 * @param path 全路径名称 - * @param paths 全路径名称列表 + * @param paths 全路径名称列表,省份/城市/地区 */ - private static void traverse(Area node, String path, List paths) { + private static void getAreaNodePathList(Area node, String path, List paths) { if (node == null) { return; } @@ -124,7 +122,7 @@ public class AreaUtils { paths.add(currentPath); // 递归遍历子节点 for (Area child : node.getChildren()) { - traverse(child, currentPath, paths); + getAreaNodePathList(child, currentPath, paths); } } @@ -195,7 +193,7 @@ public class AreaUtils { */ public static Integer getParentIdByType(Integer id, @NonNull AreaTypeEnum type) { for (int i = 0; i < Byte.MAX_VALUE; i++) { - Area area = AreaUtils.getArea(id); + Area area = AreaUtils.parseArea(id); if (area == null) { return null; } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtils.java b/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtils.java index f74f84864..4701168cd 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/IPUtils.java @@ -72,7 +72,7 @@ public class IPUtils { * @return 地区 */ public static Area getArea(String ip) { - return AreaUtils.getArea(getAreaId(ip)); + return AreaUtils.parseArea(getAreaId(ip)); } /** @@ -82,6 +82,6 @@ public class IPUtils { * @return 地区 */ public static Area getArea(long ip) { - return AreaUtils.getArea(getAreaId(ip)); + return AreaUtils.parseArea(getAreaId(ip)); } } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-ip/src/test/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtilsTest.java b/yudao-framework/yudao-spring-boot-starter-biz-ip/src/test/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtilsTest.java index 8f5646b33..704d4415d 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-ip/src/test/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtilsTest.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-ip/src/test/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtilsTest.java @@ -17,7 +17,7 @@ public class AreaUtilsTest { @Test public void testGetArea() { // 调用:北京 - Area area = AreaUtils.getArea(110100); + Area area = AreaUtils.parseArea(110100); // 断言 assertEquals(area.getId(), 110100); assertEquals(area.getName(), "北京市"); diff --git a/yudao-framework/yudao-spring-boot-starter-excel/pom.xml b/yudao-framework/yudao-spring-boot-starter-excel/pom.xml index b5d5c24a2..767532cac 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-excel/pom.xml @@ -49,7 +49,7 @@ cn.iocoder.boot yudao-spring-boot-starter-biz-ip - provided + true diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/AreaConvert.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/AreaConvert.java index f218c0b14..9778b17ae 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/AreaConvert.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/AreaConvert.java @@ -33,7 +33,7 @@ public class AreaConvert implements Converter { GlobalConfiguration globalConfiguration) { // 解析地区编号 String label = readCellData.getStringValue(); - Area area = AreaUtils.getArea(label); + Area area = AreaUtils.parseArea(label); if (area == null) { log.error("[convertToJavaData][label({}) 解析不掉]", label); return null; diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java index 661db5369..db3fc2776 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java @@ -19,33 +19,40 @@ import java.util.List; */ public class SelectSheetWriteHandler implements SheetWriteHandler { + private static final String DICT_SHEET_NAME = "字典sheet"; + + // TODO @puhui999:key 不使用 int 值么?感觉不是很优雅哈。 private final List>> selectMap; private static final char[] ALPHABET = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; public SelectSheetWriteHandler(List>> selectMap) { + if (CollUtil.isEmpty(selectMap)) { + this.selectMap = null; + return; + } selectMap.sort(Comparator.comparing(item -> item.getValue().size())); // 升序不然创建下拉会报错 this.selectMap = selectMap; } @Override public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { - if (selectMap == null || CollUtil.isEmpty(selectMap)) { + if (CollUtil.isEmpty(selectMap)) { return; } - // 需要设置下拉框的sheet页 - Sheet curSheet = writeSheetHolder.getSheet(); - DataValidationHelper helper = curSheet.getDataValidationHelper(); - String dictSheetName = "字典sheet"; + // 需要设置下拉框的 sheet 页 + Sheet currentSheet = writeSheetHolder.getSheet(); + DataValidationHelper helper = currentSheet.getDataValidationHelper(); Workbook workbook = writeWorkbookHolder.getWorkbook(); - // 数据字典的sheet页 - Sheet dictSheet = workbook.createSheet(dictSheetName); + + // 数据字典的 sheet 页 + Sheet dictSheet = workbook.createSheet(DICT_SHEET_NAME); for (KeyValue> keyValue : selectMap) { // 设置下拉单元格的首行、末行、首列、末列 CellRangeAddressList rangeAddressList = new CellRangeAddressList(1, 65533, keyValue.getKey(), keyValue.getKey()); int rowLen = keyValue.getValue().size(); - // 设置字典sheet页的值 每一列一个字典项 + // 设置字典 sheet 页的值 每一列一个字典项 for (int i = 0; i < rowLen; i++) { Row row = dictSheet.getRow(i); if (row == null) { @@ -53,18 +60,18 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { } row.createCell(keyValue.getKey()).setCellValue(keyValue.getValue().get(i)); } - String excelColumn = getExcelColumn(keyValue.getKey()); - // 下拉框数据来源 eg:字典sheet!$B1:$B2 - String refers = dictSheetName + "!$" + excelColumn + "$1:$" + excelColumn + "$" + rowLen; - // 创建可被其他单元格引用的名称 + + // TODO @puhui999:下面 1. 2.1 2.2 2.3 我是按照已经理解的,调整了下格式;这样可读性更好;在 52 到 62 行,你可以看看,是不是也弄下序号; + // 1. 创建可被其他单元格引用的名称 Name name = workbook.createName(); - // 设置名称的名字 - name.setNameName("dict" + keyValue.getKey()); - // 设置公式 - name.setRefersToFormula(refers); - // 设置引用约束 - DataValidationConstraint constraint = helper.createFormulaListConstraint("dict" + keyValue.getKey()); - // 设置约束 + // TODO @puhui999:下面的 excelColumn 和 refers 两行,是不是可以封装成一个方法,替代 getExcelColumn; + String excelColumn = getExcelColumn(keyValue.getKey()); + String refers = DICT_SHEET_NAME + "!$" + excelColumn + "$1:$" + excelColumn + "$" + rowLen; // 下拉框数据来源 eg:字典sheet!$B1:$B2 + name.setNameName("dict" + keyValue.getKey()); // 设置名称的名字 + name.setRefersToFormula(refers); // 设置公式 + + // 2.1 设置约束 + DataValidationConstraint constraint = helper.createFormulaListConstraint("dict" + keyValue.getKey()); // 设置引用约束 DataValidation validation = helper.createValidation(constraint, rangeAddressList); if (validation instanceof HSSFDataValidation) { validation.setSuppressDropDownArrow(false); @@ -72,10 +79,10 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { validation.setSuppressDropDownArrow(true); validation.setShowErrorBox(true); } - // 阻止输入非下拉框的值 + // 2.2 阻止输入非下拉框的值 validation.setErrorStyle(DataValidation.ErrorStyle.STOP); validation.createErrorBox("提示", "此值不存在于下拉选择中!"); - // 添加下拉框约束 + // 2.3 添加下拉框约束 writeSheetHolder.getSheet().addValidationData(validation); } } @@ -86,8 +93,9 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { * @param num 数字 * @return 字母 */ + // TODO @puhui999:这个是必须字母列哇?还是数字其实也可以哈?主要想看看,怎么能把这个逻辑,进一步简化 private String getExcelColumn(int num) { - String column = ""; + String column; int len = ALPHABET.length - 1; int first = num / len; int second = num % len; @@ -96,9 +104,9 @@ public class SelectSheetWriteHandler implements SheetWriteHandler { } else { column = ALPHABET[first - 1] + ""; if (second == 0) { - column = column + ALPHABET[len] + ""; + column = column + ALPHABET[len]; } else { - column = column + ALPHABET[second - 1] + ""; + column = column + ALPHABET[second - 1]; } } return column; diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java index 83877ece8..ee4ba25c7 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java @@ -33,15 +33,7 @@ public class ExcelUtils { */ public static void write(HttpServletResponse response, String filename, String sheetName, Class head, List data) throws IOException { - // 输出 Excel - EasyExcel.write(response.getOutputStream(), head) - .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 - .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 - .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 - .sheet(sheetName).doWrite(data); - // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 - response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name())); - response.setContentType("application/vnd.ms-excel;charset=UTF-8"); + write(response, filename, sheetName, head, data, null); } /** diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java index 5640d16a2..b9c3898ce 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java @@ -14,6 +14,7 @@ public interface ErrorCodeConstants { ErrorCode CONTRACT_UPDATE_FAIL_NOT_DRAFT = new ErrorCode(1_020_000_001, "合同更新失败,原因:合同不是草稿状态"); ErrorCode CONTRACT_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_000_002, "合同提交审核失败,原因:合同没处在未提交状态"); ErrorCode CONTRACT_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_000_003, "更新合同审核状态失败,原因:合同不是审核中状态"); + ErrorCode CONTRACT_NO_EXISTS = new ErrorCode(1_020_000_004, "生成合同序列号重复,请重试"); // ========== 线索管理 1-020-001-000 ========== ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在"); diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReturnTypeEnum.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReceivableReturnTypeEnum.java similarity index 77% rename from yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReturnTypeEnum.java rename to yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReceivableReturnTypeEnum.java index 8aacadce3..3c01fe95c 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReturnTypeEnum.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReceivableReturnTypeEnum.java @@ -13,26 +13,18 @@ import java.util.Arrays; */ @Getter @AllArgsConstructor -public enum CrmReturnTypeEnum implements IntArrayValuable { +public enum CrmReceivableReturnTypeEnum implements IntArrayValuable { - // 支票 CHECK(1, "支票"), - // 现金 CASH(2, "现金"), - // 邮政汇款 POSTAL_REMITTANCE(3, "邮政汇款"), - // 电汇 TELEGRAPHIC_TRANSFER(4, "电汇"), - // 网上转账 ONLINE_TRANSFER(5, "网上转账"), - // 支付宝 ALIPAY(6, "支付宝"), - // 微信支付 WECHAT_PAY(7, "微信支付"), - // 其他 OTHER(8, "其它"); - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmReturnTypeEnum::getType).toArray(); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmReceivableReturnTypeEnum::getType).toArray(); /** * 类型 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java index df6e0e625..54327c24c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java @@ -268,6 +268,24 @@ public class CrmCustomerController { ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list, builderSelectMap()); } + private List>> builderSelectMap() { + List>> selectMap = new ArrayList<>(); + // 获取地区下拉数据 + // TODO @puhui999:嘿嘿,这里改成省份、城市、区域,三个选项,难度大么? + Area area = AreaUtils.parseArea(Area.ID_CHINA); + selectMap.add(new KeyValue<>(6, AreaUtils.getAreaNodePathList(area.getChildren()))); + // 获取客户所属行业 + List customerIndustries = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_INDUSTRY); + selectMap.add(new KeyValue<>(8, customerIndustries)); + // 获取客户等级 + List customerLevels = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_LEVEL); + selectMap.add(new KeyValue<>(9, customerLevels)); + // 获取客户来源 + List customerSources = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_SOURCE); + selectMap.add(new KeyValue<>(10, customerSources)); + return selectMap; + } + @PostMapping("/import") @Operation(summary = "导入客户") @PreAuthorize("@ss.hasPermission('system:customer:import')") @@ -321,21 +339,4 @@ public class CrmCustomerController { return success(true); } - private List>> builderSelectMap() { - List>> selectMap = new ArrayList<>(); - // 获取地区下拉数据 - Area area = AreaUtils.getArea(Area.ID_CHINA); - selectMap.add(new KeyValue<>(6, AreaUtils.getAllAreaNodePaths(area.getChildren()))); - // 获取客户所属行业 - List customerIndustries = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_INDUSTRY); - selectMap.add(new KeyValue<>(8, customerIndustries)); - // 获取客户等级 - List customerLevels = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_LEVEL); - selectMap.add(new KeyValue<>(9, customerLevels)); - // 获取客户来源 - List customerSources = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_SOURCE); - selectMap.add(new KeyValue<>(10, customerSources)); - return selectMap; - } - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java index 5bbaefb5b..fcbbfed72 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java @@ -107,7 +107,6 @@ public class CrmReceivableController { return success(buildReceivableDetailPage(pageResult)); } - // TODO 芋艿:后面在优化导出 @GetMapping("/export-excel") @Operation(summary = "导出回款 Excel") @PreAuthorize("@ss.hasPermission('crm:receivable:export')") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java index 2500c6f15..cbb9d51e4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java @@ -28,7 +28,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.*; @@ -56,7 +55,6 @@ public class CrmReceivablePlanController { @Resource private CrmReceivableService receivableService; @Resource - @Lazy private CrmContractService contractService; @Resource private CrmCustomerService customerService; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java index 9e6d1a03f..9b503db40 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java @@ -6,6 +6,7 @@ import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; +// TODO @puhui999:缺导出 @Schema(description = "管理后台 - CRM 回款计划 Response VO") @Data public class CrmReceivablePlanRespVO { @@ -13,17 +14,38 @@ public class CrmReceivablePlanRespVO { @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Long id; - @Schema(description = "回款编号", example = "19852") - private Long receivableId; - @Schema(description = "期数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Integer period; + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Long customerId; + @Schema(description = "客户名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") + private String customerName; + + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Long contractId; + @Schema(description = "合同编号", example = "Q110") + private String contractNo; + + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Long ownerUserId; + @Schema(description = "负责人", example = "test") + private String ownerUserName; + + @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") + private LocalDateTime returnTime; + + @Schema(description = "回款方式", example = "1") + private Integer returnType; // 来自 Receivable 的 returnType 字段 + @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") private BigDecimal price; - @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") - private LocalDateTime returnTime; + @Schema(description = "回款编号", example = "19852") + private Long receivableId; + + @Schema(description = "完成状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean finishStatus; @Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer remindDays; @@ -31,43 +53,16 @@ public class CrmReceivablePlanRespVO { @Schema(description = "提醒日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") private LocalDateTime remindTime; - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Long customerId; - - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Long contractId; - - @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Long ownerUserId; - - @Schema(description = "显示顺序") - private Integer sort; - @Schema(description = "备注", example = "备注") private String remark; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; - @Schema(description = "客户名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "test") - private String customerName; - - @Schema(description = "合同编号", example = "Q110") - private String contractNo; - - @Schema(description = "负责人", example = "test") - private String ownerUserName; - @Schema(description = "创建人", example = "25682") private String creator; @Schema(description = "创建人名字", example = "test") private String creatorName; - @Schema(description = "完成状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Boolean finishStatus; - - @Schema(description = "回款方式", example = "1") - private Integer returnType; // 来自 Receivable 的 returnType 字段 - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanSaveReqVO.java index 235daf328..b2bb41242 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanSaveReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanSaveReqVO.java @@ -14,26 +14,6 @@ public class CrmReceivablePlanSaveReqVO { @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Long id; - @Schema(description = "期数", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @NotNull(message = "期数不能为空") - private Integer period; - - @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") - @NotNull(message = "计划回款金额不能为空") - private BigDecimal price; - - @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") - @NotNull(message = "计划回款日期不能为空") - private LocalDateTime returnTime; - - @Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "提前几天提醒不能为空") - private Integer remindDays; - - @Schema(description = "提醒日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") - @NotNull(message = "提醒日期不能为空") - private LocalDateTime remindTime; - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @NotNull(message = "客户编号不能为空") private Long customerId; @@ -46,8 +26,19 @@ public class CrmReceivablePlanSaveReqVO { @NotNull(message = "负责人编号不能为空") private Long ownerUserId; - @Schema(description = "显示顺序") - private Integer sort; + @Schema(description = "计划回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") + @NotNull(message = "计划回款日期不能为空") + private LocalDateTime returnTime; + + @Schema(description = "回款方式", example = "1") + private Integer returnType; + + @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") + @NotNull(message = "计划回款金额不能为空") + private BigDecimal price; + + @Schema(description = "提前几天提醒", example = "1") + private Integer remindDays; @Schema(description = "备注", example = "备注") private String remark; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java index 5340b4319..dfc0b1553 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.crm.enums.receivable.CrmReturnTypeEnum; +import cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableReturnTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -23,7 +23,7 @@ public class CrmReceivableSaveReqVO { private Long planId; // 不是通过回款计划创建的回款没有回款计划编号 @Schema(description = "回款方式", example = "2") - @InEnum(CrmReturnTypeEnum.class) + @InEnum(CrmReceivableReturnTypeEnum.class) private Integer returnType; @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java index 6c1610935..3c8d71cd4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java @@ -4,7 +4,7 @@ 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.customer.CrmCustomerDO; import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; -import cn.iocoder.yudao.module.crm.enums.receivable.CrmReturnTypeEnum; +import cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableReturnTypeEnum; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; @@ -60,7 +60,7 @@ public class CrmReceivableDO extends BaseDO { */ private LocalDateTime returnTime; /** - * 回款方式,关联枚举{@link CrmReturnTypeEnum} + * 回款方式,关联枚举{@link CrmReceivableReturnTypeEnum} */ private Integer returnType; /** diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivablePlanDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivablePlanDO.java index 80a04ece7..d0e6a3e66 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivablePlanDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivablePlanDO.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.crm.dal.dataobject.receivable; 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.customer.CrmCustomerDO; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import cn.iocoder.yudao.module.crm.enums.receivable.CrmReceivableReturnTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -13,7 +13,7 @@ import java.math.BigDecimal; import java.time.LocalDateTime; /** - * 回款计划 DO + * CRM 回款计划 DO * * @author 芋道源码 */ @@ -37,17 +37,49 @@ public class CrmReceivablePlanDO extends BaseDO { */ private Integer period; /** - * 回款编号,关联 {@link CrmReceivableDO#getId()} + * 客户编号 + * + * 关联 {@link CrmCustomerDO#getId()} */ - private Long receivableId; + private Long customerId; /** - * 计划回款金额,单位:元 + * 合同编号 + * + * 关联 {@link CrmContractDO#getId()} */ - private BigDecimal price; + private Long contractId; + + /** + * 负责人编号 + * + * 关联 AdminUserDO 的 id 字段 + */ + private Long ownerUserId; + /** * 计划回款日期 */ private LocalDateTime returnTime; + /** + * 回款类型 + * + * 枚举 {@link CrmReceivableReturnTypeEnum} + */ + private Integer returnType; + /** + * 计划回款金额,单位:元 + */ + private BigDecimal price; + + /** + * 回款编号,关联 {@link CrmReceivableDO#getId()} + */ + private Long receivableId; + /** + * 完成状态 + */ + private Boolean finishStatus; + /** * 提前几天提醒 */ @@ -56,30 +88,9 @@ public class CrmReceivablePlanDO extends BaseDO { * 提醒日期 */ private LocalDateTime remindTime; - /** - * 客户编号,关联 {@link CrmCustomerDO#getId()} - */ - private Long customerId; - /** - * 合同编号,关联 {@link CrmContractDO#getId()} - */ - private Long contractId; - /** - * 负责人编号,关联 {@link AdminUserRespDTO#getId()} - */ - private Long ownerUserId; - /** - * 显示顺序 - */ - private Integer sort; /** * 备注 */ private String remark; - /** - * 完成状态 - */ - private Boolean finishStatus; - } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java index d1556be3e..f1f3128c9 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java @@ -11,7 +11,6 @@ import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; import java.time.LocalDateTime; @@ -26,10 +25,8 @@ import java.util.List; @Mapper public interface CrmContractMapper extends BaseMapperX { - default int updateOwnerUserIdById(Long id, Long ownerUserId) { - return update(new LambdaUpdateWrapper() - .eq(CrmContractDO::getId, id) - .set(CrmContractDO::getOwnerUserId, ownerUserId)); + default CrmContractDO selectByNo(String no) { + return selectOne(CrmContractDO::getNo, no); } default PageResult selectPageByCustomerId(CrmContractPageReqVO pageReqVO) { diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/RedisKeyConstants.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/RedisKeyConstants.java new file mode 100644 index 000000000..2932c1db1 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/RedisKeyConstants.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.crm.dal.redis; + +/** + * CRM Redis Key 枚举类 + * + * @author 芋道源码 + */ +public interface RedisKeyConstants { + + /** + * 序号的缓存 + * + * KEY 格式:trade_no:{prefix} + * VALUE 数据格式:编号自增 + */ + String NO = "crm:seq_no:"; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java new file mode 100644 index 000000000..7b5913905 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.crm.dal.redis.no; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; +import cn.iocoder.yudao.module.crm.dal.redis.RedisKeyConstants; +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import java.time.Duration; +import java.time.LocalDateTime; + + +/** + * Crm 订单序号的 Redis DAO + * + * @author HUIHUI + */ +@Repository +public class CrmNoRedisDAO { + + /** + * 合同 {@link cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO} + */ + public static final String CONTRACT_NO_PREFIX = "HT"; + + /** + * 还款 {@link cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO} + */ + public static final String RECEIVABLE_PREFIX = "HK"; + + @Resource + private StringRedisTemplate stringRedisTemplate; + + /** + * 生成序号,使用当前日期,格式为 {PREFIX} + yyyyMMdd + 6 位自增 + * 例如说:QTRK 202109 000001 (没有中间空格) + * + * @param prefix 前缀 + * @return 序号 + */ + public String generate(String prefix) { + // 递增序号 + String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN); + String key = RedisKeyConstants.NO + noPrefix; + Long no = stringRedisTemplate.opsForValue().increment(key); + // 设置过期时间 + stringRedisTemplate.expire(key, Duration.ofDays(1L)); + return noPrefix + String.format("%06d", no); + } + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java index dcb892349..9f5f603d2 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java @@ -17,6 +17,7 @@ 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.mysql.contract.CrmContractMapper; import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractProductMapper; +import cn.iocoder.yudao.module.crm.dal.redis.no.CrmNoRedisDAO; 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; @@ -69,6 +70,9 @@ public class CrmContractServiceImpl implements CrmContractService { @Resource private CrmContractProductMapper contractProductMapper; + @Resource + private CrmNoRedisDAO noRedisDAO; + @Resource private CrmPermissionService crmPermissionService; @Resource @@ -94,11 +98,14 @@ public class CrmContractServiceImpl implements CrmContractService { List contractProducts = validateContractProducts(createReqVO.getProducts()); // 1.2 校验关联字段 validateRelationDataExists(createReqVO); - // TODO 芋艿:生成 no + // 1.3 生成序号 + String no = noRedisDAO.generate(CrmNoRedisDAO.CONTRACT_NO_PREFIX); + if (contractMapper.selectByNo(no) != null) { + throw exception(CONTRACT_NO_EXISTS); + } // 2.1 插入合同 - CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class); - contract.setNo(System.currentTimeMillis() + ""); // TODO + CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setNo(no); calculateTotalPrice(contract, contractProducts); contractMapper.insert(contract); // 2.2 插入合同关联商品 @@ -247,7 +254,7 @@ public class CrmContractServiceImpl implements CrmContractService { crmPermissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CONTRACT.getType(), reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); // 2.2 设置负责人 - contractMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); + contractMapper.updateById(new CrmContractDO().setId(reqVO.getId()).setOwnerUserId(reqVO.getNewOwnerUserId())); // 3. 记录转移日志 LogRecordContext.putVariable("contract", contract); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java index db8ea9e0c..55c403404 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java @@ -23,7 +23,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.hibernate.validator.internal.util.stereotypes.Lazy; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -57,6 +57,7 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { private CrmCustomerService customerService; @Resource private CrmPermissionService permissionService; + @Resource private AdminUserApi adminUserApi; @@ -72,15 +73,16 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { int period = (int) (count + 1); createReqVO.setPeriod(createReqVO.getPeriod() != period ? period : createReqVO.getPeriod()); // 如果期数不对则纠正 - // 2.1 插入 + // 2. 插入还款计划 CrmReceivablePlanDO receivablePlan = BeanUtils.toBean(createReqVO, CrmReceivablePlanDO.class).setId(null).setFinishStatus(false); receivablePlanMapper.insert(receivablePlan); - // 2.2 创建数据权限 + + // 3. 创建数据权限 permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(createReqVO.getOwnerUserId()) .setBizType(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType()).setBizId(receivablePlan.getId()) .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); - // 3. 记录操作日志上下文 + // 4. 记录操作日志上下文 LogRecordContext.putVariable("receivablePlan", receivablePlan); return receivablePlan.getId(); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java index d11bb939d..921b714d8 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java @@ -31,6 +31,7 @@ import com.mzt.logapi.service.impl.DiffParseFunction; import com.mzt.logapi.starter.annotation.LogRecord; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -66,10 +67,12 @@ public class CrmReceivableServiceImpl implements CrmReceivableService { private CrmContractService contractService; @Resource private CrmCustomerService customerService; - @Resource +// @Resource + @Lazy // 延迟加载,避免循环依赖 private CrmReceivablePlanService receivablePlanService; @Resource private CrmPermissionService permissionService; + @Resource private AdminUserApi adminUserApi; @Resource diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java index 0169b0d87..665e98fbe 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.crm.util; import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; @@ -18,23 +17,11 @@ public class CrmAuditStatusUtils { * @param bpmResult BPM 审批结果 */ public static Integer convertBpmResultToAuditStatus(Integer bpmResult) { - Assert.isTrue(isEndResult(bpmResult), "BPM 审批结果({}) 转换失败, 流程状态不是最终结果", bpmResult); Integer auditStatus = BpmProcessInstanceResultEnum.APPROVE.getResult().equals(bpmResult) ? CrmAuditStatusEnum.APPROVE.getStatus() : BpmProcessInstanceResultEnum.REJECT.getResult().equals(bpmResult) ? CrmAuditStatusEnum.REJECT.getStatus() - : BpmProcessInstanceResultEnum.CANCEL.getResult(); + : BpmProcessInstanceResultEnum.CANCEL.getResult().equals(bpmResult) ? BpmProcessInstanceResultEnum.CANCEL.getResult() : null; Assert.notNull(auditStatus, "BPM 审批结果({}) 转换失败", bpmResult); return auditStatus; } - /** - * 判断该结果是否处于 End 最终结果 - * - * @param bpmResult BPM 审批结果 - * @return 是否 - */ - public static boolean isEndResult(Integer bpmResult) { - return ObjectUtils.equalsAny(bpmResult, BpmProcessInstanceResultEnum.APPROVE.getResult(), - BpmProcessInstanceResultEnum.REJECT.getResult(), BpmProcessInstanceResultEnum.CANCEL.getResult()); - } - } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java index f0ba46807..daa5c1614 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java @@ -13,6 +13,6 @@ public interface RedisKeyConstants { * KEY 格式:trade_no:{prefix} * VALUE 数据格式:编号自增 */ - String NO = "seq_no:"; + String NO = "erp:seq_no:"; } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java index 98fb8e8ff..b6777d207 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java @@ -12,7 +12,7 @@ import java.time.LocalDateTime; /** - * 订单序号的 Redis DAO + * Erp 订单序号的 Redis DAO * * @author HUIHUI */ diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java index bfc2a1590..5c47f4de3 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java @@ -5,6 +5,8 @@ import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; import java.util.Collection; import java.util.List; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + /** * 字典数据 API 接口 * @@ -40,12 +42,23 @@ public interface DictDataApi { */ DictDataRespDTO parseDictData(String type, String label); + /** + * 获得指定字典类型的字典数据列表 + * + * @param dictType 字典类型 + * @return 字典数据列表 + */ + List getDictDataList(String dictType); + /** * 获得字典数据标签列表 * * @param dictType 字典类型 * @return 字典数据标签列表 */ - List getDictDataLabelList(String dictType); + default List getDictDataLabelList(String dictType) { + List list = getDictDataList(dictType); + return convertList(list, DictDataRespDTO::getLabel); + } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApiImpl.java index f3ddb6927..450512784 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApiImpl.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.system.api.dict; -import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; @@ -9,11 +8,8 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import java.util.Collection; -import java.util.Collections; import java.util.List; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; - /** * 字典数据 API 实现类 * @@ -43,12 +39,9 @@ public class DictDataApiImpl implements DictDataApi { } @Override - public List getDictDataLabelList(String dictType) { - List dictDataList = dictDataService.getDictDataListByDictType(dictType); - if (CollUtil.isEmpty(dictDataList)) { - return Collections.emptyList(); - } - return convertList(dictDataList, DictDataDO::getLabel); + public List getDictDataList(String dictType) { + List list = dictDataService.getDictDataListByDictType(dictType); + return BeanUtils.toBean(list, DictDataRespDTO.class); } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.java index b2f95d69f..b39e0a06d 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.java @@ -29,7 +29,7 @@ public class AreaController { @GetMapping("/tree") @Operation(summary = "获得地区树") public CommonResult> getAreaTree() { - Area area = AreaUtils.getArea(Area.ID_CHINA); + Area area = AreaUtils.parseArea(Area.ID_CHINA); Assert.notNull(area, "获取不到中国"); return success(BeanUtils.toBean(area.getChildren(), AreaNodeRespVO.class)); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/AppAreaController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/AppAreaController.java index 54b0e87db..759b72c72 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/AppAreaController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/AppAreaController.java @@ -26,7 +26,7 @@ public class AppAreaController { @GetMapping("/tree") @Operation(summary = "获得地区树") public CommonResult> getAreaTree() { - Area area = AreaUtils.getArea(Area.ID_CHINA); + Area area = AreaUtils.parseArea(Area.ID_CHINA); Assert.notNull(area, "获取不到中国"); return success(BeanUtils.toBean(area.getChildren(), AppAreaNodeRespVO.class)); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataService.java index ce75c9afe..fc2498f1b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataService.java @@ -100,7 +100,7 @@ public interface DictDataService { DictDataDO parseDictData(String dictType, String label); /** - * 获得字典数据列表 + * 获得指定数据类型的字典数据列表 * * @param dictType 字典类型 * @return 字典数据列表 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java index 7982e2302..b15fd506a 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java @@ -171,7 +171,9 @@ public class DictDataServiceImpl implements DictDataService { @Override public List getDictDataListByDictType(String dictType) { - return dictDataMapper.selectList(DictDataDO::getDictType, dictType); + List list = dictDataMapper.selectList(DictDataDO::getDictType, dictType); + list.sort(Comparator.comparing(DictDataDO::getSort)); + return list; } }