From 3ad98f271b3496d3e485ba7006d4e23846884886 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 28 Feb 2024 22:40:54 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=202.0.1=20=E7=89=88=E6=9C=AC=E5=8F=91?= =?UTF-8?q?=E5=B8=83=E5=87=86=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-framework/pom.xml | 1 - .../yudao-spring-boot-starter-excel/pom.xml | 7 - .../core/util/DictFrameworkUtilsTest.java | 51 -- yudao-module-bpm/pom.xml | 28 - .../event/BpmProcessInstanceResultEvent.java | 43 -- ...BpmProcessInstanceResultEventListener.java | 34 - yudao-module-bpm/yudao-module-bpm-biz/pom.xml | 74 --- .../task/BpmProcessInstanceConvert.java | 115 ---- ...pmProcessInstanceResultEventPublisher.java | 25 - .../oa/listener/BpmOALeaveResultListener.java | 32 - .../pom.xml | 37 -- .../config/YudaoFlowableConfiguration.java | 46 -- .../core/context/FlowableContextHolder.java | 40 -- .../core/enums/BpmnModelConstants.java | 22 - .../framework/flowable/core/package-info.java | 1 - .../flowable/core/util/BpmnModelUtils.java | 309 --------- .../flowable/core/util/FlowableUtils.java | 32 - .../flowable/core/web/FlowableWebFilter.java | 35 - .../framework/flowable/package-info.java | 1 - ...ot.autoconfigure.AutoConfiguration.imports | 1 - yudao-module-crm/pom.xml | 24 - .../module/crm/enums/DictTypeConstants.java | 19 - .../module/crm/enums/ErrorCodeConstants.java | 103 --- .../module/crm/enums/LogRecordConstants.java | 163 ----- .../business/CrmBusinessEndStatusEnum.java | 45 -- .../crm/enums/common/CrmBizTypeEnum.java | 52 -- .../permission/CrmPermissionLevelEnum.java | 53 -- .../CrmReceivableReturnTypeEnum.java | 43 -- yudao-module-crm/yudao-module-crm-biz/pom.xml | 79 --- .../admin/business/CrmBusinessController.java | 222 ------- .../business/CrmBusinessStatusController.java | 126 ---- .../vo/business/CrmBusinessRespVO.java | 144 ---- .../vo/business/CrmBusinessSaveReqVO.java | 95 --- .../CrmBusinessUpdateStatusReqVO.java | 31 - .../vo/status/CrmBusinessStatusRespVO.java | 51 -- .../vo/status/CrmBusinessStatusSaveReqVO.java | 50 -- .../admin/clue/CrmClueController.java | 173 ----- .../admin/clue/vo/CrmCluePageReqVO.java | 48 -- .../admin/clue/vo/CrmClueRespVO.java | 129 ---- .../admin/clue/vo/CrmClueSaveReqVO.java | 109 --- .../admin/contact/CrmContactController.java | 227 ------- .../contact/vo/CrmContactBusiness2ReqVO.java | 22 - .../contact/vo/CrmContactBusinessReqVO.java | 22 - .../admin/contact/vo/CrmContactPageReqVO.java | 45 -- .../admin/contact/vo/CrmContactRespVO.java | 122 ---- .../admin/contact/vo/CrmContactSaveReqVO.java | 98 --- .../contract/CrmContractConfigController.java | 45 -- .../admin/contract/CrmContractController.java | 256 ------- .../vo/config/CrmContractConfigRespVO.java | 16 - .../vo/config/CrmContractConfigSaveReqVO.java | 33 - .../vo/contract/CrmContractPageReqVO.java | 50 -- .../vo/contract/CrmContractRespVO.java | 162 ----- .../vo/contract/CrmContractSaveReqVO.java | 111 ---- .../vo/contract/CrmContractTransferReqVO.java | 26 - .../admin/customer/CrmCustomerController.java | 342 ---------- .../CrmCustomerLimitConfigController.java | 104 --- .../customer/CrmCustomerDistributeReqVO.java | 22 - .../vo/customer/CrmCustomerImportExcelVO.java | 64 -- .../vo/customer/CrmCustomerImportReqVO.java | 26 - .../vo/customer/CrmCustomerImportRespVO.java | 24 - .../vo/customer/CrmCustomerLockReqVO.java | 16 - .../vo/customer/CrmCustomerPageReqVO.java | 58 -- .../vo/customer/CrmCustomerRespVO.java | 130 ---- .../vo/customer/CrmCustomerSaveReqVO.java | 99 --- .../vo/customer/CrmCustomerTransferReqVO.java | 32 - .../followup/CrmFollowUpRecordController.java | 105 --- .../followup/vo/CrmFollowUpRecordRespVO.java | 64 -- .../operatelog/CrmOperateLogController.java | 64 -- .../operatelog/vo/CrmOperateLogRespVO.java | 44 -- .../permission/CrmPermissionController.java | 135 ---- .../admin/product/CrmProductController.java | 145 ---- .../product/vo/product/CrmProductRespVO.java | 75 --- .../vo/product/CrmProductSaveReqVO.java | 56 -- .../receivable/CrmReceivableController.java | 182 ----- .../CrmReceivablePlanController.java | 190 ------ .../vo/plan/CrmReceivablePlanPageReqVO.java | 46 -- .../vo/plan/CrmReceivablePlanRespVO.java | 75 --- .../vo/plan/CrmReceivablePlanSaveReqVO.java | 45 -- .../vo/receivable/CrmReceivablePageReqVO.java | 38 -- .../vo/receivable/CrmReceivableRespVO.java | 75 --- .../vo/receivable/CrmReceivableSaveReqVO.java | 58 -- .../CrmStatisticsRankController.http | 9 - .../CrmStatisticsRankController.java | 87 --- .../vo/CrmStatisticsRanKRespVO.java | 29 - .../statistics/vo/CrmStatisticsRankReqVO.java | 35 - .../dataobject/business/CrmBusinessDO.java | 111 ---- .../business/CrmBusinessProductDO.java | 67 -- .../business/CrmBusinessStatusDO.java | 48 -- .../business/CrmBusinessStatusTypeDO.java | 46 -- .../crm/dal/dataobject/clue/CrmClueDO.java | 128 ---- .../dal/dataobject/contact/CrmContactDO.java | 118 ---- .../contract/CrmContractConfigDO.java | 33 - .../dataobject/contract/CrmContractDO.java | 123 ---- .../contract/CrmContractProductDO.java | 63 -- .../dataobject/customer/CrmCustomerDO.java | 127 ---- .../dal/dataobject/product/CrmProductDO.java | 74 --- .../receivable/CrmReceivableDO.java | 94 --- .../receivable/CrmReceivablePlanDO.java | 92 --- .../dal/mysql/business/CrmBusinessMapper.java | 60 -- .../business/CrmBusinessProductMapper.java | 22 - .../business/CrmBusinessStatusMapper.java | 30 - .../business/CrmBusinessStatusTypeMapper.java | 27 - .../crm/dal/mysql/clue/CrmClueMapper.java | 63 -- .../contact/CrmContactBusinessMapper.java | 44 -- .../dal/mysql/contact/CrmContactMapper.java | 76 --- .../contract/CrmContractConfigMapper.java | 20 - .../dal/mysql/contract/CrmContractMapper.java | 120 ---- .../contract/CrmContractProductMapper.java | 23 - .../dal/mysql/customer/CrmCustomerMapper.java | 189 ------ .../dal/mysql/product/CrmProductMapper.java | 39 -- .../mysql/receivable/CrmReceivableMapper.java | 102 --- .../receivable/CrmReceivablePlanMapper.java | 99 --- .../CrmStatisticsRankingMapper.java | 81 --- .../crm/dal/redis/RedisKeyConstants.java | 18 - .../crm/dal/redis/no/CrmNoRedisDAO.java | 52 -- .../CrmCustomerIndustryParseFunction.java | 40 -- .../core/CrmCustomerLevelParseFunction.java | 40 -- .../core/CrmCustomerSourceParseFunction.java | 40 -- .../core/CrmProductStatusParseFunction.java | 39 -- .../core/CrmProductUnitParseFunction.java | 39 -- .../core/CrmReceivablePlanParseFunction.java | 45 -- .../CrmReceivableReturnTypeParseFunction.java | 40 -- .../core/SysBooleanParseFunction.java | 39 -- .../operatelog/core/SysSexParseFunction.java | 39 -- .../core/aop/CrmPermissionAspect.java | 130 ---- .../web/config/CrmWebConfiguration.java | 24 - .../crm/framework/web/package-info.java | 4 - .../yudao/module/crm/job/package-info.java | 4 - .../service/business/CrmBusinessService.java | 188 ------ .../business/CrmBusinessServiceImpl.java | 373 ----------- .../business/CrmBusinessStatusService.java | 135 ---- .../CrmBusinessStatusServiceImpl.java | 195 ------ .../crm/service/clue/CrmClueService.java | 101 --- .../crm/service/clue/CrmClueServiceImpl.java | 241 ------- .../contact/CrmContactBusinessService.java | 68 -- .../CrmContactBusinessServiceImpl.java | 139 ---- .../service/contact/CrmContactService.java | 163 ----- .../contact/CrmContactServiceImpl.java | 301 --------- .../contract/CrmContractConfigService.java | 29 - .../CrmContractConfigServiceImpl.java | 56 -- .../service/contract/CrmContractService.java | 196 ------ .../contract/CrmContractServiceImpl.java | 399 ----------- .../listener/CrmContractResultListener.java | 32 - .../CrmCustomerPoolConfigServiceImpl.java | 56 -- .../service/customer/CrmCustomerService.java | 198 ------ .../customer/CrmCustomerServiceImpl.java | 622 ------------------ .../customer/bo/CrmCustomerCreateReqBO.java | 121 ---- .../CrmFollowUpRecordServiceImpl.java | 149 ----- .../permission/CrmPermissionServiceImpl.java | 223 ------- .../bo/CrmPermissionTransferReqBO.java | 53 -- .../product/CrmProductCategoryService.java | 77 --- .../service/product/CrmProductService.java | 102 --- .../product/CrmProductServiceImpl.java | 183 ------ .../receivable/CrmReceivablePlanService.java | 95 --- .../CrmReceivablePlanServiceImpl.java | 191 ------ .../receivable/CrmReceivableService.java | 125 ---- .../receivable/CrmReceivableServiceImpl.java | 292 -------- .../listener/CrmReceivableResultListener.java | 32 - .../CrmStatisticsRankingService.java | 80 --- .../CrmStatisticsRankingServiceImpl.java | 134 ---- .../module/crm/util/CrmAuditStatusUtils.java | 27 - .../module/crm/util/CrmPermissionUtils.java | 106 --- .../mapper/bi/CrmBiRankingMapper.xml | 126 ---- yudao-module-erp/yudao-module-erp-biz/pom.xml | 73 -- .../ErpPurchaseStatisticsController.java | 69 -- .../ErpSaleStatisticsController.http | 11 - .../ErpSaleStatisticsController.java | 69 -- .../vo/purchase/ErpPurchaseSummaryRespVO.java | 24 - .../ErpPurchaseTimeSummaryRespVO.java | 18 - .../vo/sale/ErpSaleSummaryRespVO.java | 24 - .../vo/sale/ErpSaleTimeSummaryRespVO.java | 18 - .../admin/stock/ErpWarehouseController.java | 116 ---- .../vo/warehouse/ErpWarehouseSaveReqVO.java | 47 -- .../ErpPurchaseStatisticsMapper.java | 20 - .../statistics/ErpSaleStatisticsMapper.java | 20 - .../erp/dal/redis/RedisKeyConstants.java | 18 - .../erp/dal/redis/no/ErpNoRedisDAO.java | 96 --- .../purchase/ErpPurchaseInServiceImpl.java | 308 --------- .../ErpPurchaseReturnServiceImpl.java | 304 --------- .../service/sale/ErpSaleOutServiceImpl.java | 316 --------- .../sale/ErpSaleReturnServiceImpl.java | 316 --------- .../ErpPurchaseStatisticsService.java | 24 - .../ErpPurchaseStatisticsServiceImpl.java | 26 - .../statistics/ErpSaleStatisticsService.java | 24 - .../ErpSaleStatisticsServiceImpl.java | 26 - .../service/stock/ErpWarehouseService.java | 102 --- .../stock/ErpWarehouseServiceImpl.java | 126 ---- .../ErpPurchaseStatisticsMapper.xml | 23 - .../statistics/ErpSaleStatisticsMapper.xml | 23 - .../file/core/ftp/FtpFileClientTest.java | 41 -- .../file/core/local/LocalFileClientTest.java | 29 - .../file/core/s3/S3FileClientTest.java | 119 ---- .../file/core/sftp/SftpFileClientTest.java | 39 -- .../codegen/CodegenServiceImplTest.java | 558 ---------------- .../file/FileConfigServiceImplTest.java | 281 -------- .../service/file/FileServiceImplTest.java | 143 ---- .../yudao-module-product-biz/pom.xml | 67 -- .../mysql/comment/ProductCommentMapper.java | 60 -- .../yudao-module-promotion-biz/pom.xml | 82 --- .../yudao-module-statistics-biz/pom.xml | 95 --- .../member/MemberStatisticsController.java | 114 ---- .../infra/ApiAccessLogStatisticsMapper.java | 27 - .../mysql/member/MemberStatisticsMapper.java | 42 -- .../mysql/pay/PayWalletStatisticsMapper.java | 38 -- .../trade/AfterSaleStatisticsMapper.java | 24 - .../trade/BrokerageStatisticsMapper.java | 25 - .../trade/TradeOrderStatisticsMapper.java | 65 -- .../mysql/trade/TradeStatisticsMapper.java | 41 -- .../infra/ApiAccessLogStatisticsService.java | 32 - .../member/MemberStatisticsService.java | 70 -- .../pay/PayWalletStatisticsService.java | 40 -- .../trade/AfterSaleStatisticsService.java | 32 - .../trade/BrokerageStatisticsService.java | 31 - .../trade/TradeOrderStatisticsService.java | 83 --- .../service/trade/TradeStatisticsService.java | 67 -- .../yudao-module-trade-biz/pom.xml | 101 --- .../brokerage/BrokerageWithdrawConvert.java | 57 -- .../convert/order/TradeOrderConvert.java | 288 -------- yudao-module-pay/pom.xml | 25 - yudao-module-pay/yudao-module-pay-biz/pom.xml | 84 --- .../wallet/PayWalletRechargeConvert.java | 43 -- .../yudao-spring-boot-starter-biz-pay/pom.xml | 76 --- .../pay/config/YudaoPayAutoConfiguration.java | 22 - .../framework/pay/core/client/PayClient.java | 98 --- .../pay/core/client/PayClientConfig.java | 30 - .../pay/core/client/PayClientFactory.java | 38 -- .../client/dto/order/PayOrderRespDTO.java | 141 ---- .../dto/order/PayOrderUnifiedReqDTO.java | 92 --- .../client/dto/refund/PayRefundRespDTO.java | 115 ---- .../dto/refund/PayRefundUnifiedReqDTO.java | 70 -- .../dto/transfer/PayTransferRespDTO.java | 109 --- .../transfer/PayTransferUnifiedReqDTO.java | 78 --- .../core/client/exception/PayException.java | 17 - .../core/client/impl/AbstractPayClient.java | 250 ------- .../core/client/impl/NonePayClientConfig.java | 31 - .../client/impl/PayClientFactoryImpl.java | 95 --- .../impl/alipay/AbstractAlipayPayClient.java | 342 ---------- .../impl/alipay/AlipayAppPayClient.java | 59 -- .../impl/alipay/AlipayBarPayClient.java | 85 --- .../impl/alipay/AlipayPayClientConfig.java | 109 --- .../client/impl/alipay/AlipayPcPayClient.java | 69 -- .../client/impl/alipay/AlipayQrPayClient.java | 66 -- .../impl/alipay/AlipayWapPayClient.java | 58 -- .../core/client/impl/mock/MockPayClient.java | 80 --- .../impl/weixin/AbstractWxPayClient.java | 484 -------------- .../client/impl/weixin/WxAppPayClient.java | 63 -- .../client/impl/weixin/WxBarPayClient.java | 107 --- .../client/impl/weixin/WxLitePayClient.java | 22 - .../client/impl/weixin/WxNativePayClient.java | 58 -- .../client/impl/weixin/WxPayClientConfig.java | 110 ---- .../client/impl/weixin/WxPubPayClient.java | 80 --- .../core/enums/channel/PayChannelEnum.java | 68 -- .../enums/order/PayOrderDisplayModeEnum.java | 29 - .../enums/order/PayOrderStatusRespEnum.java | 56 -- .../enums/refund/PayRefundStatusRespEnum.java | 32 - .../transfer/PayTransferStatusRespEnum.java | 45 -- .../enums/transfer/PayTransferTypeEnum.java | 44 -- ...ot.autoconfigure.AutoConfiguration.imports | 1 - .../PayClientFactoryImplIntegrationTest.java | 133 ---- .../impl/alipay/AbstractAlipayClientTest.java | 221 ------- .../impl/alipay/AlipayBarPayClientTest.java | 170 ----- .../impl/alipay/AlipayPcPayClientTest.java | 131 ---- .../impl/alipay/AlipayQrPayClientTest.java | 147 ----- .../impl/alipay/AlipayWapPayClientTest.java | 111 ---- .../weixin/WxBarPayClientIntegrationTest.java | 123 ---- .../WxNativePayClientIntegrationTest.java | 83 --- .../auth/AdminAuthServiceImplTest.java | 372 ----------- 267 files changed, 24626 deletions(-) delete mode 100644 yudao-framework/yudao-spring-boot-starter-excel/src/test/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtilsTest.java delete mode 100644 yudao-module-bpm/pom.xml delete mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEvent.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEventListener.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/pom.xml delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventPublisher.java delete mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveResultListener.java delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/pom.xml delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/config/YudaoFlowableConfiguration.java delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/context/FlowableContextHolder.java delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/package-info.java delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/web/FlowableWebFilter.java delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/package-info.java delete mode 100644 yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports delete mode 100644 yudao-module-crm/pom.xml delete mode 100644 yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/DictTypeConstants.java delete mode 100644 yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java delete mode 100644 yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java delete mode 100644 yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/business/CrmBusinessEndStatusEnum.java delete mode 100644 yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmBizTypeEnum.java delete mode 100644 yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/permission/CrmPermissionLevelEnum.java delete mode 100644 yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReceivableReturnTypeEnum.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/pom.xml delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessStatusController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessUpdateStatusReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusSaveReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueSaveReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusiness2ReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusinessReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactPageReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSaveReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractConfigController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigSaveReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractPageReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractSaveReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractTransferReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerLimitConfigController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerDistributeReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerLockReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerPageReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerSaveReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/vo/CrmOperateLogRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductSaveReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanPageReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanSaveReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivablePageReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.http delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRanKRespVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRankReqVO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessDO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusDO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusTypeDO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractConfigDO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractProductDO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductDO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivablePlanDO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessProductMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusTypeMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactBusinessMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractConfigMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractProductMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankingMapper.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/RedisKeyConstants.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerIndustryParseFunction.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerLevelParseFunction.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerSourceParseFunction.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductStatusParseFunction.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductUnitParseFunction.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivablePlanParseFunction.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivableReturnTypeParseFunction.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysBooleanParseFunction.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysSexParseFunction.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/config/CrmWebConfiguration.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/package-info.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/job/package-info.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractResultListener.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/bo/CrmCustomerCreateReqBO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionTransferReqBO.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableResultListener.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingService.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingServiceImpl.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java delete mode 100644 yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/bi/CrmBiRankingMapper.xml delete mode 100644 yudao-module-erp/yudao-module-erp-biz/pom.xml delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpPurchaseStatisticsController.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.http delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseSummaryRespVO.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseTimeSummaryRespVO.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleSummaryRespVO.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleTimeSummaryRespVO.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpPurchaseStatisticsMapper.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpSaleStatisticsMapper.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsService.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsServiceImpl.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsService.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsServiceImpl.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpPurchaseStatisticsMapper.xml delete mode 100644 yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpSaleStatisticsMapper.xml delete mode 100644 yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/ftp/FtpFileClientTest.java delete mode 100644 yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/local/LocalFileClientTest.java delete mode 100644 yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/s3/S3FileClientTest.java delete mode 100644 yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/sftp/SftpFileClientTest.java delete mode 100644 yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java delete mode 100755 yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java delete mode 100644 yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java delete mode 100644 yudao-module-mall/yudao-module-product-biz/pom.xml delete mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java delete mode 100644 yudao-module-mall/yudao-module-promotion-biz/pom.xml delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/pom.xml delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/MemberStatisticsController.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/infra/ApiAccessLogStatisticsMapper.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/member/MemberStatisticsMapper.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/pay/PayWalletStatisticsMapper.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/AfterSaleStatisticsMapper.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/BrokerageStatisticsMapper.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeOrderStatisticsMapper.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeStatisticsMapper.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/infra/ApiAccessLogStatisticsService.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/member/MemberStatisticsService.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/PayWalletStatisticsService.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/AfterSaleStatisticsService.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/BrokerageStatisticsService.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeOrderStatisticsService.java delete mode 100644 yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeStatisticsService.java delete mode 100644 yudao-module-mall/yudao-module-trade-biz/pom.xml delete mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageWithdrawConvert.java delete mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java delete mode 100644 yudao-module-pay/pom.xml delete mode 100644 yudao-module-pay/yudao-module-pay-biz/pom.xml delete mode 100644 yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletRechargeConvert.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/pom.xml delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/YudaoPayAutoConfiguration.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientFactory.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundUnifiedReqDTO.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/exception/PayException.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/NonePayClientConfig.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayClientConfig.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxAppPayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxLitePayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/channel/PayChannelEnum.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderDisplayModeEnum.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderStatusRespEnum.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayRefundStatusRespEnum.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferTypeEnum.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClientTest.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClientTest.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClientTest.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClientTest.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClientIntegrationTest.java delete mode 100644 yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClientIntegrationTest.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java diff --git a/yudao-framework/pom.xml b/yudao-framework/pom.xml index 820fc4f2b3..fba24dca58 100644 --- a/yudao-framework/pom.xml +++ b/yudao-framework/pom.xml @@ -23,7 +23,6 @@ yudao-spring-boot-starter-mq yudao-spring-boot-starter-excel - yudao-spring-boot-starter-test yudao-spring-boot-starter-biz-operatelog yudao-spring-boot-starter-biz-tenant diff --git a/yudao-framework/yudao-spring-boot-starter-excel/pom.xml b/yudao-framework/yudao-spring-boot-starter-excel/pom.xml index 3da22b0527..8d778c7d4a 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-excel/pom.xml @@ -63,13 +63,6 @@ yudao-spring-boot-starter-biz-ip true - - - - cn.iocoder.boot - yudao-spring-boot-starter-test - test - diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/test/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtilsTest.java b/yudao-framework/yudao-spring-boot-starter-excel/src/test/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtilsTest.java deleted file mode 100644 index 3bce63c510..0000000000 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/test/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtilsTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package cn.iocoder.yudao.framework.dict.core.util; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.dict.util.DictFrameworkUtils; -import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; -import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; - -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.when; - -/** - * {@link DictFrameworkUtils} 的单元测试 - */ -public class DictFrameworkUtilsTest extends BaseMockitoUnitTest { - - @Mock - private DictDataApi dictDataApi; - - @BeforeEach - public void setUp() { - DictFrameworkUtils.init(dictDataApi); - } - - @Test - public void testGetDictDataLabel() { - // mock 数据 - DictDataRespDTO dataRespDTO = randomPojo(DictDataRespDTO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); - // mock 方法 - when(dictDataApi.getDictData(dataRespDTO.getDictType(), dataRespDTO.getValue())).thenReturn(dataRespDTO); - - // 断言返回值 - assertEquals(dataRespDTO.getLabel(), DictFrameworkUtils.getDictDataLabel(dataRespDTO.getDictType(), dataRespDTO.getValue())); - } - - @Test - public void testParseDictDataValue() { - // mock 数据 - DictDataRespDTO resp = randomPojo(DictDataRespDTO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); - // mock 方法 - when(dictDataApi.parseDictData(resp.getDictType(), resp.getLabel())).thenReturn(resp); - - // 断言返回值 - assertEquals(resp.getValue(), DictFrameworkUtils.parseDictDataValue(resp.getDictType(), resp.getLabel())); - } - -} diff --git a/yudao-module-bpm/pom.xml b/yudao-module-bpm/pom.xml deleted file mode 100644 index 491c99771a..0000000000 --- a/yudao-module-bpm/pom.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - yudao - cn.iocoder.boot - ${revision} - - 4.0.0 - - yudao-module-bpm-api - yudao-module-bpm-biz - yudao-spring-boot-starter-flowable - - yudao-module-bpm - pom - - ${project.artifactId} - - bpm 包下,业务流程管理(Business Process Management),我们放工作流的功能。 - 例如说:流程定义、表单配置、审核中心(我的申请、我的待办、我的已办)等等 - bpm 解释:https://baike.baidu.com/item/BPM/1933 - - 工作流基于 Flowable 6 实现,分成流程定义、流程表单、流程实例、流程任务等功能模块。 - - - diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEvent.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEvent.java deleted file mode 100644 index 8d0b2de551..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEvent.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.yudao.module.bpm.event; - -import lombok.Data; -import org.springframework.context.ApplicationEvent; - -import javax.validation.constraints.NotNull; - -/** - * 流程实例的结果发生变化的 Event - * 定位:由于额外增加了 {@link BpmProcessInstanceExtDO#getResult()} 结果,所以增加该事件 - * - * @author 芋道源码 - */ -@SuppressWarnings("ALL") -@Data -public class BpmProcessInstanceResultEvent extends ApplicationEvent { - - /** - * 流程实例的编号 - */ - @NotNull(message = "流程实例的编号不能为空") - private String id; - /** - * 流程实例的 key - */ - @NotNull(message = "流程实例的 key 不能为空") - private String processDefinitionKey; - /** - * 流程实例的结果 - */ - @NotNull(message = "流程实例的结果不能为空") - private Integer result; - /** - * 流程实例对应的业务标识 - * 例如说,请假 - */ - private String businessKey; - - public BpmProcessInstanceResultEvent(Object source) { - super(source); - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEventListener.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEventListener.java deleted file mode 100644 index bff99a8c19..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/event/BpmProcessInstanceResultEventListener.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.yudao.module.bpm.event; - -import cn.hutool.core.util.StrUtil; -import org.springframework.context.ApplicationListener; - -/** - * {@link BpmProcessInstanceResultEvent} 的监听器 - * - * @author 芋道源码 - */ -public abstract class BpmProcessInstanceResultEventListener - implements ApplicationListener { - - @Override - public final void onApplicationEvent(BpmProcessInstanceResultEvent event) { - if (!StrUtil.equals(event.getProcessDefinitionKey(), getProcessDefinitionKey())) { - return; - } - onEvent(event); - } - - /** - * @return 返回监听的流程定义 Key - */ - protected abstract String getProcessDefinitionKey(); - - /** - * 处理事件 - * - * @param event 事件 - */ - protected abstract void onEvent(BpmProcessInstanceResultEvent event); - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/pom.xml b/yudao-module-bpm/yudao-module-bpm-biz/pom.xml deleted file mode 100644 index f1ac4c0ee8..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - cn.iocoder.boot - yudao-module-bpm - ${revision} - - 4.0.0 - yudao-module-bpm-biz - - ${project.artifactId} - - bpm 包下,业务流程管理(Business Process Management),我们放工作流的功能,基于 Flowable 6 版本实现。 - 例如说:流程定义、表单配置、审核中心(我的申请、我的待办、我的已办)等等 - - - - cn.iocoder.boot - yudao-module-bpm-api - ${revision} - - - cn.iocoder.boot - yudao-module-system-api - ${revision} - - - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-operatelog - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-data-permission - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-tenant - - - - - cn.iocoder.boot - yudao-spring-boot-starter-web - - - - cn.iocoder.boot - yudao-spring-boot-starter-security - - - - - cn.iocoder.boot - yudao-spring-boot-starter-mybatis - - - - - cn.iocoder.boot - yudao-spring-boot-starter-test - - - - - cn.iocoder.boot - yudao-spring-boot-starter-flowable - ${revision} - - - diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java deleted file mode 100644 index 41f2184c5c..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java +++ /dev/null @@ -1,115 +0,0 @@ -package cn.iocoder.yudao.module.bpm.convert.task; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.date.DateUtils; -import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageItemRespVO; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; -import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; -import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import org.flowable.engine.history.HistoricProcessInstance; -import org.flowable.engine.repository.ProcessDefinition; -import org.flowable.engine.runtime.ProcessInstance; -import org.flowable.task.api.Task; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.MappingTarget; -import org.mapstruct.factory.Mappers; - -import java.util.List; -import java.util.Map; - -/** - * 流程实例 Convert - * - * @author 芋道源码 - */ -@Mapper(uses = DateUtils.class) -public interface BpmProcessInstanceConvert { - - BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class); - - default PageResult convertPage(PageResult page, - Map> taskMap) { - List list = convertList(page.getList()); - list.forEach(respVO -> respVO.setTasks(convertList2(taskMap.get(respVO.getId())))); - return new PageResult<>(list, page.getTotal()); - } - - List convertList(List list); - - @Mapping(source = "processInstanceId", target = "id") - BpmProcessInstancePageItemRespVO convert(BpmProcessInstanceExtDO bean); - - List convertList2(List tasks); - - default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, BpmProcessInstanceExtDO processInstanceExt, - ProcessDefinition processDefinition, BpmProcessDefinitionExtDO processDefinitionExt, - String bpmnXml, AdminUserRespDTO startUser, DeptRespDTO dept) { - BpmProcessInstanceRespVO respVO = convert2(processInstance); - copyTo(processInstanceExt, respVO); - // definition - respVO.setProcessDefinition(convert2(processDefinition)); - copyTo(processDefinitionExt, respVO.getProcessDefinition()); - respVO.getProcessDefinition().setBpmnXml(bpmnXml); - // user - if (startUser != null) { - respVO.setStartUser(convert2(startUser)); - if (dept != null) { - respVO.getStartUser().setDeptName(dept.getName()); - } - } - return respVO; - } - - BpmProcessInstanceRespVO convert2(HistoricProcessInstance bean); - - @Mapping(source = "from.id", target = "to.id", ignore = true) - void copyTo(BpmProcessInstanceExtDO from, @MappingTarget BpmProcessInstanceRespVO to); - - BpmProcessInstanceRespVO.ProcessDefinition convert2(ProcessDefinition bean); - - @Mapping(source = "from.id", target = "to.id", ignore = true) - void copyTo(BpmProcessDefinitionExtDO from, @MappingTarget BpmProcessInstanceRespVO.ProcessDefinition to); - - BpmProcessInstanceRespVO.User convert2(AdminUserRespDTO bean); - - default BpmProcessInstanceResultEvent convert(Object source, HistoricProcessInstance instance, Integer result) { - BpmProcessInstanceResultEvent event = new BpmProcessInstanceResultEvent(source); - event.setId(instance.getId()); - event.setProcessDefinitionKey(instance.getProcessDefinitionKey()); - event.setBusinessKey(instance.getBusinessKey()); - event.setResult(result); - return event; - } - - default BpmProcessInstanceResultEvent convert(Object source, ProcessInstance instance, Integer result) { - BpmProcessInstanceResultEvent event = new BpmProcessInstanceResultEvent(source); - event.setId(instance.getId()); - event.setProcessDefinitionKey(instance.getProcessDefinitionKey()); - event.setBusinessKey(instance.getBusinessKey()); - event.setResult(result); - return event; - } - - default BpmMessageSendWhenProcessInstanceApproveReqDTO convert2ApprovedReq(ProcessInstance instance){ - return new BpmMessageSendWhenProcessInstanceApproveReqDTO() - .setStartUserId(NumberUtils.parseLong(instance.getStartUserId())) - .setProcessInstanceId(instance.getId()) - .setProcessInstanceName(instance.getName()); - } - - default BpmMessageSendWhenProcessInstanceRejectReqDTO convert2RejectReq(ProcessInstance instance, String reason) { - return new BpmMessageSendWhenProcessInstanceRejectReqDTO() - .setProcessInstanceName(instance.getName()) - .setProcessInstanceId(instance.getId()) - .setReason(reason) - .setStartUserId(NumberUtils.parseLong(instance.getStartUserId())); - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventPublisher.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventPublisher.java deleted file mode 100644 index 319d923c7a..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/core/event/BpmProcessInstanceResultEventPublisher.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.yudao.module.bpm.framework.bpm.core.event; - -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; -import lombok.AllArgsConstructor; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; - -/** - * {@link BpmProcessInstanceResultEvent} 的生产者 - * - * @author 芋道源码 - */ -@AllArgsConstructor -@Validated -public class BpmProcessInstanceResultEventPublisher { - - private final ApplicationEventPublisher publisher; - - public void sendProcessInstanceResultEvent(@Valid BpmProcessInstanceResultEvent event) { - publisher.publishEvent(event); - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveResultListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveResultListener.java deleted file mode 100644 index f24a18ad01..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOALeaveResultListener.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.oa.listener; - -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEventListener; -import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveService; -import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveServiceImpl; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * OA 请假单的结果的监听器实现类 - * - * @author 芋道源码 - */ -@Component -public class BpmOALeaveResultListener extends BpmProcessInstanceResultEventListener { - - @Resource - private BpmOALeaveService leaveService; - - @Override - protected String getProcessDefinitionKey() { - return BpmOALeaveServiceImpl.PROCESS_KEY; - } - - @Override - protected void onEvent(BpmProcessInstanceResultEvent event) { - leaveService.updateLeaveResult(Long.parseLong(event.getBusinessKey()), event.getResult()); - } - -} diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/pom.xml b/yudao-module-bpm/yudao-spring-boot-starter-flowable/pom.xml deleted file mode 100644 index ae0ed46eef..0000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - cn.iocoder.boot - yudao-module-bpm - ${revision} - - 4.0.0 - - yudao-spring-boot-starter-flowable - - - - cn.iocoder.boot - yudao-common - - - - - cn.iocoder.boot - yudao-spring-boot-starter-security - - - - - org.flowable - flowable-spring-boot-starter-process - - - org.flowable - flowable-spring-boot-starter-actuator - - - - diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/config/YudaoFlowableConfiguration.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/config/YudaoFlowableConfiguration.java deleted file mode 100644 index 859eca510d..0000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/config/YudaoFlowableConfiguration.java +++ /dev/null @@ -1,46 +0,0 @@ -package cn.iocoder.yudao.framework.flowable.config; - -import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; -import cn.iocoder.yudao.framework.flowable.core.web.FlowableWebFilter; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.core.task.AsyncListenableTaskExecutor; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; - -@AutoConfiguration -public class YudaoFlowableConfiguration { - - /** - * 参考 {@link org.flowable.spring.boot.FlowableJobConfiguration} 类,创建对应的 AsyncListenableTaskExecutor Bean - * - * 如果不创建,会导致项目启动时,Flowable 报错的问题 - */ - @Bean(name = "applicationTaskExecutor") - @ConditionalOnMissingBean(name = "applicationTaskExecutor") - public AsyncListenableTaskExecutor taskExecutor() { - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - executor.setCorePoolSize(8); - executor.setMaxPoolSize(8); - executor.setQueueCapacity(100); - executor.setThreadNamePrefix("flowable-task-Executor-"); - executor.setAwaitTerminationSeconds(30); - executor.setWaitForTasksToCompleteOnShutdown(true); - executor.setAllowCoreThreadTimeOut(true); - executor.initialize(); - return executor; - } - - /** - * 配置 flowable Web 过滤器 - */ - @Bean - public FilterRegistrationBean flowableWebFilter() { - FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); - registrationBean.setFilter(new FlowableWebFilter()); - registrationBean.setOrder(WebFilterOrderEnum.FLOWABLE_FILTER); - return registrationBean; - } - -} diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/context/FlowableContextHolder.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/context/FlowableContextHolder.java deleted file mode 100644 index efc6d5340d..0000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/context/FlowableContextHolder.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.framework.flowable.core.context; - -import cn.hutool.core.collection.CollUtil; -import com.alibaba.ttl.TransmittableThreadLocal; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * 工作流--用户用到的上下文相关信息 - */ -public class FlowableContextHolder { - - private static final ThreadLocal>> ASSIGNEE = new TransmittableThreadLocal<>(); - - /** - * 通过流程任务的定义 key ,拿到提前选好的审批人 - * 此方法目的:首次创建流程实例时,数据库中还查询不到 assignee 字段,所以存入上下文中获取 - * - * @param taskDefinitionKey 流程任务 key - * @return 审批人 ID 集合 - */ - public static List getAssigneeByTaskDefinitionKey(String taskDefinitionKey) { - if (CollUtil.isNotEmpty(ASSIGNEE.get())) { - return ASSIGNEE.get().get(taskDefinitionKey); - } - return Collections.emptyList(); - } - - /** - * 存入提前选好的审批人到上下文线程变量中 - * - * @param assignee 流程任务 key -> 审批人 ID 炅和 - */ - public static void setAssignee(Map> assignee) { - ASSIGNEE.set(assignee); - } - -} diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java deleted file mode 100644 index c3cce4272c..0000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.framework.flowable.core.enums; - -/** - * 流程常量信息 - */ -public interface BpmnModelConstants { - - String BPMN_FILE_SUFFIX = ".bpmn"; - - /** - * BPMN 中的命名空间 - * - * 这个东西有可能导致无法切换工作流程的实现 - */ - String NAMESPACE = "http://flowable.org/bpmn"; - - /** - * 自定义属性 dataType - */ - String PROCESS_CUSTOM_DATA_TYPE = "dataType"; - -} diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/package-info.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/package-info.java deleted file mode 100644 index de8d6279d7..0000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.framework.flowable.core; diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java deleted file mode 100644 index 7b23a467a0..0000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java +++ /dev/null @@ -1,309 +0,0 @@ -package cn.iocoder.yudao.framework.flowable.core.util; - -import cn.hutool.core.collection.CollUtil; -import org.flowable.bpmn.converter.BpmnXMLConverter; -import org.flowable.bpmn.model.Process; -import org.flowable.bpmn.model.*; - -import java.util.*; - -/** - * 流程模型转操作工具类 - */ -public class BpmnModelUtils { - - /** - * 根据节点,获取入口连线 - * - * @param source 起始节点 - * @return 入口连线列表 - */ - public static List getElementIncomingFlows(FlowElement source) { - if (source instanceof FlowNode) { - return ((FlowNode) source).getIncomingFlows(); - } - return new ArrayList<>(); - } - - /** - * 根据节点,获取出口连线 - * - * @param source 起始节点 - * @return 出口连线列表 - */ - public static List getElementOutgoingFlows(FlowElement source) { - if (source instanceof FlowNode) { - return ((FlowNode) source).getOutgoingFlows(); - } - return new ArrayList<>(); - } - - /** - * 获取流程元素信息 - * - * @param model bpmnModel 对象 - * @param flowElementId 元素 ID - * @return 元素信息 - */ - public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) { - Process process = model.getMainProcess(); - return process.getFlowElement(flowElementId); - } - - /** - * 获得 BPMN 流程中,指定的元素们 - * - * @param model - * @param clazz 指定元素。例如说,{@link UserTask}、{@link Gateway} 等等 - * @return 元素们 - */ - public static List getBpmnModelElements(BpmnModel model, Class clazz) { - List result = new ArrayList<>(); - model.getProcesses().forEach(process -> { - process.getFlowElements().forEach(flowElement -> { - if (flowElement.getClass().isAssignableFrom(clazz)) { - result.add((T) flowElement); - } - }); - }); - return result; - } - - /** - * 比较 两个bpmnModel 是否相同 - * @param oldModel 老的bpmn model - * @param newModel 新的bpmn model - */ - public static boolean equals(BpmnModel oldModel, BpmnModel newModel) { - // 由于 BpmnModel 未提供 equals 方法,所以只能转成字节数组,进行比较 - return Arrays.equals(getBpmnBytes(oldModel), getBpmnBytes(newModel)); - } - - /** - * 把 bpmnModel 转换成 byte[] - * @param model bpmnModel - */ - public static byte[] getBpmnBytes(BpmnModel model) { - if (model == null) { - return new byte[0]; - } - BpmnXMLConverter converter = new BpmnXMLConverter(); - return converter.convertToXML(model); - } - - // ========== 遍历相关的方法 ========== - - /** - * 找到 source 节点之前的所有用户任务节点 - * - * @param source 起始节点 - * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 - * @param userTaskList 已找到的用户任务节点 - * @return 用户任务节点 数组 - */ - public static List getPreviousUserTaskList(FlowElement source, Set hasSequenceFlow, List userTaskList) { - userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; - hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; - // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 - if (source instanceof StartEvent && source.getSubProcess() != null) { - userTaskList = getPreviousUserTaskList(source.getSubProcess(), hasSequenceFlow, userTaskList); - } - - // 根据类型,获取入口连线 - List sequenceFlows = getElementIncomingFlows(source); - if (sequenceFlows == null) { - return userTaskList; - } - // 循环找到目标元素 - for (SequenceFlow sequenceFlow : sequenceFlows) { - // 如果发现连线重复,说明循环了,跳过这个循环 - if (hasSequenceFlow.contains(sequenceFlow.getId())) { - continue; - } - // 添加已经走过的连线 - hasSequenceFlow.add(sequenceFlow.getId()); - // 类型为用户节点,则新增父级节点 - if (sequenceFlow.getSourceFlowElement() instanceof UserTask) { - userTaskList.add((UserTask) sequenceFlow.getSourceFlowElement()); - } - // 类型为子流程,则添加子流程开始节点出口处相连的节点 - if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) { - // 获取子流程用户任务节点 - List childUserTaskList = findChildProcessUserTaskList((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, null); - // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续 - if (CollUtil.isNotEmpty(childUserTaskList)) { - userTaskList.addAll(childUserTaskList); - } - } - // 继续迭代 - userTaskList = getPreviousUserTaskList(sequenceFlow.getSourceFlowElement(), hasSequenceFlow, userTaskList); - } - return userTaskList; - } - - /** - * 迭代获取子流程用户任务节点 - * - * @param source 起始节点 - * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 - * @param userTaskList 需要撤回的用户任务列表 - * @return 用户任务节点 - */ - public static List findChildProcessUserTaskList(FlowElement source, Set hasSequenceFlow, List userTaskList) { - hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; - userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; - - // 根据类型,获取出口连线 - List sequenceFlows = getElementOutgoingFlows(source); - if (sequenceFlows == null) { - return userTaskList; - } - // 循环找到目标元素 - for (SequenceFlow sequenceFlow : sequenceFlows) { - // 如果发现连线重复,说明循环了,跳过这个循环 - if (hasSequenceFlow.contains(sequenceFlow.getId())) { - continue; - } - // 添加已经走过的连线 - hasSequenceFlow.add(sequenceFlow.getId()); - // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加 - if (sequenceFlow.getTargetFlowElement() instanceof UserTask) { - userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement()); - continue; - } - // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取 - if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { - List childUserTaskList = findChildProcessUserTaskList((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, null); - // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续 - if (CollUtil.isNotEmpty(childUserTaskList)) { - userTaskList.addAll(childUserTaskList); - continue; - } - } - // 继续迭代 - userTaskList = findChildProcessUserTaskList(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, userTaskList); - } - return userTaskList; - } - - - /** - * 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行 - * 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况 - * - * @param source 起始节点 - * @param target 目标节点 - * @param visitedElements 已经经过的连线的 ID,用于判断线路是否重复 - * @return 结果 - */ - public static boolean isSequentialReachable(FlowElement source, FlowElement target, Set visitedElements) { - visitedElements = visitedElements == null ? new HashSet<>() : visitedElements; - // 不能是开始事件和子流程 - if (source instanceof StartEvent && isInEventSubprocess(source)) { - return false; - } - - // 根据类型,获取入口连线 - List sequenceFlows = getElementIncomingFlows(source); - if (CollUtil.isEmpty(sequenceFlows)) { - return true; - } - // 循环找到目标元素 - for (SequenceFlow sequenceFlow : sequenceFlows) { - // 如果发现连线重复,说明循环了,跳过这个循环 - if (visitedElements.contains(sequenceFlow.getId())) { - continue; - } - // 添加已经走过的连线 - visitedElements.add(sequenceFlow.getId()); - // 这条线路存在目标节点,这条线路完成,进入下个线路 - FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement(); - if (target.getId().equals(sourceFlowElement.getId())) { - continue; - } - // 如果目标节点为并行网关,则不继续 - if (sourceFlowElement instanceof ParallelGateway) { - return false; - } - // 否则就继续迭代 - if (!isSequentialReachable(sourceFlowElement, target, visitedElements)) { - return false; - } - } - return true; - } - - /** - * 判断当前节点是否属于不同的子流程 - * - * @param flowElement 被判断的节点 - * @return true 表示属于子流程 - */ - private static boolean isInEventSubprocess(FlowElement flowElement) { - FlowElementsContainer flowElementsContainer = flowElement.getParentContainer(); - while (flowElementsContainer != null) { - if (flowElementsContainer instanceof EventSubProcess) { - return true; - } - - if (flowElementsContainer instanceof FlowElement) { - flowElementsContainer = ((FlowElement) flowElementsContainer).getParentContainer(); - } else { - flowElementsContainer = null; - } - } - return false; - } - - /** - * 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找 - * - * @param source 起始节点 - * @param runTaskKeyList 正在运行的任务 Key,用于校验任务节点是否是正在运行的节点 - * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 - * @param userTaskList 需要撤回的用户任务列表 - * @return 子级任务节点列表 - */ - public static List iteratorFindChildUserTasks(FlowElement source, List runTaskKeyList, - Set hasSequenceFlow, List userTaskList) { - hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; - userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; - // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代 - if (source instanceof StartEvent && source.getSubProcess() != null) { - userTaskList = iteratorFindChildUserTasks(source.getSubProcess(), runTaskKeyList, hasSequenceFlow, userTaskList); - } - - // 根据类型,获取出口连线 - List sequenceFlows = getElementOutgoingFlows(source); - if (sequenceFlows == null) { - return userTaskList; - } - // 循环找到目标元素 - for (SequenceFlow sequenceFlow : sequenceFlows) { - // 如果发现连线重复,说明循环了,跳过这个循环 - if (hasSequenceFlow.contains(sequenceFlow.getId())) { - continue; - } - // 添加已经走过的连线 - hasSequenceFlow.add(sequenceFlow.getId()); - // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加 - if (sequenceFlow.getTargetFlowElement() instanceof UserTask && runTaskKeyList.contains((sequenceFlow.getTargetFlowElement()).getId())) { - userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement()); - continue; - } - // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取 - if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { - List childUserTaskList = iteratorFindChildUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), runTaskKeyList, hasSequenceFlow, null); - // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续 - if (CollUtil.isNotEmpty(childUserTaskList)) { - userTaskList.addAll(childUserTaskList); - continue; - } - } - // 继续迭代 - userTaskList = iteratorFindChildUserTasks(sequenceFlow.getTargetFlowElement(), runTaskKeyList, hasSequenceFlow, userTaskList); - } - return userTaskList; - } - -} diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java deleted file mode 100644 index 2a0fc38ac5..0000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.framework.flowable.core.util; - -import org.flowable.common.engine.impl.identity.Authentication; - -/** - * Flowable 相关的工具方法 - * - * @author 芋道源码 - */ -public class FlowableUtils { - - // ========== User 相关的工具方法 ========== - - public static void setAuthenticatedUserId(Long userId) { - Authentication.setAuthenticatedUserId(String.valueOf(userId)); - } - - public static void clearAuthenticatedUserId() { - Authentication.setAuthenticatedUserId(null); - } - - // ========== Execution 相关的工具方法 ========== - - public static String formatCollectionVariable(String activityId) { - return activityId + "_assignees"; - } - - public static String formatCollectionElementVariable(String activityId) { - return activityId + "_assignee"; - } - -} diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/web/FlowableWebFilter.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/web/FlowableWebFilter.java deleted file mode 100644 index d9845a394c..0000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/web/FlowableWebFilter.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.framework.flowable.core.web; - -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; -import org.springframework.web.filter.OncePerRequestFilter; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -/** - * flowable Web 过滤器,将 userId 设置到 {@link org.flowable.common.engine.impl.identity.Authentication} 中 - * - * @author jason - */ -public class FlowableWebFilter extends OncePerRequestFilter { - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) - throws ServletException, IOException { - try { - // 设置工作流的用户 - Long userId = SecurityFrameworkUtils.getLoginUserId(); - if (userId != null) { - FlowableUtils.setAuthenticatedUserId(userId); - } - // 过滤 - chain.doFilter(request, response); - } finally { - // 清理 - FlowableUtils.clearAuthenticatedUserId(); - } - } -} diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/package-info.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/package-info.java deleted file mode 100644 index 324d3de0ec..0000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.framework.flowable; diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 1df61598ce..0000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1 +0,0 @@ -cn.iocoder.yudao.framework.flowable.config.YudaoFlowableConfiguration \ No newline at end of file diff --git a/yudao-module-crm/pom.xml b/yudao-module-crm/pom.xml deleted file mode 100644 index 310a7df872..0000000000 --- a/yudao-module-crm/pom.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - cn.iocoder.boot - yudao - ${revision} - - - yudao-module-crm-api - yudao-module-crm-biz - - 4.0.0 - yudao-module-crm - pom - - ${project.artifactId} - - crm 包下,客户关系管理(Customer Relationship Management)。 - 例如说:客户、联系人、商机、合同、回款等等 - - - diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/DictTypeConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/DictTypeConstants.java deleted file mode 100644 index eee2b32d9c..0000000000 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/DictTypeConstants.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.yudao.module.crm.enums; - -/** - * CRM 字典类型的枚举类 - * - * @author 芋道源码 - */ -public interface DictTypeConstants { - - String CRM_CUSTOMER_INDUSTRY = "crm_customer_industry"; // CRM 客户所属行业 - String CRM_CUSTOMER_LEVEL = "crm_customer_level"; // CRM 客户等级 - String CRM_CUSTOMER_SOURCE = "crm_customer_source"; // CRM 客户来源 - String CRM_AUDIT_STATUS = "crm_audit_status"; // CRM 审批状态 - String CRM_PRODUCT_UNIT = "crm_product_unit"; // CRM 产品单位 - String CRM_PRODUCT_STATUS = "crm_product_status"; // CRM 产品状态 - String CRM_FOLLOW_UP_TYPE = "crm_follow_up_type"; // CRM 跟进方式 - String CRM_RECEIVABLE_RETURN_TYPE = "crm_receivable_return_type"; // CRM 回款方式 - -} 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 deleted file mode 100644 index a15a3211b4..0000000000 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java +++ /dev/null @@ -1,103 +0,0 @@ -package cn.iocoder.yudao.module.crm.enums; - -import cn.iocoder.yudao.framework.common.exception.ErrorCode; - -/** - * CRM 错误码枚举类 - *

- * crm 系统,使用 1-020-000-000 段 - */ -public interface ErrorCodeConstants { - - // ========== 合同管理 1-020-000-000 ========== - ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在"); - 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, "线索不存在"); - ErrorCode CLUE_TRANSFORM_FAIL_ALREADY = new ErrorCode(1_020_001_001, "线索已经转化过了,请勿重复转化"); - - // ========== 商机管理 1-020-002-000 ========== - ErrorCode BUSINESS_NOT_EXISTS = new ErrorCode(1_020_002_000, "商机不存在"); - ErrorCode BUSINESS_DELETE_FAIL_CONTRACT_EXISTS = new ErrorCode(1_020_002_001, "商机已关联合同,不能删除"); - ErrorCode BUSINESS_UPDATE_STATUS_FAIL_END_STATUS = new ErrorCode(1_020_002_002, "更新商机状态失败,原因:已经是结束状态"); - ErrorCode BUSINESS_UPDATE_STATUS_FAIL_STATUS_EQUALS = new ErrorCode(1_020_002_003, "更新商机状态失败,原因:已经是该状态"); - - // ========== 联系人管理 1-020-003-000 ========== - ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在"); - ErrorCode CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS = new ErrorCode(1_020_003_002, "联系人已关联合同,不能删除"); - ErrorCode CONTACT_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_003_003, "更新联系人负责人失败"); - - // ========== 回款 1-020-004-000 ========== - ErrorCode RECEIVABLE_NOT_EXISTS = new ErrorCode(1_020_004_000, "回款不存在"); - ErrorCode RECEIVABLE_UPDATE_FAIL_EDITING_PROHIBITED = new ErrorCode(1_020_004_001, "更新回款失败,原因:禁止编辑"); - ErrorCode RECEIVABLE_DELETE_FAIL = new ErrorCode(1_020_004_002, "删除回款失败,原因: 被回款计划所使用,不允许删除"); - ErrorCode RECEIVABLE_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_004_003, "回款提交审核失败,原因:回款没处在未提交状态"); - ErrorCode RECEIVABLE_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_004_004, "更新回款审核状态失败,原因:回款不是审核中状态"); - ErrorCode RECEIVABLE_NO_EXISTS = new ErrorCode(1_020_004_005, "生成回款序列号重复,请重试"); - ErrorCode RECEIVABLE_CREATE_FAIL_CONTRACT_NOT_APPROVE = new ErrorCode(1_020_004_006, "创建回款失败,原因:合同不是审核通过状态"); - ErrorCode RECEIVABLE_CREATE_FAIL_PRICE_EXCEEDS_LIMIT = new ErrorCode(1_020_004_007, "创建回款失败,原因:回款金额超出合同金额,目前剩余可退:{} 元"); - - // ========== 回款计划 1-020-005-000 ========== - ErrorCode RECEIVABLE_PLAN_NOT_EXISTS = new ErrorCode(1_020_005_000, "回款计划不存在"); - ErrorCode RECEIVABLE_PLAN_UPDATE_FAIL = new ErrorCode(1_020_006_000, "更想回款计划失败,原因:已经有对应的还款"); - ErrorCode RECEIVABLE_PLAN_EXISTS_RECEIVABLE = new ErrorCode(1_020_006_001, "回款计划已经有对应的回款,不能使用"); - - // ========== 客户管理 1_020_006_000 ========== - ErrorCode CUSTOMER_NOT_EXISTS = new ErrorCode(1_020_006_000, "客户不存在"); - ErrorCode CUSTOMER_OWNER_EXISTS = new ErrorCode(1_020_006_001, "客户【{}】已存在所属负责人"); - ErrorCode CUSTOMER_LOCKED = new ErrorCode(1_020_006_002, "客户【{}】状态已锁定"); - ErrorCode CUSTOMER_ALREADY_DEAL = new ErrorCode(1_020_006_003, "客户已交易"); - ErrorCode CUSTOMER_IN_POOL = new ErrorCode(1_020_006_004, "客户【{}】放入公海失败,原因:已经是公海客户"); - ErrorCode CUSTOMER_LOCKED_PUT_POOL_FAIL = new ErrorCode(1_020_006_005, "客户【{}】放入公海失败,原因:客户已锁定"); - ErrorCode CUSTOMER_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_006_006, "更新客户【{}】负责人失败, 原因:系统异常"); - ErrorCode CUSTOMER_LOCK_FAIL_IS_LOCK = new ErrorCode(1_020_006_007, "锁定客户失败,它已经处于锁定状态"); - ErrorCode CUSTOMER_UNLOCK_FAIL_IS_UNLOCK = new ErrorCode(1_020_006_008, "解锁客户失败,它已经处于未锁定状态"); - ErrorCode CUSTOMER_LOCK_EXCEED_LIMIT = new ErrorCode(1_020_006_009, "锁定客户失败,超出锁定规则上限"); - ErrorCode CUSTOMER_OWNER_EXCEED_LIMIT = new ErrorCode(1_020_006_010, "操作失败,超出客户数拥有上限"); - ErrorCode CUSTOMER_DELETE_FAIL_HAVE_REFERENCE = new ErrorCode(1_020_006_011, "删除客户失败,有关联{}"); - ErrorCode CUSTOMER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_020_006_012, "导入客户数据不能为空!"); - ErrorCode CUSTOMER_CREATE_NAME_NOT_NULL = new ErrorCode(1_020_006_013, "客户名称不能为空!"); - ErrorCode CUSTOMER_NAME_EXISTS = new ErrorCode(1_020_006_014, "已存在名为【{}】的客户!"); - ErrorCode CUSTOMER_UPDATE_DEAL_STATUS_FAIL = new ErrorCode(1_020_006_015, "更新客户的成交状态失败,原因:已经是该状态,无需更新"); - - // ========== 权限管理 1_020_007_000 ========== - ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在"); - ErrorCode CRM_PERMISSION_DENIED = new ErrorCode(1_020_007_001, "{}操作失败,原因:没有权限"); - ErrorCode CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS = new ErrorCode(1_020_007_003, "{}操作失败,原因:转移对象已经是该负责人"); - ErrorCode CRM_PERMISSION_DELETE_FAIL = new ErrorCode(1_020_007_004, "删除数据权限失败,原因:批量删除权限的时候,只能属于同一个 bizId 下"); - ErrorCode CRM_PERMISSION_DELETE_DENIED = new ErrorCode(1_020_007_006, "删除数据权限失败,原因:没有权限"); - ErrorCode CRM_PERMISSION_DELETE_SELF_PERMISSION_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_007, "删除数据权限失败,原因:不能删除负责人"); - ErrorCode CRM_PERMISSION_CREATE_FAIL = new ErrorCode(1_020_007_008, "创建数据权限失败,原因:所加用户已有权限"); - - // ========== 产品 1_020_008_000 ========== - ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_020_008_000, "产品不存在"); - ErrorCode PRODUCT_NO_EXISTS = new ErrorCode(1_020_008_001, "产品编号已存在"); - ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_020_008_002, "产品【{}】已禁用"); - - // ========== 产品分类 1_020_009_000 ========== - ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_020_009_000, "产品分类不存在"); - ErrorCode PRODUCT_CATEGORY_EXISTS = new ErrorCode(1_020_009_001, "产品分类已存在"); - ErrorCode PRODUCT_CATEGORY_USED = new ErrorCode(1_020_009_002, "产品分类已关联产品"); - ErrorCode PRODUCT_CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1_020_009_003, "父分类不存在"); - ErrorCode PRODUCT_CATEGORY_PARENT_NOT_FIRST_LEVEL = new ErrorCode(1_020_009_004, "父分类不能是二级分类"); - ErrorCode product_CATEGORY_EXISTS_CHILDREN = new ErrorCode(1_020_009_005, "存在子分类,无法删除"); - - // ========== 商机状态 1_020_010_000 ========== - ErrorCode BUSINESS_STATUS_TYPE_NOT_EXISTS = new ErrorCode(1_020_010_000, "商机状态组不存在"); - ErrorCode BUSINESS_STATUS_TYPE_NAME_EXISTS = new ErrorCode(1_020_010_001, "商机状态组的名称已存在"); - ErrorCode BUSINESS_STATUS_UPDATE_FAIL_USED = new ErrorCode(1_020_010_002, "已经被使用的商机状态组,无法进行更新"); - ErrorCode BUSINESS_STATUS_DELETE_FAIL_USED = new ErrorCode(1_020_010_002, "已经被使用的商机状态组,无法进行删除"); - ErrorCode BUSINESS_STATUS_NOT_EXISTS = new ErrorCode(1_020_010_003, "商机状态不存在"); - - // ========== 客户公海规则设置 1_020_012_000 ========== - ErrorCode CUSTOMER_LIMIT_CONFIG_NOT_EXISTS = new ErrorCode(1_020_012_001, "客户限制配置不存在"); - - // ========== 跟进记录 1_020_013_000 ========== - ErrorCode FOLLOW_UP_RECORD_NOT_EXISTS = new ErrorCode(1_020_013_000, "跟进记录不存在"); - ErrorCode FOLLOW_UP_RECORD_DELETE_DENIED = new ErrorCode(1_020_013_001, "删除跟进记录失败,原因:没有权限"); - -} diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java deleted file mode 100644 index c2c835b7f1..0000000000 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java +++ /dev/null @@ -1,163 +0,0 @@ -package cn.iocoder.yudao.module.crm.enums; - -/** - * CRM 操作日志枚举 - * 目的:统一管理,也减少 Service 里各种“复杂”字符串 - * - * @author HUIHUI - */ -public interface LogRecordConstants { - - // ======================= CRM_CLUE 线索 ======================= - - String CRM_CLUE_TYPE = "CRM 线索"; - String CRM_CLUE_CREATE_SUB_TYPE = "创建线索"; - String CRM_CLUE_CREATE_SUCCESS = "创建了线索{{#clue.name}}"; - String CRM_CLUE_UPDATE_SUB_TYPE = "更新线索"; - String CRM_CLUE_UPDATE_SUCCESS = "更新了线索【{{#clueName}}】: {_DIFF{#updateReq}}"; - String CRM_CLUE_DELETE_SUB_TYPE = "删除线索"; - String CRM_CLUE_DELETE_SUCCESS = "删除了线索【{{#clueName}}】"; - String CRM_CLUE_TRANSFER_SUB_TYPE = "转移线索"; - String CRM_CLUE_TRANSFER_SUCCESS = "将线索【{{#clue.name}}】的负责人从【{getAdminUserById{#clue.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; - String CRM_CLUE_TRANSLATE_SUB_TYPE = "线索转化为客户"; - String CRM_CLUE_TRANSLATE_SUCCESS = "将线索【{{#clueName}}】转化为客户"; - String CRM_CLUE_FOLLOW_UP_SUB_TYPE = "线索跟进"; - String CRM_CLUE_FOLLOW_UP_SUCCESS = "线索跟进【{{#clueName}}】"; - - // ======================= CRM_CUSTOMER 客户 ======================= - - String CRM_CUSTOMER_TYPE = "CRM 客户"; - String CRM_CUSTOMER_CREATE_SUB_TYPE = "创建客户"; - String CRM_CUSTOMER_CREATE_SUCCESS = "创建了客户{{#customer.name}}"; - String CRM_CUSTOMER_UPDATE_SUB_TYPE = "更新客户"; - String CRM_CUSTOMER_UPDATE_SUCCESS = "更新了客户【{{#customerName}}】: {_DIFF{#updateReqVO}}"; - String CRM_CUSTOMER_DELETE_SUB_TYPE = "删除客户"; - String CRM_CUSTOMER_DELETE_SUCCESS = "删除了客户【{{#customerName}}】"; - String CRM_CUSTOMER_TRANSFER_SUB_TYPE = "转移客户"; - String CRM_CUSTOMER_TRANSFER_SUCCESS = "将客户【{{#customer.name}}】的负责人从【{getAdminUserById{#customer.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; - String CRM_CUSTOMER_LOCK_SUB_TYPE = "{{#customer.lockStatus ? '解锁客户' : '锁定客户'}}"; - String CRM_CUSTOMER_LOCK_SUCCESS = "{{#customer.lockStatus ? '将客户【' + #customer.name + '】解锁' : '将客户【' + #customer.name + '】锁定'}}"; - String CRM_CUSTOMER_POOL_SUB_TYPE = "客户放入公海"; - String CRM_CUSTOMER_POOL_SUCCESS = "将客户【{{#customerName}}】放入了公海"; - String CRM_CUSTOMER_RECEIVE_SUB_TYPE = "{{#ownerUserName != null ? '分配客户' : '领取客户'}}"; - String CRM_CUSTOMER_RECEIVE_SUCCESS = "{{#ownerUserName != null ? '将客户【' + #customer.name + '】分配给【' + #ownerUserName + '】' : '领取客户【' + #customer.name + '】'}}"; - String CRM_CUSTOMER_IMPORT_SUB_TYPE = "{{#isUpdate ? '导入并更新客户' : '导入客户'}}"; - String CRM_CUSTOMER_IMPORT_SUCCESS = "{{#isUpdate ? '导入并更新了客户【'+ #customer.name +'】' : '导入了客户【'+ #customer.name +'】'}}"; - String CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUB_TYPE = "更新客户成交状态"; - String CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUCCESS = "更新了客户【{{#customerName}}】的成交状态为【{{#dealStatus ? '已成交' : '未成交'}}】"; - String CRM_CUSTOMER_FOLLOW_UP_SUB_TYPE = "客户跟进"; - String CRM_CUSTOMER_FOLLOW_UP_SUCCESS = "客户跟进【{{#customerName}}】"; - - // ======================= CRM_CUSTOMER_LIMIT_CONFIG 客户限制配置 ======================= - - String CRM_CUSTOMER_LIMIT_CONFIG_TYPE = "CRM 客户限制配置"; - String CRM_CUSTOMER_LIMIT_CONFIG_CREATE_SUB_TYPE = "创建客户限制配置"; - String CRM_CUSTOMER_LIMIT_CONFIG_CREATE_SUCCESS = "创建了【{{#limitType}}】类型的客户限制配置"; - String CRM_CUSTOMER_LIMIT_CONFIG_UPDATE_SUB_TYPE = "更新客户限制配置"; - String CRM_CUSTOMER_LIMIT_CONFIG_UPDATE_SUCCESS = "更新了客户限制配置: {_DIFF{#updateReqVO}}"; - String CRM_CUSTOMER_LIMIT_CONFIG_DELETE_SUB_TYPE = "删除客户限制配置"; - String CRM_CUSTOMER_LIMIT_CONFIG_DELETE_SUCCESS = "删除了【{{#limitType}}】类型的客户限制配置"; - - // ======================= CRM_CUSTOMER_POOL_CONFIG 客户公海规则 ======================= - - String CRM_CUSTOMER_POOL_CONFIG_TYPE = "CRM 客户公海规则"; - String CRM_CUSTOMER_POOL_CONFIG_SUB_TYPE = "{{#isPoolConfigUpdate ? '更新客户公海规则' : '创建客户公海规则'}}"; - String CRM_CUSTOMER_POOL_CONFIG_SUCCESS = "{{#isPoolConfigUpdate ? '更新了客户公海规则' : '创建了客户公海规则'}}"; - - // ======================= CRM_CONTACT 联系人 ======================= - - String CRM_CONTACT_TYPE = "CRM 联系人"; - String CRM_CONTACT_CREATE_SUB_TYPE = "创建联系人"; - String CRM_CONTACT_CREATE_SUCCESS = "创建了联系人{{#contact.name}}"; - String CRM_CONTACT_UPDATE_SUB_TYPE = "更新联系人"; - String CRM_CONTACT_UPDATE_SUCCESS = "更新了联系人【{{#contactName}}】: {_DIFF{#updateReqVO}}"; - String CRM_CONTACT_DELETE_SUB_TYPE = "删除联系人"; - String CRM_CONTACT_DELETE_SUCCESS = "删除了联系人【{{#contactName}}】"; - String CRM_CONTACT_TRANSFER_SUB_TYPE = "转移联系人"; - String CRM_CONTACT_TRANSFER_SUCCESS = "将联系人【{{#contact.name}}】的负责人从【{getAdminUserById{#contact.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; - String CRM_CONTACT_FOLLOW_UP_SUB_TYPE = "联系人跟进"; - String CRM_CONTACT_FOLLOW_UP_SUCCESS = "联系人跟进【{{#contactName}}】"; - String CRM_CONTACT_UPDATE_OWNER_USER_SUB_TYPE = "更新联系人负责人"; - String CRM_CONTACT_UPDATE_OWNER_USER_SUCCESS = "将联系人【{{#contact.name}}】的负责人从【{getAdminUserById{#contact.ownerUserId}}】变更为了【{getAdminUserById{#ownerUserId}}】"; - - // ======================= CRM_BUSINESS 商机 ======================= - - String CRM_BUSINESS_TYPE = "CRM 商机"; - String CRM_BUSINESS_CREATE_SUB_TYPE = "创建商机"; - String CRM_BUSINESS_CREATE_SUCCESS = "创建了商机{{#business.name}}"; - String CRM_BUSINESS_UPDATE_SUB_TYPE = "更新商机"; - String CRM_BUSINESS_UPDATE_SUCCESS = "更新了商机【{{#businessName}}】: {_DIFF{#updateReqVO}}"; - String CRM_BUSINESS_DELETE_SUB_TYPE = "删除商机"; - String CRM_BUSINESS_DELETE_SUCCESS = "删除了商机【{{#businessName}}】"; - String CRM_BUSINESS_TRANSFER_SUB_TYPE = "转移商机"; - String CRM_BUSINESS_TRANSFER_SUCCESS = "将商机【{{#business.name}}】的负责人从【{getAdminUserById{#business.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; - String CRM_BUSINESS_FOLLOW_UP_SUB_TYPE = "商机跟进"; - String CRM_BUSINESS_FOLLOW_UP_SUCCESS = "商机跟进【{{#businessName}}】"; - String CRM_BUSINESS_UPDATE_STATUS_SUB_TYPE = "更新商机状态"; - String CRM_BUSINESS_UPDATE_STATUS_SUCCESS = "更新了商机【{{#businessName}}】的状态从【{{#oldStatusName}}】变更为了【{{#newStatusName}}】"; - - // ======================= CRM_CONTRACT_CONFIG 合同配置 ======================= - - String CRM_CONTRACT_CONFIG_TYPE = "CRM 合同配置"; - String CRM_CONTRACT_CONFIG_SUB_TYPE = "{{#isPoolConfigUpdate ? '更新合同配置' : '创建合同配置'}}"; - String CRM_CONTRACT_CONFIG_SUCCESS = "{{#isPoolConfigUpdate ? '更新了合同配置' : '创建了合同配置'}}"; - - // ======================= CRM_CONTRACT 合同 ======================= - - String CRM_CONTRACT_TYPE = "CRM 合同"; - String CRM_CONTRACT_CREATE_SUB_TYPE = "创建合同"; - String CRM_CONTRACT_CREATE_SUCCESS = "创建了合同{{#contract.name}}"; - String CRM_CONTRACT_UPDATE_SUB_TYPE = "更新合同"; - String CRM_CONTRACT_UPDATE_SUCCESS = "更新了合同【{{#contractName}}】: {_DIFF{#updateReqVO}}"; - String CRM_CONTRACT_DELETE_SUB_TYPE = "删除合同"; - String CRM_CONTRACT_DELETE_SUCCESS = "删除了合同【{{#contractName}}】"; - String CRM_CONTRACT_TRANSFER_SUB_TYPE = "转移合同"; - String CRM_CONTRACT_TRANSFER_SUCCESS = "将合同【{{#contract.name}}】的负责人从【{getAdminUserById{#contract.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; - String CRM_CONTRACT_SUBMIT_SUB_TYPE = "提交合同审批"; - String CRM_CONTRACT_SUBMIT_SUCCESS = "提交合同【{{#contractName}}】审批成功"; - String CRM_CONTRACT_FOLLOW_UP_SUB_TYPE = "合同跟进"; - String CRM_CONTRACT_FOLLOW_UP_SUCCESS = "合同跟进【{{#contractName}}】"; - - // ======================= CRM_PRODUCT 产品 ======================= - - String CRM_PRODUCT_TYPE = "CRM 产品"; - String CRM_PRODUCT_CREATE_SUB_TYPE = "创建产品"; - String CRM_PRODUCT_CREATE_SUCCESS = "创建了产品【{{#createReqVO.name}}】"; - String CRM_PRODUCT_UPDATE_SUB_TYPE = "更新产品"; - String CRM_PRODUCT_UPDATE_SUCCESS = "更新了产品【{{#updateReqVO.name}}】: {_DIFF{#updateReqVO}}"; - String CRM_PRODUCT_DELETE_SUB_TYPE = "删除产品"; - String CRM_PRODUCT_DELETE_SUCCESS = "删除了产品【{{#product.name}}】"; - - // ======================= CRM_PRODUCT_CATEGORY 产品分类 ======================= - - String CRM_PRODUCT_CATEGORY_TYPE = "CRM 产品分类"; - String CRM_PRODUCT_CATEGORY_CREATE_SUB_TYPE = "创建产品分类"; - String CRM_PRODUCT_CATEGORY_CREATE_SUCCESS = "创建了产品分类【{{#createReqVO.name}}】"; - String CRM_PRODUCT_CATEGORY_UPDATE_SUB_TYPE = "更新产品分类"; - String CRM_PRODUCT_CATEGORY_UPDATE_SUCCESS = "更新了产品分类【{{#updateReqVO.name}}】: {_DIFF{#updateReqVO}}"; - String CRM_PRODUCT_CATEGORY_DELETE_SUB_TYPE = "删除产品分类"; - String CRM_PRODUCT_CATEGORY_DELETE_SUCCESS = "删除了产品分类【{{#productCategory.name}}】"; - - // ======================= CRM_RECEIVABLE 回款 ======================= - - String CRM_RECEIVABLE_TYPE = "CRM 回款"; - String CRM_RECEIVABLE_CREATE_SUB_TYPE = "创建回款"; - String CRM_RECEIVABLE_CREATE_SUCCESS = "创建了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款"; - String CRM_RECEIVABLE_UPDATE_SUB_TYPE = "更新回款"; - String CRM_RECEIVABLE_UPDATE_SUCCESS = "更新了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款: {_DIFF{#updateReqVO}}"; - String CRM_RECEIVABLE_DELETE_SUB_TYPE = "删除回款"; - String CRM_RECEIVABLE_DELETE_SUCCESS = "删除了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款"; - String CRM_RECEIVABLE_SUBMIT_SUB_TYPE = "提交回款审批"; - String CRM_RECEIVABLE_SUBMIT_SUCCESS = "提交编号为【{{#receivableNo}}】的回款审批成功"; - - // ======================= CRM_RECEIVABLE_PLAN 回款计划 ======================= - - String CRM_RECEIVABLE_PLAN_TYPE = "CRM 回款计划"; - String CRM_RECEIVABLE_PLAN_CREATE_SUB_TYPE = "创建回款计划"; - String CRM_RECEIVABLE_PLAN_CREATE_SUCCESS = "创建了合同【{getContractById{#receivablePlan.contractId}}】的第【{{#receivablePlan.period}}】期回款计划"; - String CRM_RECEIVABLE_PLAN_UPDATE_SUB_TYPE = "更新回款计划"; - String CRM_RECEIVABLE_PLAN_UPDATE_SUCCESS = "更新了合同【{getContractById{#receivablePlan.contractId}}】的第【{{#receivablePlan.period}}】期回款计划: {_DIFF{#updateReqVO}}"; - String CRM_RECEIVABLE_PLAN_DELETE_SUB_TYPE = "删除回款计划"; - String CRM_RECEIVABLE_PLAN_DELETE_SUCCESS = "删除了合同【{getContractById{#receivablePlan.contractId}}】的第【{{#receivablePlan.period}}】期回款计划"; - -} diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/business/CrmBusinessEndStatusEnum.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/business/CrmBusinessEndStatusEnum.java deleted file mode 100644 index 4736c01b77..0000000000 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/business/CrmBusinessEndStatusEnum.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.module.crm.enums.business; - -import cn.iocoder.yudao.framework.common.core.IntArrayValuable; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.util.Arrays; - -/** - * 商机的结束状态枚举 - * - * @author lzxhqs - */ -@RequiredArgsConstructor -@Getter -public enum CrmBusinessEndStatusEnum implements IntArrayValuable { - - WIN(1, "赢单"), - LOSE(2, "输单"), - INVALID(3, "无效"); - - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmBusinessEndStatusEnum::getStatus).toArray(); - - /** - * 场景类型 - */ - private final Integer status; - /** - * 场景名称 - */ - private final String name; - - @Override - public int[] array() { - return ARRAYS; - } - - public static CrmBusinessEndStatusEnum fromStatus(Integer status) { - return Arrays.stream(values()) - .filter(value -> value.getStatus().equals(status)) - .findFirst() - .orElse(null); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmBizTypeEnum.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmBizTypeEnum.java deleted file mode 100644 index 8402ad2886..0000000000 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmBizTypeEnum.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.iocoder.yudao.module.crm.enums.common; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjUtil; -import cn.iocoder.yudao.framework.common.core.IntArrayValuable; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.util.Arrays; - -/** - * CRM 业务类型枚举 - * - * @author HUIHUI - */ -@RequiredArgsConstructor -@Getter -public enum CrmBizTypeEnum implements IntArrayValuable { - - CRM_CLUE(1, "线索"), - CRM_CUSTOMER(2, "客户"), - CRM_CONTACT(3, "联系人"), - CRM_BUSINESS(4, "商机"), - CRM_CONTRACT(5, "合同"), - CRM_PRODUCT(6, "产品"), - CRM_RECEIVABLE(7, "回款"), - CRM_RECEIVABLE_PLAN(8, "回款计划") - ; - - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmBizTypeEnum::getType).toArray(); - - /** - * 类型 - */ - private final Integer type; - /** - * 名称 - */ - private final String name; - - public static String getNameByType(Integer type) { - CrmBizTypeEnum typeEnum = CollUtil.findOne(CollUtil.newArrayList(CrmBizTypeEnum.values()), - item -> ObjUtil.equal(item.type, type)); - return typeEnum == null ? null : typeEnum.getName(); - } - - @Override - public int[] array() { - return ARRAYS; - } - -} diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/permission/CrmPermissionLevelEnum.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/permission/CrmPermissionLevelEnum.java deleted file mode 100644 index 7b44fe962e..0000000000 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/permission/CrmPermissionLevelEnum.java +++ /dev/null @@ -1,53 +0,0 @@ -package cn.iocoder.yudao.module.crm.enums.permission; - -import cn.hutool.core.util.ObjUtil; -import cn.iocoder.yudao.framework.common.core.IntArrayValuable; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Arrays; - -/** - * CRM 数据权限级别枚举 - * - * OWNER > WRITE > READ - * - * @author HUIHUI - */ -@Getter -@AllArgsConstructor -public enum CrmPermissionLevelEnum implements IntArrayValuable { - - OWNER(1, "负责人"), - READ(2, "只读"), - WRITE(3, "读写"); - - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmPermissionLevelEnum::getLevel).toArray(); - - /** - * 级别 - */ - private final Integer level; - /** - * 级别名称 - */ - private final String name; - - @Override - public int[] array() { - return ARRAYS; - } - - public static boolean isOwner(Integer level) { - return ObjUtil.equal(OWNER.level, level); - } - - public static boolean isRead(Integer level) { - return ObjUtil.equal(READ.level, level); - } - - public static boolean isWrite(Integer level) { - return ObjUtil.equal(WRITE.level, level); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReceivableReturnTypeEnum.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReceivableReturnTypeEnum.java deleted file mode 100644 index 3c01fe95c1..0000000000 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/receivable/CrmReceivableReturnTypeEnum.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.yudao.module.crm.enums.receivable; - -import cn.iocoder.yudao.framework.common.core.IntArrayValuable; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Arrays; - -/** - * CRM 回款方式枚举 - * - * @author HUIHUI - */ -@Getter -@AllArgsConstructor -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(CrmReceivableReturnTypeEnum::getType).toArray(); - - /** - * 类型 - */ - private final Integer type; - /** - * 名称 - */ - private final String name; - - @Override - public int[] array() { - return ARRAYS; - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/pom.xml b/yudao-module-crm/yudao-module-crm-biz/pom.xml deleted file mode 100644 index 04e048da79..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - cn.iocoder.boot - yudao-module-crm - ${revision} - - 4.0.0 - yudao-module-crm-biz - - ${project.artifactId} - - crm 包下,客户关系管理(Customer Relationship Management)。 - 例如说:客户、联系人、商机、合同、回款等等 - - - - - cn.iocoder.boot - yudao-module-system-api - ${revision} - - - cn.iocoder.boot - yudao-module-crm-api - ${revision} - - - cn.iocoder.boot - yudao-module-bpm-api - ${revision} - - - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-operatelog - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-ip - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-tenant - - - - - cn.iocoder.boot - yudao-spring-boot-starter-web - - - - cn.iocoder.boot - yudao-spring-boot-starter-security - - - - - cn.iocoder.boot - yudao-spring-boot-starter-mybatis - - - - - cn.iocoder.boot - yudao-spring-boot-starter-excel - - - - - cn.iocoder.boot - yudao-spring-boot-starter-test - - - diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java deleted file mode 100644 index 8cd44bd8cb..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java +++ /dev/null @@ -1,222 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.business; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -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.business.vo.business.*; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; -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.CrmBusinessService; -import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusService; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; -import cn.iocoder.yudao.module.crm.service.product.CrmProductService; -import cn.iocoder.yudao.module.system.api.dept.DeptApi; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletResponse; -import javax.validation.Valid; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS; - -@Tag(name = "管理后台 - CRM 商机") -@RestController -@RequestMapping("/crm/business") -@Validated -public class CrmBusinessController { - - @Resource - private CrmBusinessService businessService; - @Resource - private CrmCustomerService customerService; - @Resource - private CrmBusinessStatusService businessStatusTypeService; - @Resource - private CrmBusinessStatusService businessStatusService; - @Resource - private CrmProductService productService; - - @Resource - private AdminUserApi adminUserApi; - @Resource - private DeptApi deptApi; - - @PostMapping("/create") - @Operation(summary = "创建商机") - @PreAuthorize("@ss.hasPermission('crm:business:create')") - public CommonResult createBusiness(@Valid @RequestBody CrmBusinessSaveReqVO createReqVO) { - return success(businessService.createBusiness(createReqVO, getLoginUserId())); - } - - @PutMapping("/update") - @Operation(summary = "更新商机") - @PreAuthorize("@ss.hasPermission('crm:business:update')") - public CommonResult updateBusiness(@Valid @RequestBody CrmBusinessSaveReqVO updateReqVO) { - businessService.updateBusiness(updateReqVO); - return success(true); - } - - @PutMapping("/update-status") - @Operation(summary = "更新商机状态") - @PreAuthorize("@ss.hasPermission('crm:business:update')") - public CommonResult updateBusinessStatus(@Valid @RequestBody CrmBusinessUpdateStatusReqVO updateStatusReqVO) { - businessService.updateBusinessStatus(updateStatusReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除商机") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:business:delete')") - public CommonResult deleteBusiness(@RequestParam("id") Long id) { - businessService.deleteBusiness(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得商机") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:business:query')") - public CommonResult getBusiness(@RequestParam("id") Long id) { - CrmBusinessDO business = businessService.getBusiness(id); - return success(buildBusinessDetail(business)); - } - - private CrmBusinessRespVO buildBusinessDetail(CrmBusinessDO business) { - if (business == null) { - return null; - } - CrmBusinessRespVO businessVO = buildBusinessDetailList(Collections.singletonList(business)).get(0); - // 拼接产品项 - List businessProducts = businessService.getBusinessProductListByBusinessId(businessVO.getId()); - Map productMap = productService.getProductMap( - convertSet(businessProducts, CrmBusinessProductDO::getProductId)); - businessVO.setProducts(BeanUtils.toBean(businessProducts, CrmBusinessRespVO.Product.class, businessProductVO -> - MapUtils.findAndThen(productMap, businessProductVO.getProductId(), - product -> businessProductVO.setProductName(product.getName()) - .setProductNo(product.getNo()).setProductUnit(product.getUnit())))); - return businessVO; - } - - @GetMapping("/simple-all-list") - @Operation(summary = "获得联系人的精简列表") - @PreAuthorize("@ss.hasPermission('crm:contact:query')") - public CommonResult> getSimpleContactList() { - CrmBusinessPageReqVO reqVO = new CrmBusinessPageReqVO(); - reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 - PageResult pageResult = businessService.getBusinessPage(reqVO, getLoginUserId()); - return success(convertList(pageResult.getList(), business -> // 只返回 id、name 字段 - new CrmBusinessRespVO().setId(business.getId()).setName(business.getName()) - .setCustomerId(business.getCustomerId()))); - } - - @GetMapping("/page") - @Operation(summary = "获得商机分页") - @PreAuthorize("@ss.hasPermission('crm:business:query')") - public CommonResult> getBusinessPage(@Valid CrmBusinessPageReqVO pageVO) { - PageResult pageResult = businessService.getBusinessPage(pageVO, getLoginUserId()); - return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/page-by-customer") - @Operation(summary = "获得商机分页,基于指定客户") - public CommonResult> getBusinessPageByCustomer(@Valid CrmBusinessPageReqVO pageReqVO) { - if (pageReqVO.getCustomerId() == null) { - throw exception(CUSTOMER_NOT_EXISTS); - } - PageResult pageResult = businessService.getBusinessPageByCustomerId(pageReqVO); - return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/page-by-contact") - @Operation(summary = "获得联系人的商机分页") - @PreAuthorize("@ss.hasPermission('crm:business:query')") - public CommonResult> getBusinessContactPage(@Valid CrmBusinessPageReqVO pageReqVO) { - PageResult pageResult = businessService.getBusinessPageByContact(pageReqVO); - return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出商机 Excel") - @PreAuthorize("@ss.hasPermission('crm:business:export')") - @OperateLog(type = EXPORT) - public void exportBusinessExcel(@Valid CrmBusinessPageReqVO exportReqVO, - HttpServletResponse response) throws IOException { - exportReqVO.setPageSize(PAGE_SIZE_NONE); - List list = businessService.getBusinessPage(exportReqVO, getLoginUserId()).getList(); - // 导出 Excel - ExcelUtils.write(response, "商机.xls", "数据", CrmBusinessRespVO.class, - buildBusinessDetailList(list)); - } - - private List buildBusinessDetailList(List list) { - if (CollUtil.isEmpty(list)) { - return Collections.emptyList(); - } - // 1.1 获取客户列表 - Map customerMap = customerService.getCustomerMap( - convertSet(list, CrmBusinessDO::getCustomerId)); - // 1.2 获取创建人、负责人列表 - Map userMap = adminUserApi.getUserMap(convertListByFlatMap(list, - contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); - Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); - // 1.3 获得商机状态组 - Map statusTypeMap = businessStatusTypeService.getBusinessStatusTypeMap( - convertSet(list, CrmBusinessDO::getStatusTypeId)); - Map statusMap = businessStatusService.getBusinessStatusMap( - convertSet(list, CrmBusinessDO::getStatusId)); - // 2. 拼接数据 - return BeanUtils.toBean(list, CrmBusinessRespVO.class, businessVO -> { - // 2.1 设置客户名称 - MapUtils.findAndThen(customerMap, businessVO.getCustomerId(), customer -> businessVO.setCustomerName(customer.getName())); - // 2.2 设置创建人、负责人名称 - MapUtils.findAndThen(userMap, NumberUtils.parseLong(businessVO.getCreator()), - user -> businessVO.setCreatorName(user.getNickname())); - MapUtils.findAndThen(userMap, businessVO.getOwnerUserId(), user -> { - businessVO.setOwnerUserName(user.getNickname()); - MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> businessVO.setOwnerUserDeptName(dept.getName())); - }); - // 2.3 设置商机状态 - MapUtils.findAndThen(statusTypeMap, businessVO.getStatusTypeId(), statusType -> businessVO.setStatusTypeName(statusType.getName())); - MapUtils.findAndThen(statusMap, businessVO.getStatusId(), status -> businessVO.setStatusName( - businessService.getBusinessStatusName(businessVO.getEndStatus(), status))); - }); - } - - @PutMapping("/transfer") - @Operation(summary = "商机转移") - @PreAuthorize("@ss.hasPermission('crm:business:update')") - public CommonResult transferBusiness(@Valid @RequestBody CrmBusinessTransferReqVO reqVO) { - businessService.transferBusiness(reqVO, getLoginUserId()); - return success(true); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessStatusController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessStatusController.java deleted file mode 100644 index db80306730..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessStatusController.java +++ /dev/null @@ -1,126 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.business; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusSaveReqVO; -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; -import cn.iocoder.yudao.module.system.api.dept.DeptApi; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.validation.Valid; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -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.security.core.util.SecurityFrameworkUtils.getLoginUserId; - -@Tag(name = "管理后台 - CRM 商机状态") -@RestController -@RequestMapping("/crm/business-status") -@Validated -public class CrmBusinessStatusController { - - @Resource - private CrmBusinessStatusService businessStatusTypeService; - - @Resource - private AdminUserApi adminUserApi; - @Resource - private DeptApi deptApi; - - @PostMapping("/create") - @Operation(summary = "创建商机状态") - @PreAuthorize("@ss.hasPermission('crm:business-status:create')") - public CommonResult createBusinessStatus(@Valid @RequestBody CrmBusinessStatusSaveReqVO createReqVO) { - return success(businessStatusTypeService.createBusinessStatus(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新商机状态") - @PreAuthorize("@ss.hasPermission('crm:business-status:update')") - public CommonResult updateBusinessStatus(@Valid @RequestBody CrmBusinessStatusSaveReqVO updateReqVO) { - businessStatusTypeService.updateBusinessStatus(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除商机状态") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:business-status:delete')") - public CommonResult deleteBusinessStatusType(@RequestParam("id") Long id) { - businessStatusTypeService.deleteBusinessStatusType(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得商机状态") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:business-status:query')") - public CommonResult getBusinessStatusType(@RequestParam("id") Long id) { - CrmBusinessStatusTypeDO statusType = businessStatusTypeService.getBusinessStatusType(id); - if (statusType == null) { - return success(null); - } - List statuses = businessStatusTypeService.getBusinessStatusListByTypeId(id); - return success(BeanUtils.toBean(statusType, CrmBusinessStatusRespVO.class, - statusTypeVO -> statusTypeVO.setStatuses(BeanUtils.toBean(statuses, CrmBusinessStatusRespVO.Status.class)))); - } - - @GetMapping("/page") - @Operation(summary = "获得商机状态分页") - @PreAuthorize("@ss.hasPermission('crm:business-status:query')") - public CommonResult> getBusinessStatusPage(@Valid PageParam pageReqVO) { - // 1. 查询数据 - PageResult pageResult = businessStatusTypeService.getBusinessStatusTypePage(pageReqVO); - if (CollUtil.isEmpty(pageResult.getList())) { - return success(PageResult.empty(pageResult.getTotal())); - } - // 2. 拼接数据 - Map userMap = adminUserApi.getUserMap( - convertSet(pageResult.getList(), statusType -> Long.parseLong(statusType.getCreator()))); - Map deptMap = deptApi.getDeptMap( - convertSetByFlatMap(pageResult.getList(), CrmBusinessStatusTypeDO::getDeptIds, Collection::stream)); - return success(BeanUtils.toBean(pageResult, CrmBusinessStatusRespVO.class, statusTypeVO -> { - statusTypeVO.setCreator(userMap.get(NumberUtils.parseLong(statusTypeVO.getCreator())).getNickname()); - statusTypeVO.setDeptNames(convertList(statusTypeVO.getDeptIds(), - deptId -> deptMap.containsKey(deptId) ? deptMap.get(deptId).getName() : null)); - })); - } - - @GetMapping("/type-simple-list") - @Operation(summary = "获得商机状态组列表") - public CommonResult> getBusinessStatusTypeSimpleList() { - List list = businessStatusTypeService.getBusinessStatusTypeList(); - // 过滤掉部门不匹配的 - Long deptId = adminUserApi.getUser(getLoginUserId()).getDeptId(); - list.removeIf(statusType -> CollUtil.isNotEmpty(statusType.getDeptIds()) && !statusType.getDeptIds().contains(deptId)); - return success(BeanUtils.toBean(list, CrmBusinessStatusRespVO.class)); - } - - @GetMapping("/status-simple-list") - @Operation(summary = "获得商机状态列表") - @Parameter(name = "typeId", description = "商机状态组", required = true, example = "1024") - public CommonResult> getBusinessStatusSimpleList(@RequestParam("typeId") Long typeId) { - List list = businessStatusTypeService.getBusinessStatusListByTypeId(typeId); - return success(BeanUtils.toBean(list, CrmBusinessStatusRespVO.Status.class)); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java deleted file mode 100644 index 49cdcb80be..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java +++ /dev/null @@ -1,144 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; - -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.math.BigDecimal; -import java.time.LocalDateTime; -import java.util.List; - -@Schema(description = "管理后台 - CRM 商机 Response VO") -@Data -@ExcelIgnoreUnannotated -public class CrmBusinessRespVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") - @ExcelProperty("编号") - private Long id; - - @Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") - @ExcelProperty("商机名称") - private String name; - - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299") - private Long customerId; - @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") - @ExcelProperty("客户名称") - private String customerName; - - @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example ="true") - @ExcelProperty("跟进状态") - private Boolean followUpStatus; - - @Schema(description = "最后跟进时间") - @ExcelProperty("最后跟进时间") - private LocalDateTime contactLastTime; - - @Schema(description = "下次联系时间") - @ExcelProperty("下次联系时间") - private LocalDateTime contactNextTime; - - @Schema(description = "负责人的用户编号", example = "25682") - @ExcelProperty("负责人的用户编号") - private Long ownerUserId; - @Schema(description = "负责人名字", example = "25682") - @ExcelProperty("负责人名字") - private String ownerUserName; - @Schema(description = "负责人部门") - @ExcelProperty("负责人部门") - private String ownerUserDeptName; - - @Schema(description = "商机状态组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") - private Long statusTypeId; - @Schema(description = "商机状组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "进行中") - @ExcelProperty("商机状态组") - private String statusTypeName; - - @Schema(description = "商机状态编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") - private Long statusId; - @Schema(description = "状态名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "跟进中") - @ExcelProperty("商机状态") - private String statusName; - - @Schema - @ExcelProperty("结束状态") - private Integer endStatus; - - @ExcelProperty("结束时的备注") - private String endRemark; - - @Schema(description = "预计成交日期") - @ExcelProperty("预计成交日期") - private LocalDateTime dealTime; - - @Schema(description = "产品总金额", example = "12025") - @ExcelProperty("产品总金额") - private BigDecimal totalProductPrice; - - @Schema(description = "整单折扣") - @ExcelProperty("整单折扣") - private BigDecimal discountPercent; - - @Schema(description = "商机总金额", example = "12371") - @ExcelProperty("商机总金额") - private BigDecimal totalPrice; - - @Schema(description = "备注", example = "随便") - @ExcelProperty("备注") - private String remark; - - @Schema(description = "创建人", example = "1024") - @ExcelProperty("创建人") - private String creator; - @Schema(description = "创建人名字", example = "芋道源码") - @ExcelProperty("创建人名字") - private String creatorName; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - - @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("更新时间") - private LocalDateTime updateTime; - - @Schema(description = "产品列表") - private List products; - - @Schema(description = "产品列表") - @Data - @NoArgsConstructor - @AllArgsConstructor - public static class Product { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") - private Long id; - - @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") - private Long productId; - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") - private String productName; - @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") - private String productNo; - @Schema(description = "产品单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") - private Integer productUnit; - - @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") - private BigDecimal productPrice; - - @Schema(description = "商机价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") - private BigDecimal businessPrice; - - @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") - private BigDecimal count; - - @Schema(description = "总计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") - private BigDecimal totalPrice; - - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java deleted file mode 100644 index 9275e0e032..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java +++ /dev/null @@ -1,95 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; - -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerParseFunction; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysAdminUserParseFunction; -import com.mzt.logapi.starter.annotation.DiffLogField; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.format.annotation.DateTimeFormat; - -import javax.validation.constraints.NotNull; -import java.math.BigDecimal; -import java.time.LocalDateTime; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -@Schema(description = "管理后台 - CRM 商机创建/更新 Request VO") -@Data -public class CrmBusinessSaveReqVO { - - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") - private Long id; - - @Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") - @DiffLogField(name = "商机名称") - @NotNull(message = "商机名称不能为空") - private String name; - - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299") - @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) - @NotNull(message = "客户不能为空") - private Long customerId; - - @Schema(description = "下次联系时间") - @DiffLogField(name = "下次联系时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime contactNextTime; - - @Schema(description = "负责人用户编号", example = "14334") - @NotNull(message = "负责人不能为空") - @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) - private Long ownerUserId; - - @Schema(description = "商机状态组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") - @DiffLogField(name = "商机状态组") - @NotNull(message = "商机状态组不能为空") - private Long statusTypeId; - - @Schema(description = "预计成交日期") - @DiffLogField(name = "预计成交日期") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime dealTime; - - @Schema(description = "整单折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "55.00") - @DiffLogField(name = "整单折扣") - @NotNull(message = "整单折扣不能为空") - private BigDecimal discountPercent; - - @Schema(description = "备注", example = "随便") - @DiffLogField(name = "备注") - private String remark; - - @Schema(description = "联系人编号", example = "110") - private Long contactId; // 使用场景,在【联系人详情】添加商机时,如果需要关联两者,需要传递 contactId 字段 - - @Schema(description = "产品列表") - private List products; - - @Schema(description = "产品列表") - @Data - @NoArgsConstructor - @AllArgsConstructor - public static class Product { - - @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") - @NotNull(message = "产品编号不能为空") - private Long productId; - - @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") - @NotNull(message = "产品单价不能为空") - private BigDecimal productPrice; - - @Schema(description = "商机价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") - @NotNull(message = "商机价格不能为空") - private BigDecimal businessPrice; - - @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") - @NotNull(message = "产品数量不能为空") - private Integer count; - - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessUpdateStatusReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessUpdateStatusReqVO.java deleted file mode 100644 index 3fe7d9f47f..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessUpdateStatusReqVO.java +++ /dev/null @@ -1,31 +0,0 @@ -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.enums.business.CrmBusinessEndStatusEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import javax.validation.constraints.AssertTrue; -import javax.validation.constraints.NotNull; - -@Schema(description = "管理后台 - CRM 商机更新状态 Request VO") -@Data -public class CrmBusinessUpdateStatusReqVO { - - @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") - @NotNull(message = "商机编号不能为空") - private Long id; - - @Schema(description = "状态编号", example = "1") - private Long statusId; - - @Schema(description = "结束状态", example = "1") - @InEnum(value = CrmBusinessEndStatusEnum.class) - private Integer endStatus; - - @AssertTrue(message = "变更状态不正确") - public boolean isStatusValid() { - return statusId != null || endStatus != null; - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusRespVO.java deleted file mode 100644 index a2ee1dfe5a..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusRespVO.java +++ /dev/null @@ -1,51 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.status; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.math.BigDecimal; -import java.time.LocalDateTime; -import java.util.List; - -@Schema(description = "管理后台 - 商机状态 Response VO") -@Data -public class CrmBusinessStatusRespVO { - - @Schema(description = "状态组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2934") - private Long id; - - @Schema(description = "状态组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") - private String name; - - @Schema(description = "使用的部门编号", requiredMode = Schema.RequiredMode.REQUIRED) - private List deptIds; - @Schema(description = "使用的部门名称", requiredMode = Schema.RequiredMode.REQUIRED) - private List deptNames; - - @Schema(description = "创建人", requiredMode = Schema.RequiredMode.REQUIRED) - private String creator; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime createTime; - - @Schema(description = "状态集合", requiredMode = Schema.RequiredMode.REQUIRED) - private List statuses; - - @Data - public static class Status { - - @Schema(description = "状态编号", example = "23899") - private Long id; - - @Schema(description = "状态名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") - private String name; - - @Schema(description = "赢单率", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") - private BigDecimal percent; - - @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer sort; - - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusSaveReqVO.java deleted file mode 100644 index 42d6620e90..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusSaveReqVO.java +++ /dev/null @@ -1,50 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.status; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import javax.validation.Valid; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.math.BigDecimal; -import java.util.List; - -@Schema(description = "管理后台 - 商机状态组新增/修改 Request VO") -@Data -public class CrmBusinessStatusSaveReqVO { - - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "2934") - private Long id; - - @Schema(description = "状态类型名", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") - @NotEmpty(message = "状态类型名不能为空") - private String name; - - @Schema(description = "使用的部门编号") - private List deptIds; - - @Schema(description = "商机状态集合", requiredMode = Schema.RequiredMode.REQUIRED) - @NotEmpty(message = "商机状态集合不能为空") - @Valid - private List statuses; - - @Data - public static class Status { - - @Schema(description = "状态编号", example = "23899") - private Long id; - - @Schema(description = "状态名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") - @NotEmpty(message = "状态名不能为空") - private String name; - - @Schema(description = "赢单率", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") - @NotNull(message = "赢单率不能为空") - private BigDecimal percent; - - @Schema(description = "排序", hidden = true, example = "1") - private Integer sort; - - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java deleted file mode 100644 index eeae08b985..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java +++ /dev/null @@ -1,173 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.clue; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -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.ip.core.utils.AreaUtils; -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueSaveReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransferReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; -import cn.iocoder.yudao.module.crm.service.clue.CrmClueService; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; -import cn.iocoder.yudao.module.system.api.dept.DeptApi; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletResponse; -import javax.validation.Valid; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; -import static java.util.Collections.singletonList; - -@Tag(name = "管理后台 - 线索") -@RestController -@RequestMapping("/crm/clue") -@Validated -public class CrmClueController { - - @Resource - private CrmClueService clueService; - @Resource - private CrmCustomerService customerService; - - @Resource - private AdminUserApi adminUserApi; - @Resource - private DeptApi deptApi; - - @PostMapping("/create") - @Operation(summary = "创建线索") - @PreAuthorize("@ss.hasPermission('crm:clue:create')") - public CommonResult createClue(@Valid @RequestBody CrmClueSaveReqVO createReqVO) { - return success(clueService.createClue(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新线索") - @PreAuthorize("@ss.hasPermission('crm:clue:update')") - public CommonResult updateClue(@Valid @RequestBody CrmClueSaveReqVO updateReqVO) { - clueService.updateClue(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除线索") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:clue:delete')") - public CommonResult deleteClue(@RequestParam("id") Long id) { - clueService.deleteClue(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得线索") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:clue:query')") - public CommonResult getClue(@RequestParam("id") Long id) { - CrmClueDO clue = clueService.getClue(id); - return success(buildClueDetail(clue)); - } - - private CrmClueRespVO buildClueDetail(CrmClueDO clue) { - if (clue == null) { - return null; - } - return buildClueDetailList(singletonList(clue)).get(0); - } - - @GetMapping("/page") - @Operation(summary = "获得线索分页") - @PreAuthorize("@ss.hasPermission('crm:clue:query')") - public CommonResult> getCluePage(@Valid CrmCluePageReqVO pageVO) { - PageResult pageResult = clueService.getCluePage(pageVO, getLoginUserId()); - return success(new PageResult<>(buildClueDetailList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出线索 Excel") - @PreAuthorize("@ss.hasPermission('crm:clue:export')") - @OperateLog(type = EXPORT) - public void exportClueExcel(@Valid CrmCluePageReqVO pageReqVO, HttpServletResponse response) throws IOException { - pageReqVO.setPageSize(PAGE_SIZE_NONE); - List list = clueService.getCluePage(pageReqVO, getLoginUserId()).getList(); - // 导出 Excel - ExcelUtils.write(response, "线索.xls", "数据", CrmClueRespVO.class, buildClueDetailList(list)); - } - - private List buildClueDetailList(List list) { - if (CollUtil.isEmpty(list)) { - return Collections.emptyList(); - } - // 1.1 获取客户列表 - Map customerMap = customerService.getCustomerMap( - convertSet(list, CrmClueDO::getCustomerId)); - // 1.2 获取创建人、负责人列表 - Map userMap = adminUserApi.getUserMap(convertListByFlatMap(list, - contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); - Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); - // 2. 转换成 VO - return BeanUtils.toBean(list, CrmClueRespVO.class, clueVO -> { - clueVO.setAreaName(AreaUtils.format(clueVO.getAreaId())); - // 2.1 设置客户名称 - MapUtils.findAndThen(customerMap, clueVO.getCustomerId(), customer -> clueVO.setCustomerName(customer.getName())); - // 2.2 设置创建人、负责人名称 - MapUtils.findAndThen(userMap, NumberUtils.parseLong(clueVO.getCreator()), - user -> clueVO.setCreatorName(user.getNickname())); - MapUtils.findAndThen(userMap, clueVO.getOwnerUserId(), user -> { - clueVO.setOwnerUserName(user.getNickname()); - MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> clueVO.setOwnerUserDeptName(dept.getName())); - }); - }); - } - - @PutMapping("/transfer") - @Operation(summary = "线索转移") - @PreAuthorize("@ss.hasPermission('crm:clue:update')") - public CommonResult transferClue(@Valid @RequestBody CrmClueTransferReqVO reqVO) { - clueService.transferClue(reqVO, getLoginUserId()); - return success(true); - } - - @PutMapping("/transform") - @Operation(summary = "线索转化为客户") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:clue:update')") - public CommonResult transformClue(@RequestParam("id") Long id) { - clueService.transformClue(id, getLoginUserId()); - return success(Boolean.TRUE); - } - - @GetMapping("/follow-count") - @Operation(summary = "获得分配给我的、待跟进的线索数量") - @PreAuthorize("@ss.hasPermission('crm:clue:query')") - public CommonResult getFollowClueCount() { - return success(clueService.getFollowClueCount(getLoginUserId())); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java deleted file mode 100644 index a63d946e9d..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -@Schema(description = "管理后台 - 线索分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class CrmCluePageReqVO extends PageParam { - - @Schema(description = "线索名称", example = "线索xxx") - private String name; - - @Schema(description = "转化状态", example = "2048") - private Boolean transformStatus; - - @Schema(description = "电话", example = "18000000000") - private String telephone; - - @Schema(description = "手机号", example = "18000000000") - private String mobile; - - @Schema(description = "场景类型", example = "1") - @InEnum(CrmSceneTypeEnum.class) - private Integer sceneType; // 场景类型,为 null 时则表示全部 - - @Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") - private Boolean pool; // null 则表示为不是公海数据 - - @Schema(description = "所属行业", example = "1") - private Integer industryId; - - @Schema(description = "客户等级", example = "1") - private Integer level; - - @Schema(description = "客户来源", example = "1") - private Integer source; - - @Schema(description = "跟进状态", example = "true") - private Boolean followUpStatus; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueRespVO.java deleted file mode 100644 index 56e5c25612..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueRespVO.java +++ /dev/null @@ -1,129 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; - -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; -import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; -import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.ToString; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - 线索 Response VO") -@Data -@ToString(callSuper = true) -@ExcelIgnoreUnannotated -public class CrmClueRespVO { - - @Schema(description = "编号,主键自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "10969") - @ExcelProperty("编号") - private Long id; - - @Schema(description = "线索名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "线索xxx") - @ExcelProperty("线索名称") - private String name; - - @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") - @ExcelProperty(value = "跟进状态", converter = DictConvert.class) - @DictFormat(DictTypeConstants.BOOLEAN_STRING) - private Boolean followUpStatus; - - @Schema(description = "最后跟进时间") - @ExcelProperty("最后跟进时间") - private LocalDateTime contactLastTime; - - @Schema(description = "最后跟进内容", example = "吃饭、睡觉、打逗逗") - @ExcelProperty("最后跟进内容") - private String contactLastContent; - - @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00") - @ExcelProperty("下次联系时间") - private LocalDateTime contactNextTime; - - @Schema(description = "负责人编号") - private Long ownerUserId; - @Schema(description = "负责人名字", example = "25682") - @ExcelProperty("负责人名字") - private String ownerUserName; - @Schema(description = "负责人部门") - @ExcelProperty("负责人部门") - private String ownerUserDeptName; - - @Schema(description = "转化状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") - @ExcelProperty(value = "转化状态", converter = DictConvert.class) - @DictFormat(DictTypeConstants.BOOLEAN_STRING) - private Boolean transformStatus; - - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "520") - private Long customerId; - @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "客户名称") - @ExcelProperty("客户名称") - private String customerName; - - @Schema(description = "手机号", example = "18000000000") - @ExcelProperty("手机号") - private String mobile; - - @Schema(description = "电话", example = "18000000000") - @ExcelProperty("电话") - private String telephone; - - @Schema(description = "QQ", example = "25682") - @ExcelProperty("QQ") - private String qq; - - @Schema(description = "wechat", example = "25682") - @ExcelProperty("wechat") - private String wechat; - - @Schema(description = "email", example = "25682") - @ExcelProperty("email") - private String email; - - @Schema(description = "地区编号", example = "1024") - @ExcelProperty("地区编号") - private Integer areaId; - @Schema(description = "地区名称", example = "北京市") - @ExcelProperty("地区名称") - private String areaName; - @Schema(description = "详细地址", example = "北京市成华大道") - @ExcelProperty("详细地址") - private String detailAddress; - - @Schema(description = "所属行业", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - @ExcelProperty(value = "所属行业", converter = DictConvert.class) - @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY) - private Integer industryId; - - @Schema(description = "客户等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - @ExcelProperty(value = "客户等级", converter = DictConvert.class) - @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_LEVEL) - private Integer level; - - @Schema(description = "客户来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - @ExcelProperty(value = "客户来源", converter = DictConvert.class) - @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_SOURCE) - private Integer source; - - @Schema(description = "备注", example = "随便") - @ExcelProperty("备注") - private String remark; - - @Schema(description = "创建人", example = "1024") - @ExcelProperty("创建人") - private String creator; - @Schema(description = "创建人名字", example = "芋道源码") - @ExcelProperty("创建人名字") - private String creatorName; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - - @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("更新时间") - private LocalDateTime updateTime; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueSaveReqVO.java deleted file mode 100644 index aff2ad1eb8..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueSaveReqVO.java +++ /dev/null @@ -1,109 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.framework.common.validation.Mobile; -import cn.iocoder.yudao.framework.common.validation.Telephone; -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; -import cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLevelEnum; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerIndustryParseFunction; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerLevelParseFunction; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerSourceParseFunction; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysAreaParseFunction; -import com.mzt.logapi.starter.annotation.DiffLogField; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; - -import javax.validation.constraints.Email; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; - -@Schema(description = "管理后台 - CRM 线索创建/更新 Request VO") -@Data -public class CrmClueSaveReqVO { - - @Schema(description = "编号", example = "10969") - private Long id; - - @Schema(description = "线索名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "线索xxx") - @DiffLogField(name = "线索名称") - @NotEmpty(message = "线索名称不能为空") - private String name; - - @Schema(description = "最后跟进时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @DiffLogField(name = "最后跟进时间") - private LocalDateTime contactLastTime; - - @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00") - @DiffLogField(name = "下次联系时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime contactNextTime; - - @Schema(description = "负责人编号", example = "2048") - @NotNull(message = "负责人编号不能为空") - private Long ownerUserId; - - @Schema(description = "手机号", example = "18000000000") - @DiffLogField(name = "手机号") - @Mobile - private String mobile; - - @Schema(description = "电话", example = "18000000000") - @DiffLogField(name = "电话") - @Telephone - private String telephone; - - @Schema(description = "QQ", example = "123456789") - @DiffLogField(name = "QQ") - @Size(max = 20, message = "QQ长度不能超过 20 个字符") - private String qq; - - @Schema(description = "微信", example = "123456789") - @DiffLogField(name = "微信") - @Size(max = 255, message = "微信长度不能超过 255 个字符") - private String wechat; - - @Schema(description = "邮箱", example = "123456789@qq.com") - @DiffLogField(name = "邮箱") - @Email(message = "邮箱格式不正确") - @Size(max = 255, message = "邮箱长度不能超过 255 个字符") - private String email; - - @Schema(description = "地区编号", example = "20158") - @DiffLogField(name = "地区编号", function = SysAreaParseFunction.NAME) - private Integer areaId; - - @Schema(description = "详细地址", example = "北京市海淀区") - @DiffLogField(name = "详细地址") - private String detailAddress; - - @Schema(description = "所属行业", example = "1") - @DiffLogField(name = "所属行业", function = CrmCustomerIndustryParseFunction.NAME) - @DictFormat(CRM_CUSTOMER_INDUSTRY) - private Integer industryId; - - @Schema(description = "客户等级", example = "2") - @DiffLogField(name = "客户等级", function = CrmCustomerLevelParseFunction.NAME) - @InEnum(CrmCustomerLevelEnum.class) - private Integer level; - - @Schema(description = "客户来源", example = "3") - @DiffLogField(name = "客户来源", function = CrmCustomerSourceParseFunction.NAME) - private Integer source; - - @Schema(description = "客户描述", example = "任意文字") - @DiffLogField(name = "客户描述") - @Size(max = 4096, message = "客户描述长度不能超过 4096 个字符") - private String description; - - @Schema(description = "备注", example = "随便") - @DiffLogField(name = "备注") - private String remark; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java deleted file mode 100644 index adf58a921f..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java +++ /dev/null @@ -1,227 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contact; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -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.ip.core.utils.AreaUtils; -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.*; -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.contact.CrmContactBusinessService; -import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; -import cn.iocoder.yudao.module.system.api.dept.DeptApi; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.extern.slf4j.Slf4j; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletResponse; -import javax.validation.Valid; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; -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; -import static java.util.Collections.singletonList; - -@Tag(name = "管理后台 - CRM 联系人") -@RestController -@RequestMapping("/crm/contact") -@Validated -@Slf4j -public class CrmContactController { - - @Resource - private CrmContactService contactService; - @Resource - private CrmCustomerService customerService; - @Resource - private CrmContactBusinessService contactBusinessLinkService; - - @Resource - private AdminUserApi adminUserApi; - @Resource - private DeptApi deptApi; - - @PostMapping("/create") - @Operation(summary = "创建联系人") - @PreAuthorize("@ss.hasPermission('crm:contact:create')") - public CommonResult createContact(@Valid @RequestBody CrmContactSaveReqVO createReqVO) { - return success(contactService.createContact(createReqVO, getLoginUserId())); - } - - @PutMapping("/update") - @Operation(summary = "更新联系人") - @OperateLog(enable = false) - @PreAuthorize("@ss.hasPermission('crm:contact:update')") - public CommonResult updateContact(@Valid @RequestBody CrmContactSaveReqVO updateReqVO) { - contactService.updateContact(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除联系人") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:contact:delete')") - public CommonResult deleteContact(@RequestParam("id") Long id) { - contactService.deleteContact(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得联系人") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:contact:query')") - public CommonResult getContact(@RequestParam("id") Long id) { - CrmContactDO contact = contactService.getContact(id); - return success(buildContactDetail(contact)); - } - - private CrmContactRespVO buildContactDetail(CrmContactDO contact) { - if (contact == null) { - return null; - } - return buildContactDetailList(singletonList(contact)).get(0); - } - - @GetMapping("/simple-all-list") - @Operation(summary = "获得联系人的精简列表") - @PreAuthorize("@ss.hasPermission('crm:contact:query')") - public CommonResult> getSimpleContactList() { - List list = contactService.getContactList(getLoginUserId()); - return success(convertList(list, contact -> // 只返回 id、name 字段 - new CrmContactRespVO().setId(contact.getId()).setName(contact.getName()) - .setCustomerId(contact.getCustomerId()))); - } - - @GetMapping("/page") - @Operation(summary = "获得联系人分页") - @PreAuthorize("@ss.hasPermission('crm:contact:query')") - public CommonResult> getContactPage(@Valid CrmContactPageReqVO pageVO) { - PageResult pageResult = contactService.getContactPage(pageVO, getLoginUserId()); - return success(new PageResult<>(buildContactDetailList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/page-by-customer") - @Operation(summary = "获得联系人分页,基于指定客户") - public CommonResult> getContactPageByCustomer(@Valid CrmContactPageReqVO pageVO) { - Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空"); - PageResult pageResult = contactService.getContactPageByCustomerId(pageVO); - return success(new PageResult<>(buildContactDetailList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/page-by-business") - @Operation(summary = "获得联系人分页,基于指定商机") - public CommonResult> getContactPageByBusiness(@Valid CrmContactPageReqVO pageVO) { - Assert.notNull(pageVO.getBusinessId(), "商机编号不能为空"); - PageResult pageResult = contactService.getContactPageByBusinessId(pageVO); - return success(new PageResult<>(buildContactDetailList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出联系人 Excel") - @PreAuthorize("@ss.hasPermission('crm:contact:export')") - @OperateLog(type = EXPORT) - public void exportContactExcel(@Valid CrmContactPageReqVO exportReqVO, - HttpServletResponse response) throws IOException { - exportReqVO.setPageNo(PAGE_SIZE_NONE); - List list = contactService.getContactPage(exportReqVO, getLoginUserId()).getList(); - ExcelUtils.write(response, "联系人.xls", "数据", CrmContactRespVO.class, buildContactDetailList(list)); - } - - private List buildContactDetailList(List contactList) { - if (CollUtil.isEmpty(contactList)) { - return Collections.emptyList(); - } - // 1.1 获取客户列表 - Map customerMap = customerService.getCustomerMap( - convertSet(contactList, CrmContactDO::getCustomerId)); - // 1.2 获取创建人、负责人列表 - Map userMap = adminUserApi.getUserMap(convertListByFlatMap(contactList, - contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); - Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); - // 1.3 直属上级 Map - Map parentContactMap = contactService.getContactMap( - convertSet(contactList, CrmContactDO::getParentId)); - // 2. 转换成 VO - return BeanUtils.toBean(contactList, CrmContactRespVO.class, contactVO -> { - contactVO.setAreaName(AreaUtils.format(contactVO.getAreaId())); - // 2.1 设置客户名称 - MapUtils.findAndThen(customerMap, contactVO.getCustomerId(), customer -> contactVO.setCustomerName(customer.getName())); - // 2.2 设置创建人、负责人名称 - MapUtils.findAndThen(userMap, NumberUtils.parseLong(contactVO.getCreator()), - user -> contactVO.setCreatorName(user.getNickname())); - MapUtils.findAndThen(userMap, contactVO.getOwnerUserId(), user -> { - contactVO.setOwnerUserName(user.getNickname()); - MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> contactVO.setOwnerUserDeptName(dept.getName())); - }); - // 2.3 设置直属上级名称 - findAndThen(parentContactMap, contactVO.getParentId(), contact -> contactVO.setParentName(contact.getName())); - }); - } - - @PutMapping("/transfer") - @Operation(summary = "联系人转移") - @PreAuthorize("@ss.hasPermission('crm:contact:update')") - public CommonResult transferContact(@Valid @RequestBody CrmContactTransferReqVO reqVO) { - contactService.transferContact(reqVO, getLoginUserId()); - return success(true); - } - - // ================== 关联/取关商机 =================== - - @PostMapping("/create-business-list") - @Operation(summary = "创建联系人与商机的关联") - @PreAuthorize("@ss.hasPermission('crm:contact:create-business')") - public CommonResult createContactBusinessList(@Valid @RequestBody CrmContactBusinessReqVO createReqVO) { - contactBusinessLinkService.createContactBusinessList(createReqVO); - return success(true); - } - - - @PostMapping("/create-business-list2") - @Operation(summary = "创建联系人与商机的关联") - @PreAuthorize("@ss.hasPermission('crm:contact:create-business')") - public CommonResult createContactBusinessList2(@Valid @RequestBody CrmContactBusiness2ReqVO createReqVO) { - contactBusinessLinkService.createContactBusinessList2(createReqVO); - return success(true); - } - - @DeleteMapping("/delete-business-list") - @Operation(summary = "删除联系人与联系人的关联") - @PreAuthorize("@ss.hasPermission('crm:contact:delete-business')") - public CommonResult deleteContactBusinessList(@Valid @RequestBody CrmContactBusinessReqVO deleteReqVO) { - contactBusinessLinkService.deleteContactBusinessList(deleteReqVO); - return success(true); - } - - @DeleteMapping("/delete-business-list2") - @Operation(summary = "删除联系人与联系人的关联") - @PreAuthorize("@ss.hasPermission('crm:contact:delete-business')") - public CommonResult deleteContactBusinessList(@Valid @RequestBody CrmContactBusiness2ReqVO deleteReqVO) { - contactBusinessLinkService.deleteContactBusinessList2(deleteReqVO); - return success(true); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusiness2ReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusiness2ReqVO.java deleted file mode 100644 index edc07bf962..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusiness2ReqVO.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.util.List; - -@Schema(description = "管理后台 - CRM 联系人商机 Request VO") // 【商机关联联系人】用于关联,取消关联的操作 -@Data -public class CrmContactBusiness2ReqVO { - - @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7638") - @NotNull(message="商机不能为空") - private Long businessId; - - @Schema(description = "联系人编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "20878") - @NotEmpty(message="联系人数组不能为空") - private List contactIds; - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusinessReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusinessReqVO.java deleted file mode 100644 index aaac18e43e..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusinessReqVO.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.util.List; - -@Schema(description = "管理后台 - CRM 联系人商机 Request VO") // 【联系人关联商机】用于关联,取消关联的操作 -@Data -public class CrmContactBusinessReqVO { - - @Schema(description = "联系人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20878") - @NotNull(message="联系人不能为空") - private Long contactId; - - @Schema(description = "商机编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "7638") - @NotEmpty(message="商机不能为空") - private List businessIds; - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactPageReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactPageReqVO.java deleted file mode 100644 index 6698a3855e..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactPageReqVO.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -@Schema(description = "管理后台 - CRM 联系人分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class CrmContactPageReqVO extends PageParam { - - @Schema(description = "姓名", example = "芋艿") - private String name; - - @Schema(description = "客户编号", example = "10795") - private Long customerId; - - @Schema(description = "手机号", example = "13898273941") - private String mobile; - - @Schema(description = "电话", example = "021-383773") - private String telephone; - - @Schema(description = "电子邮箱", example = "111@22.com") - private String email; - - @Schema(description = "QQ", example = "3882872") - private Long qq; - - @Schema(description = "微信", example = "zzZ98373") - private String wechat; - - @Schema(description = "场景类型", example = "1") - @InEnum(CrmSceneTypeEnum.class) - private Integer sceneType; // 场景类型,为 null 时则表示全部 - - @Schema(description = "商机编号", example = "10430") - private Long businessId; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactRespVO.java deleted file mode 100644 index b2b1e83848..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactRespVO.java +++ /dev/null @@ -1,122 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; - -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; -import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; -import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.ToString; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - CRM 联系人 Response VO") -@Data -@ToString(callSuper = true) -@ExcelIgnoreUnannotated -public class CrmContactRespVO { - - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "3167") - private Long id; - - @Schema(description = "联系人姓名", example = "芋艿") - @ExcelProperty(value = "联系人姓名", order = 1) - private String name; - - @Schema(description = "客户编号", example = "10795") - private Long customerId; - @ExcelProperty(value = "客户名称", order = 2) - @Schema(description = "客户名字", example = "test") - private String customerName; - - @Schema(description = "最后跟进时间") - @ExcelProperty(value = "最后跟进时间", order = 6) - private LocalDateTime contactLastTime; - - @Schema(description = "最后跟进内容") - @ExcelProperty(value = "最后跟进内容", order = 6) - private String contactLastContent; - - @Schema(description = "下次联系时间") - @ExcelProperty(value = "下次联系时间", order = 6) - private LocalDateTime contactNextTime; - - @Schema(description = "负责人编号") - private Long ownerUserId; - @Schema(description = "负责人名字", example = "25682") - @ExcelProperty("负责人名字") - private String ownerUserName; - @Schema(description = "负责人部门") - @ExcelProperty("负责人部门") - private String ownerUserDeptName; - - @Schema(description = "手机号", example = "1387171766") - @ExcelProperty(value = "手机号", order = 4) - private String mobile; - - @Schema(description = "电话", example = "021-0029922") - @ExcelProperty(value = "电话", order = 4) - private String telephone; - - @Schema(description = "电子邮箱", example = "1111@22.com") - @ExcelProperty(value = "邮箱", order = 4) - private String email; - - @Schema(description = "QQ", example = "197272662") - @ExcelProperty(value = "QQ", order = 4) - private Long qq; - - @Schema(description = "微信", example = "zzz3883") - @ExcelProperty(value = "微信", order = 4) - private String wechat; - - @Schema(description = "地区编号", example = "20158") - private Integer areaId; - @Schema(description = "地区名", example = "上海上海市浦东新区") - @ExcelProperty(value = "地区", order = 5) - private String areaName; - - @Schema(description = "地址") - @ExcelProperty(value = "地址", order = 5) - private String detailAddress; - - @Schema(description = "性别") - @ExcelProperty(value = "性别", converter = DictConvert.class, order = 3) - @DictFormat(cn.iocoder.yudao.module.system.enums.DictTypeConstants.USER_SEX) - private Integer sex; - - @Schema(description = "是否关键决策人") - @ExcelProperty(value = "是否关键决策人", converter = DictConvert.class, order = 3) - @DictFormat(DictTypeConstants.BOOLEAN_STRING) - private Boolean master; - - @Schema(description = "职位") - @ExcelProperty(value = "职位", order = 3) - private String post; - - @Schema(description = "直属上级", example = "23457") - private Long parentId; - @Schema(description = "直属上级名", example = "芋头") - @ExcelProperty(value = "直属上级", order = 4) - private String parentName; - - @Schema(description = "备注", example = "你说的对") - @ExcelProperty(value = "备注", order = 6) - private String remark; - - @Schema(description = "创建人", example = "25682") - private String creator; - @Schema(description = "创建人名字", example = "test") - @ExcelProperty(value = "创建人", order = 8) - private String creatorName; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - - @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("更新时间") - private LocalDateTime updateTime; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSaveReqVO.java deleted file mode 100644 index f16af86bfa..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSaveReqVO.java +++ /dev/null @@ -1,98 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; - -import cn.iocoder.yudao.framework.common.validation.Mobile; -import cn.iocoder.yudao.framework.common.validation.Telephone; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.*; -import com.mzt.logapi.starter.annotation.DiffLogField; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; - -import javax.validation.constraints.Email; -import javax.validation.constraints.NotNull; -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; - -@Schema(description = "管理后台 - CRM 联系人创建/更新 Request VO") -@Data -public class CrmContactSaveReqVO { - - @Schema(description = "主键", example = "3167") - private Long id; - - @Schema(description = "姓名", example = "芋艿") - @NotNull(message = "姓名不能为空") - @DiffLogField(name = "姓名") - private String name; - - @Schema(description = "客户编号", example = "10795") - @NotNull(message = "客户编号不能为空") - @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) - private Long customerId; - - @Schema(description = "下次联系时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) - @DiffLogField(name = "下次联系时间") - private LocalDateTime contactNextTime; - - @Schema(description = "负责人用户编号", example = "14334") - @NotNull(message = "负责人不能为空") - @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) - private Long ownerUserId; - - @Schema(description = "手机号", example = "1387171766") - @Mobile - @DiffLogField(name = "手机号") - private String mobile; - - @Schema(description = "电话", example = "021-0029922") - @Telephone - @DiffLogField(name = "电话") - private String telephone; - - @Schema(description = "QQ", example = "197272662") - @DiffLogField(name = "QQ") - private Long qq; - - @Schema(description = "微信", example = "zzz3883") - @DiffLogField(name = "微信") - private String wechat; - - @Schema(description = "电子邮箱", example = "1111@22.com") - @DiffLogField(name = "邮箱") - @Email - private String email; - - @Schema(description = "地区编号", example = "20158") - @DiffLogField(name = "所在地", function = SysAreaParseFunction.NAME) - private Integer areaId; - - @Schema(description = "地址") - @DiffLogField(name = "地址") - private String detailAddress; - - @Schema(description = "性别") - @DiffLogField(name = "性别", function = SysSexParseFunction.NAME) - private Integer sex; - - @Schema(description = "是否关键决策人") - @DiffLogField(name = "关键决策人", function = SysBooleanParseFunction.NAME) - private Boolean master; - - @Schema(description = "职位") - @DiffLogField(name = "职位") - private String post; - - @Schema(description = "直属上级", example = "23457") - @DiffLogField(name = "直属上级", function = CrmContactParseFunction.NAME) - private Long parentId; - - @Schema(description = "备注", example = "你说的对") - @DiffLogField(name = "备注") - private String remark; - - @Schema(description = "关联商机 ID", example = "122233") - private Long businessId; // 注意:该字段用于在【商机】详情界面「新建联系人」时,自动进行关联 - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractConfigController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractConfigController.java deleted file mode 100644 index 369260fcbc..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractConfigController.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contract; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config.CrmContractConfigRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config.CrmContractConfigSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractConfigDO; -import cn.iocoder.yudao.module.crm.service.contract.CrmContractConfigService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.validation.Valid; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - CRM 合同配置") -@RestController -@RequestMapping("/crm/contract-config") -@Validated -public class CrmContractConfigController { - - @Resource - private CrmContractConfigService contractConfigService; - - @GetMapping("/get") - @Operation(summary = "获取合同配置") - @PreAuthorize("@ss.hasPermission('crm:contract-config:query')") - public CommonResult getCustomerPoolConfig() { - CrmContractConfigDO config = contractConfigService.getContractConfig(); - return success(BeanUtils.toBean(config, CrmContractConfigRespVO.class)); - } - - @PutMapping("/save") - @Operation(summary = "更新合同配置") - @PreAuthorize("@ss.hasPermission('crm:contract-config:update')") - public CommonResult saveCustomerPoolConfig(@Valid @RequestBody CrmContractConfigSaveReqVO updateReqVO) { - contractConfigService.saveContractConfig(updateReqVO); - return success(true); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java deleted file mode 100644 index 5939fef4b4..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java +++ /dev/null @@ -1,256 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contract; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -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.contract.CrmContractPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractSaveReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.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.business.CrmBusinessService; -import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; -import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; -import cn.iocoder.yudao.module.crm.service.product.CrmProductService; -import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; -import cn.iocoder.yudao.module.system.api.dept.DeptApi; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletResponse; -import javax.validation.Valid; -import java.io.IOException; -import java.math.BigDecimal; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -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; -import static java.util.Collections.singletonList; - -@Tag(name = "管理后台 - CRM 合同") -@RestController -@RequestMapping("/crm/contract") -@Validated -public class CrmContractController { - - @Resource - private CrmContractService contractService; - @Resource - private CrmCustomerService customerService; - @Resource - private CrmContactService contactService; - @Resource - private CrmBusinessService businessService; - @Resource - private CrmProductService productService; - @Resource - private CrmReceivableService receivableService; - - @Resource - private AdminUserApi adminUserApi; - @Resource - private DeptApi deptApi; - - @PostMapping("/create") - @Operation(summary = "创建合同") - @PreAuthorize("@ss.hasPermission('crm:contract:create')") - public CommonResult createContract(@Valid @RequestBody CrmContractSaveReqVO createReqVO) { - return success(contractService.createContract(createReqVO, getLoginUserId())); - } - - @PutMapping("/update") - @Operation(summary = "更新合同") - @PreAuthorize("@ss.hasPermission('crm:contract:update')") - public CommonResult updateContract(@Valid @RequestBody CrmContractSaveReqVO updateReqVO) { - contractService.updateContract(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除合同") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:contract:delete')") - public CommonResult deleteContract(@RequestParam("id") Long id) { - contractService.deleteContract(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得合同") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:contract:query')") - public CommonResult getContract(@RequestParam("id") Long id) { - CrmContractDO contract = contractService.getContract(id); - return success(buildContractDetail(contract)); - } - - private CrmContractRespVO buildContractDetail(CrmContractDO contract) { - if (contract == null) { - return null; - } - CrmContractRespVO contractVO = buildContractDetailList(singletonList(contract)).get(0); - // 拼接产品项 - List businessProducts = contractService.getContractProductListByContractId(contractVO.getId()); - Map productMap = productService.getProductMap( - convertSet(businessProducts, CrmContractProductDO::getProductId)); - contractVO.setProducts(BeanUtils.toBean(businessProducts, CrmContractRespVO.Product.class, businessProductVO -> - MapUtils.findAndThen(productMap, businessProductVO.getProductId(), - product -> businessProductVO.setProductName(product.getName()) - .setProductNo(product.getNo()).setProductUnit(product.getUnit())))); - return contractVO; - } - - @GetMapping("/page") - @Operation(summary = "获得合同分页") - @PreAuthorize("@ss.hasPermission('crm:contract:query')") - public CommonResult> getContractPage(@Valid CrmContractPageReqVO pageVO) { - PageResult pageResult = contractService.getContractPage(pageVO, getLoginUserId()); - return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetailList(pageResult.getList()))); - } - - @GetMapping("/page-by-customer") - @Operation(summary = "获得合同分页,基于指定客户") - public CommonResult> getContractPageByCustomer(@Valid CrmContractPageReqVO pageVO) { - Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空"); - PageResult pageResult = contractService.getContractPageByCustomerId(pageVO); - return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetailList(pageResult.getList()))); - } - - @GetMapping("/page-by-business") - @Operation(summary = "获得合同分页,基于指定商机") - public CommonResult> getContractPageByBusiness(@Valid CrmContractPageReqVO pageVO) { - Assert.notNull(pageVO.getBusinessId(), "商机编号不能为空"); - PageResult pageResult = contractService.getContractPageByBusinessId(pageVO); - return success(BeanUtils.toBean(pageResult, CrmContractRespVO.class).setList(buildContractDetailList(pageResult.getList()))); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出合同 Excel") - @PreAuthorize("@ss.hasPermission('crm:contract:export')") - @OperateLog(type = EXPORT) - public void exportContractExcel(@Valid CrmContractPageReqVO exportReqVO, - HttpServletResponse response) throws IOException { - PageResult pageResult = contractService.getContractPage(exportReqVO, getLoginUserId()); - // 导出 Excel - ExcelUtils.write(response, "合同.xls", "数据", CrmContractRespVO.class, - BeanUtils.toBean(pageResult.getList(), CrmContractRespVO.class)); - } - - @PutMapping("/transfer") - @Operation(summary = "合同转移") - @PreAuthorize("@ss.hasPermission('crm:contract:update')") - public CommonResult transferContract(@Valid @RequestBody CrmContractTransferReqVO reqVO) { - contractService.transferContract(reqVO, getLoginUserId()); - return success(true); - } - - @PutMapping("/submit") - @Operation(summary = "提交合同审批") - @PreAuthorize("@ss.hasPermission('crm:contract:update')") - public CommonResult submitContract(@RequestParam("id") Long id) { - contractService.submitContract(id, getLoginUserId()); - return success(true); - } - - private List buildContractDetailList(List contractList) { - if (CollUtil.isEmpty(contractList)) { - return Collections.emptyList(); - } - // 1.1 获取客户列表 - Map customerMap = customerService.getCustomerMap( - convertSet(contractList, CrmContractDO::getCustomerId)); - // 1.2 获取创建人、负责人列表 - Map userMap = adminUserApi.getUserMap(convertListByFlatMap(contractList, - contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); - Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); - // 1.3 获取联系人 - Map contactMap = convertMap(contactService.getContactList(convertSet(contractList, - CrmContractDO::getSignContactId)), CrmContactDO::getId); - // 1.4 获取商机 - Map businessMap = businessService.getBusinessMap( - convertSet(contractList, CrmContractDO::getBusinessId)); - // 1.5 获得已回款金额 - Map receivablePriceMap = receivableService.getReceivablePriceMapByContractId( - convertSet(contractList, CrmContractDO::getId)); - // 2. 拼接数据 - return BeanUtils.toBean(contractList, CrmContractRespVO.class, contractVO -> { - // 2.1 设置客户信息 - findAndThen(customerMap, contractVO.getCustomerId(), customer -> contractVO.setCustomerName(customer.getName())); - // 2.2 设置用户信息 - findAndThen(userMap, Long.parseLong(contractVO.getCreator()), user -> contractVO.setCreatorName(user.getNickname())); - MapUtils.findAndThen(userMap, contractVO.getOwnerUserId(), user -> { - contractVO.setOwnerUserName(user.getNickname()); - MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> contractVO.setOwnerUserDeptName(dept.getName())); - }); - findAndThen(userMap, contractVO.getSignUserId(), user -> contractVO.setSignUserName(user.getNickname())); - // 2.3 设置联系人信息 - findAndThen(contactMap, contractVO.getSignContactId(), contact -> contractVO.setSignContactName(contact.getName())); - // 2.4 设置商机信息 - findAndThen(businessMap, contractVO.getBusinessId(), business -> contractVO.setBusinessName(business.getName())); - // 2.5 设置已回款金额 - contractVO.setTotalReceivablePrice(receivablePriceMap.getOrDefault(contractVO.getId(), BigDecimal.ZERO)); - }); - } - - @GetMapping("/audit-count") - @Operation(summary = "获得待审核合同数量") - @PreAuthorize("@ss.hasPermission('crm:contract:query')") - public CommonResult getAuditContractCount() { - return success(contractService.getAuditContractCount(getLoginUserId())); - } - - @GetMapping("/remind-count") - @Operation(summary = "获得即将到期(提醒)的合同数量") - @PreAuthorize("@ss.hasPermission('crm:contract:query')") - public CommonResult getRemindContractCount() { - return success(contractService.getRemindContractCount(getLoginUserId())); - } - - @GetMapping("/simple-list") - @Operation(summary = "获得合同精简列表", description = "只包含的合同,主要用于前端的下拉选项") - @Parameter(name = "customerId", description = "客户编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:contract:query')") - public CommonResult> getContractSimpleList(@RequestParam("customerId") Long customerId) { - CrmContractPageReqVO pageReqVO = new CrmContractPageReqVO().setCustomerId(customerId); - pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); // 不分页 - PageResult pageResult = contractService.getContractPageByCustomerId(pageReqVO); - if (CollUtil.isEmpty(pageResult.getList())) { - return success(Collections.emptyList()); - } - // 拼接数据 - Map receivablePriceMap = receivableService.getReceivablePriceMapByContractId( - convertSet(pageResult.getList(), CrmContractDO::getId)); - return success(convertList(pageResult.getList(), contract -> new CrmContractRespVO() // 只返回 id、name 等精简字段 - .setId(contract.getId()).setName(contract.getName()).setAuditStatus(contract.getAuditStatus()) - .setTotalPrice(contract.getTotalPrice()) - .setTotalReceivablePrice(receivablePriceMap.getOrDefault(contract.getId(), BigDecimal.ZERO)))); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigRespVO.java deleted file mode 100644 index c39cf92692..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigRespVO.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Schema(description = "管理后台 - CRM 合同配置 Response VO") -@Data -public class CrmContractConfigRespVO { - - @Schema(description = "是否开启提前提醒", example = "true") - private Boolean notifyEnabled; - - @Schema(description = "提前提醒天数", example = "2") - private Integer notifyDays; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigSaveReqVO.java deleted file mode 100644 index 2eb79d8e0a..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/config/CrmContractConfigSaveReqVO.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config; - -import cn.hutool.core.util.BooleanUtil; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.mzt.logapi.starter.annotation.DiffLogField; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import javax.validation.constraints.AssertTrue; -import java.util.Objects; - -@Schema(description = "管理后台 - CRM 合同配置 Request VO") -@Data -public class CrmContractConfigSaveReqVO { - - @Schema(description = "是否开启提前提醒", example = "true") - @DiffLogField(name = "是否开启提前提醒") - private Boolean notifyEnabled; - - @Schema(description = "提前提醒天数", example = "2") - @DiffLogField(name = "提前提醒天数") - private Integer notifyDays; - - @AssertTrue(message = "提前提醒天数不能为空") - @JsonIgnore - public boolean isNotifyDaysValid() { - if (!BooleanUtil.isTrue(getNotifyEnabled())) { - return true; - } - return Objects.nonNull(getNotifyDays()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractPageReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractPageReqVO.java deleted file mode 100644 index 74f8008b8f..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractPageReqVO.java +++ /dev/null @@ -1,50 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; -import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -@Schema(description = "管理后台 - CRM 合同分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class CrmContractPageReqVO extends PageParam { - - /** - * 过期类型 - 即将过期 - */ - public static final Integer EXPIRY_TYPE_ABOUT_TO_EXPIRE = 1; - /** - * 过期类型 - 已过期 - */ - public static final Integer EXPIRY_TYPE_EXPIRED = 2; - - @Schema(description = "合同编号", example = "XYZ008") - private String no; - - @Schema(description = "合同名称", example = "王五") - private String name; - - @Schema(description = "客户编号", example = "18336") - private Long customerId; - - @Schema(description = "商机编号", example = "10864") - private Long businessId; - - @Schema(description = "场景类型", example = "1") - @InEnum(CrmSceneTypeEnum.class) - private Integer sceneType; // 场景类型,为 null 时则表示全部 - - @Schema(description = "审批状态", example = "20") - @InEnum(CrmAuditStatusEnum.class) - private Integer auditStatus; - - @Schema(description = "过期类型", example = "1") - private Integer expiryType; // 过期类型,为 null 时则表示全部 - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java deleted file mode 100644 index a01bc110b9..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractRespVO.java +++ /dev/null @@ -1,162 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; - -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.math.BigDecimal; -import java.time.LocalDateTime; -import java.util.List; - -@Schema(description = "管理后台 - CRM 合同 Response VO") -@Data -@ExcelIgnoreUnannotated -public class CrmContractRespVO { - - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") - @ExcelProperty("合同编号") - private Long id; - - @Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") - @ExcelProperty("合同名称") - private String name; - - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20230101") - @ExcelProperty("合同编号") - private String no; - - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336") - @ExcelProperty("客户编号") - private Long customerId; - @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336") - @ExcelProperty("客户名称") - private String customerName; - - @Schema(description = "商机编号", example = "10864") - @ExcelProperty("商机编号") - private Long businessId; - @Schema(description = "商机名称", example = "10864") - @ExcelProperty("商机名称") - private String businessName; - - @Schema(description = "最后跟进时间") - @ExcelProperty("最后跟进时间") - private LocalDateTime contactLastTime; - - @Schema(description = "负责人的用户编号", example = "25682") - @ExcelProperty("负责人的用户编号") - private Long ownerUserId; - @Schema(description = "负责人名字", example = "25682") - @ExcelProperty("负责人名字") - private String ownerUserName; - @Schema(description = "负责人部门") - @ExcelProperty("负责人部门") - private String ownerUserDeptName; - - @Schema(description = "工作流编号", example = "1043") - @ExcelProperty("工作流编号") - private String processInstanceId; - - @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") - @ExcelProperty("审批状态") - private Integer auditStatus; - - @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("下单日期") - private LocalDateTime orderDate; - - @Schema(description = "开始时间") - @ExcelProperty("开始时间") - private LocalDateTime startTime; - - @Schema(description = "结束时间") - @ExcelProperty("结束时间") - private LocalDateTime endTime; - - @Schema(description = "产品总金额", example = "19510") - @ExcelProperty("产品总金额") - private BigDecimal totalProductPrice; - - @Schema(description = "整单折扣") - @ExcelProperty("整单折扣") - private BigDecimal discountPercent; - - @Schema(description = "合同金额", example = "5617") - @ExcelProperty("合同金额") - private BigDecimal totalPrice; - - @Schema(description = "已回款金额", example = "5617") - @ExcelProperty("已回款金额") - private BigDecimal totalReceivablePrice; - - @Schema(description = "客户签约人编号", example = "18546") - private Long signContactId; - @Schema(description = "客户签约人", example = "小豆") - @ExcelProperty("客户签约人") - private String signContactName; - - @Schema(description = "公司签约人", example = "14036") - private Long signUserId; - @Schema(description = "公司签约人", example = "小明") - @ExcelProperty("公司签约人") - private String signUserName; - - @Schema(description = "备注", example = "你猜") - @ExcelProperty("备注") - private String remark; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - - @Schema(description = "创建人", example = "25682") - @ExcelProperty("创建人") - private String creator; - - @Schema(description = "创建人名字", example = "test") - @ExcelProperty("创建人名字") - private String creatorName; - - @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("更新时间") - private LocalDateTime updateTime; - - @Schema(description = "产品列表") - private List products; - - @Schema(description = "产品列表") - @Data - @NoArgsConstructor - @AllArgsConstructor - public static class Product { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") - private Long id; - - @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") - private Long productId; - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") - private String productName; - @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") - private String productNo; - @Schema(description = "产品单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") - private Integer productUnit; - - @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") - private BigDecimal productPrice; - - @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") - private BigDecimal contractPrice; - - @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") - private BigDecimal count; - - @Schema(description = "总计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") - private BigDecimal totalPrice; - - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractSaveReqVO.java deleted file mode 100644 index 9e06296f0f..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractSaveReqVO.java +++ /dev/null @@ -1,111 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; - -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmBusinessParseFunction; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmContactParseFunction; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerParseFunction; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysAdminUserParseFunction; -import com.mzt.logapi.starter.annotation.DiffLogField; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.format.annotation.DateTimeFormat; - -import javax.validation.constraints.NotNull; -import java.math.BigDecimal; -import java.time.LocalDateTime; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -@Schema(description = "管理后台 - CRM 合同创建/更新 Request VO") -@Data -public class CrmContractSaveReqVO { - - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") - private Long id; - - @Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") - @DiffLogField(name = "合同名称") - @NotNull(message = "合同名称不能为空") - private String name; - - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18336") - @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) - @NotNull(message = "客户编号不能为空") - private Long customerId; - - @Schema(description = "商机编号", example = "10864") - @DiffLogField(name = "商机", function = CrmBusinessParseFunction.NAME) - private Long businessId; - - @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17144") - @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) - @NotNull(message = "负责人不能为空") - private Long ownerUserId; - - @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED) - @DiffLogField(name = "下单日期") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @NotNull(message = "下单日期不能为空") - private LocalDateTime orderDate; - - @Schema(description = "开始时间") - @DiffLogField(name = "开始时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime startTime; - - @Schema(description = "结束时间") - @DiffLogField(name = "结束时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime endTime; - - @Schema(description = "整单折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "55.00") - @DiffLogField(name = "整单折扣") - @NotNull(message = "整单折扣不能为空") - private BigDecimal discountPercent; - - @Schema(description = "合同金额", example = "5617") - @DiffLogField(name = "合同金额") - private BigDecimal totalPrice; - - @Schema(description = "客户签约人编号", example = "18546") - @DiffLogField(name = "客户签约人", function = CrmContactParseFunction.NAME) - private Long signContactId; - - @Schema(description = "公司签约人", example = "14036") - @DiffLogField(name = "公司签约人", function = SysAdminUserParseFunction.NAME) - private Long signUserId; - - @Schema(description = "备注", example = "你猜") - @DiffLogField(name = "备注") - private String remark; - - @Schema(description = "产品列表") - private List products; - - @Schema(description = "产品列表") - @Data - @NoArgsConstructor - @AllArgsConstructor - public static class Product { - - @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") - @NotNull(message = "产品编号不能为空") - private Long productId; - - @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") - @NotNull(message = "产品单价不能为空") - private BigDecimal productPrice; - - @Schema(description = "合同价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.00") - @NotNull(message = "合同价格不能为空") - private BigDecimal contractPrice; - - @Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") - @NotNull(message = "产品数量不能为空") - private Integer count; - - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractTransferReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractTransferReqVO.java deleted file mode 100644 index 57c9fe65a2..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/contract/CrmContractTransferReqVO.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import javax.validation.constraints.NotNull; - -@Schema(description = "管理后台 - CRM 合同转移 Request VO") -@Data -public class CrmContractTransferReqVO { - - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") - @NotNull(message = "联系人编号不能为空") - private Long id; - - @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") - @NotNull(message = "新负责人的用户编号不能为空") - private Long newOwnerUserId; - - @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @InEnum(value = CrmPermissionLevelEnum.class) - private Integer oldOwnerPermissionLevel; - -} 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 deleted file mode 100644 index d661f6366e..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java +++ /dev/null @@ -1,342 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.customer; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.map.MapUtil; -import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; -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.enums.ExcelColumn; -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.framework.ip.core.Area; -import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; -import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerPoolConfigService; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; -import cn.iocoder.yudao.module.system.api.dept.DeptApi; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; -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 org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletResponse; -import javax.validation.Valid; -import java.io.IOException; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; -import static java.util.Collections.singletonList; - -@Tag(name = "管理后台 - CRM 客户") -@RestController -@RequestMapping("/crm/customer") -@Validated -public class CrmCustomerController { - - @Resource - private CrmCustomerService customerService; - @Resource - private CrmCustomerPoolConfigService customerPoolConfigService; - - @Resource - private DeptApi deptApi; - @Resource - private AdminUserApi adminUserApi; - @Resource - private DictDataApi dictDataApi; - - @PostMapping("/create") - @Operation(summary = "创建客户") - @PreAuthorize("@ss.hasPermission('crm:customer:create')") - public CommonResult createCustomer(@Valid @RequestBody CrmCustomerSaveReqVO createReqVO) { - return success(customerService.createCustomer(createReqVO, getLoginUserId())); - } - - @PutMapping("/update") - @Operation(summary = "更新客户") - @PreAuthorize("@ss.hasPermission('crm:customer:update')") - public CommonResult updateCustomer(@Valid @RequestBody CrmCustomerSaveReqVO updateReqVO) { - customerService.updateCustomer(updateReqVO); - return success(true); - } - - @PutMapping("/update-deal-status") - @Operation(summary = "更新客户的成交状态") - @Parameters({ - @Parameter(name = "id", description = "客户编号", required = true), - @Parameter(name = "dealStatus", description = "成交状态", required = true) - }) - public CommonResult updateCustomerDealStatus(@RequestParam("id") Long id, - @RequestParam("dealStatus") Boolean dealStatus) { - customerService.updateCustomerDealStatus(id, dealStatus); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除客户") - @Parameter(name = "id", description = "客户编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:customer:delete')") - public CommonResult deleteCustomer(@RequestParam("id") Long id) { - customerService.deleteCustomer(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得客户") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:customer:query')") - public CommonResult getCustomer(@RequestParam("id") Long id) { - // 1. 获取客户 - CrmCustomerDO customer = customerService.getCustomer(id); - // 2. 拼接数据 - return success(buildCustomerDetail(customer)); - } - - public CrmCustomerRespVO buildCustomerDetail(CrmCustomerDO customer) { - if (customer == null) { - return null; - } - return buildCustomerDetailList(singletonList(customer)).get(0); - } - - @GetMapping("/page") - @Operation(summary = "获得客户分页") - @PreAuthorize("@ss.hasPermission('crm:customer:query')") - public CommonResult> getCustomerPage(@Valid CrmCustomerPageReqVO pageVO) { - // 1. 查询客户分页 - PageResult pageResult = customerService.getCustomerPage(pageVO, getLoginUserId()); - if (CollUtil.isEmpty(pageResult.getList())) { - return success(PageResult.empty(pageResult.getTotal())); - } - // 2. 拼接数据 - return success(new PageResult<>(buildCustomerDetailList(pageResult.getList()), pageResult.getTotal())); - } - - public List buildCustomerDetailList(List list) { - if (CollUtil.isEmpty(list)) { - return java.util.Collections.emptyList(); - } - // 1.1 获取创建人、负责人列表 - Map userMap = adminUserApi.getUserMap(convertListByFlatMap(list, - contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); - Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); - // 1.2 获取距离进入公海的时间 - Map poolDayMap = getPoolDayMap(list); - // 2. 转换成 VO - return BeanUtils.toBean(list, CrmCustomerRespVO.class, customerVO -> { - customerVO.setAreaName(AreaUtils.format(customerVO.getAreaId())); - // 2.1 设置创建人、负责人名称 - MapUtils.findAndThen(userMap, NumberUtils.parseLong(customerVO.getCreator()), - user -> customerVO.setCreatorName(user.getNickname())); - MapUtils.findAndThen(userMap, customerVO.getOwnerUserId(), user -> { - customerVO.setOwnerUserName(user.getNickname()); - MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> customerVO.setOwnerUserDeptName(dept.getName())); - }); - // 2.2 设置距离进入公海的时间 - if (customerVO.getOwnerUserId() != null) { - customerVO.setPoolDay(poolDayMap.get(customerVO.getId())); - } - }); - } - - @GetMapping("/put-pool-remind-page") - @Operation(summary = "获得待进入公海客户分页") - @PreAuthorize("@ss.hasPermission('crm:customer:query')") - public CommonResult> getPutPoolRemindCustomerPage(@Valid CrmCustomerPageReqVO pageVO) { - // 1. 查询客户分页 - PageResult pageResult = customerService.getPutPoolRemindCustomerPage(pageVO, getLoginUserId()); - // 2. 拼接数据 - return success(new PageResult<>(buildCustomerDetailList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/put-pool-remind-count") - @Operation(summary = "获得待进入公海客户数量") - @PreAuthorize("@ss.hasPermission('crm:customer:query')") - public CommonResult getPutPoolRemindCustomerCount() { - return success(customerService.getPutPoolRemindCustomerCount(getLoginUserId())); - } - - @GetMapping("/today-contact-count") - @Operation(summary = "获得今日需联系客户数量") - @PreAuthorize("@ss.hasPermission('crm:customer:query')") - public CommonResult getTodayContactCustomerCount() { - return success(customerService.getTodayContactCustomerCount(getLoginUserId())); - } - - @GetMapping("/follow-count") - @Operation(summary = "获得分配给我、待跟进的线索数量的客户数量") - @PreAuthorize("@ss.hasPermission('crm:customer:query')") - public CommonResult getFollowCustomerCount() { - return success(customerService.getFollowCustomerCount(getLoginUserId())); - } - - /** - * 获取距离进入公海的时间 Map - * - * @param list 客户列表 - * @return key 客户编号, value 距离进入公海的时间 - */ - private Map getPoolDayMap(List list) { - CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig(); - if (poolConfig == null || !poolConfig.getEnabled()) { - return MapUtil.empty(); - } - list = CollectionUtils.filterList(list, customer -> { - // 特殊:如果没负责人,则说明已经在公海,不用计算 - if (customer.getOwnerUserId() == null) { - return false; - } - // 已成交 or 已锁定,不进入公海 - return !customer.getDealStatus() && !customer.getLockStatus(); - }); - return convertMap(list, CrmCustomerDO::getId, customer -> { - // 1.1 未成交放入公海天数 - long dealExpireDay = poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getOwnerTime()); - // 1.2 未跟进放入公海天数 - LocalDateTime lastTime = customer.getOwnerTime(); - if (customer.getContactLastTime() != null && customer.getContactLastTime().isAfter(lastTime)) { - lastTime = customer.getContactLastTime(); - } - long contactExpireDay = poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime); - // 2. 返回最小的天数 - long poolDay = Math.min(dealExpireDay, contactExpireDay); - return poolDay > 0 ? poolDay : 0; - }); - } - - @GetMapping(value = "/simple-list") - @Operation(summary = "获取客户精简信息列表", description = "只包含有读权限的客户,主要用于前端的下拉选项") - public CommonResult> getCustomerSimpleList() { - CrmCustomerPageReqVO reqVO = new CrmCustomerPageReqVO(); - reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 - List list = customerService.getCustomerPage(reqVO, getLoginUserId()).getList(); - return success(convertList(list, customer -> // 只返回 id、name 精简字段 - new CrmCustomerRespVO().setId(customer.getId()).setName(customer.getName()))); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出客户 Excel") - @PreAuthorize("@ss.hasPermission('crm:customer:export')") - @OperateLog(type = EXPORT) - public void exportCustomerExcel(@Valid CrmCustomerPageReqVO pageVO, - HttpServletResponse response) throws IOException { - pageVO.setPageSize(PAGE_SIZE_NONE); // 不分页 - List list = customerService.getCustomerPage(pageVO, getLoginUserId()).getList(); - // 导出 Excel - ExcelUtils.write(response, "客户.xls", "数据", CrmCustomerRespVO.class, - buildCustomerDetailList(list)); - } - - @GetMapping("/get-import-template") - @Operation(summary = "获得导入客户模板") - public void importTemplate(HttpServletResponse response) throws IOException { - // 手动创建导出 demo - List list = Arrays.asList( - CrmCustomerImportExcelVO.builder().name("芋道").industryId(1).level(1).source(1) - .mobile("15601691300").telephone("").qq("").wechat("").email("yunai@iocoder.cn") - .areaId(null).detailAddress("").remark("").build(), - CrmCustomerImportExcelVO.builder().name("源码").industryId(1).level(1).source(1) - .mobile("15601691300").telephone("").qq("").wechat("").email("yunai@iocoder.cn") - .areaId(null).detailAddress("").remark("").build() - ); - // 输出 - ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list, builderSelectMap()); - } - - private List>> builderSelectMap() { - List>> selectMap = new ArrayList<>(); - // 获取地区下拉数据 - // TODO @puhui999:嘿嘿,这里改成省份、城市、区域,三个选项,难度大么? - Area area = AreaUtils.getArea(Area.ID_CHINA); - selectMap.add(new KeyValue<>(ExcelColumn.G, AreaUtils.getAreaNodePathList(area.getChildren()))); - // 获取客户所属行业 - List customerIndustries = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_INDUSTRY); - selectMap.add(new KeyValue<>(ExcelColumn.I, customerIndustries)); - // 获取客户等级 - List customerLevels = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_LEVEL); - selectMap.add(new KeyValue<>(ExcelColumn.J, customerLevels)); - // 获取客户来源 - List customerSources = dictDataApi.getDictDataLabelList(CRM_CUSTOMER_SOURCE); - selectMap.add(new KeyValue<>(ExcelColumn.K, customerSources)); - return selectMap; - } - - @PostMapping("/import") - @Operation(summary = "导入客户") - @PreAuthorize("@ss.hasPermission('system:customer:import')") - public CommonResult importExcel(@Valid @RequestBody CrmCustomerImportReqVO importReqVO) - throws Exception { - List list = ExcelUtils.read(importReqVO.getFile(), CrmCustomerImportExcelVO.class); - return success(customerService.importCustomerList(list, importReqVO)); - } - - @PutMapping("/transfer") - @Operation(summary = "转移客户") - @PreAuthorize("@ss.hasPermission('crm:customer:update')") - public CommonResult transferCustomer(@Valid @RequestBody CrmCustomerTransferReqVO reqVO) { - customerService.transferCustomer(reqVO, getLoginUserId()); - return success(true); - } - - @PutMapping("/lock") - @Operation(summary = "锁定/解锁客户") - @PreAuthorize("@ss.hasPermission('crm:customer:update')") - public CommonResult lockCustomer(@Valid @RequestBody CrmCustomerLockReqVO lockReqVO) { - customerService.lockCustomer(lockReqVO, getLoginUserId()); - return success(true); - } - - // ==================== 公海相关操作 ==================== - - @PutMapping("/put-pool") - @Operation(summary = "数据放入公海") - @Parameter(name = "id", description = "客户编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:customer:update')") - public CommonResult putCustomerPool(@RequestParam("id") Long id) { - customerService.putCustomerPool(id); - return success(true); - } - - @PutMapping("/receive") - @Operation(summary = "领取公海客户") - @Parameter(name = "ids", description = "编号数组", required = true, example = "1,2,3") - @PreAuthorize("@ss.hasPermission('crm:customer:receive')") - public CommonResult receiveCustomer(@RequestParam(value = "ids") List ids) { - customerService.receiveCustomer(ids, getLoginUserId(), Boolean.TRUE); - return success(true); - } - - @PutMapping("/distribute") - @Operation(summary = "分配公海给对应负责人") - @PreAuthorize("@ss.hasPermission('crm:customer:distribute')") - public CommonResult distributeCustomer(@Valid @RequestBody CrmCustomerDistributeReqVO distributeReqVO) { - customerService.receiveCustomer(distributeReqVO.getIds(), distributeReqVO.getOwnerUserId(), Boolean.FALSE); - return success(true); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerLimitConfigController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerLimitConfigController.java deleted file mode 100644 index 82a326c054..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerLimitConfigController.java +++ /dev/null @@ -1,104 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.customer; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -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.customer.vo.limitconfig.CrmCustomerLimitConfigPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerLimitConfigService; -import cn.iocoder.yudao.module.system.api.dept.DeptApi; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.validation.Valid; -import java.util.Collection; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; - -@Tag(name = "管理后台 - CRM 客户限制配置") -@RestController -@RequestMapping("/crm/customer-limit-config") -@Validated -public class CrmCustomerLimitConfigController { - - @Resource - private CrmCustomerLimitConfigService customerLimitConfigService; - - @Resource - private DeptApi deptApi; - @Resource - private AdminUserApi adminUserApi; - - @PostMapping("/create") - @Operation(summary = "创建客户限制配置") - @PreAuthorize("@ss.hasPermission('crm:customer-limit-config:create')") - public CommonResult createCustomerLimitConfig(@Valid @RequestBody CrmCustomerLimitConfigSaveReqVO createReqVO) { - return success(customerLimitConfigService.createCustomerLimitConfig(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新客户限制配置") - @PreAuthorize("@ss.hasPermission('crm:customer-limit-config:update')") - public CommonResult updateCustomerLimitConfig(@Valid @RequestBody CrmCustomerLimitConfigSaveReqVO updateReqVO) { - customerLimitConfigService.updateCustomerLimitConfig(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除客户限制配置") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:customer-limit-config:delete')") - public CommonResult deleteCustomerLimitConfig(@RequestParam("id") Long id) { - customerLimitConfigService.deleteCustomerLimitConfig(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得客户限制配置") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:customer-limit-config:query')") - public CommonResult getCustomerLimitConfig(@RequestParam("id") Long id) { - CrmCustomerLimitConfigDO limitConfig = customerLimitConfigService.getCustomerLimitConfig(id); - // 拼接数据 - Map userMap = adminUserApi.getUserMap(limitConfig.getUserIds()); - Map deptMap = deptApi.getDeptMap(limitConfig.getDeptIds()); - return success(BeanUtils.toBean(limitConfig, CrmCustomerLimitConfigRespVO.class, configVO -> { - configVO.setUsers(CollectionUtils.convertList(configVO.getUserIds(), userMap::get)); - configVO.setDepts(CollectionUtils.convertList(configVO.getDeptIds(), deptMap::get)); - })); - } - - @GetMapping("/page") - @Operation(summary = "获得客户限制配置分页") - @PreAuthorize("@ss.hasPermission('crm:customer-limit-config:query')") - public CommonResult> getCustomerLimitConfigPage(@Valid CrmCustomerLimitConfigPageReqVO pageVO) { - PageResult pageResult = customerLimitConfigService.getCustomerLimitConfigPage(pageVO); - if (CollUtil.isEmpty(pageResult.getList())) { - return success(PageResult.empty(pageResult.getTotal())); - } - // 拼接数据 - Map userMap = adminUserApi.getUserMap( - convertSetByFlatMap(pageResult.getList(), CrmCustomerLimitConfigDO::getUserIds, Collection::stream)); - Map deptMap = deptApi.getDeptMap( - convertSetByFlatMap(pageResult.getList(), CrmCustomerLimitConfigDO::getDeptIds, Collection::stream)); - return success(BeanUtils.toBean(pageResult, CrmCustomerLimitConfigRespVO.class, configVO -> { - configVO.setUsers(CollectionUtils.convertList(configVO.getUserIds(), userMap::get)); - configVO.setDepts(CollectionUtils.convertList(configVO.getDeptIds(), deptMap::get)); - })); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerDistributeReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerDistributeReqVO.java deleted file mode 100644 index 4f8b0d4e86..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerDistributeReqVO.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.util.List; - -@Schema(description = "管理后台 - CRM 客户分配公海给对应负责人 Request VO") -@Data -public class CrmCustomerDistributeReqVO { - - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1024]") - @NotEmpty(message = "客户编号不能为空") - private List ids; - - @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @NotNull(message = "负责人不能为空") - private Long ownerUserId; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java deleted file mode 100644 index 2c39472fd6..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java +++ /dev/null @@ -1,64 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; - -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; -import cn.iocoder.yudao.framework.excel.core.convert.AreaConvert; -import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; -import com.alibaba.excel.annotation.ExcelProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; - -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; - -/** - * 客户 Excel 导入 VO - */ -@Data -@Builder -@AllArgsConstructor -@NoArgsConstructor -@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题 -public class CrmCustomerImportExcelVO { - - @ExcelProperty("客户名称") - private String name; - - @ExcelProperty("手机") - private String mobile; - - @ExcelProperty("电话") - private String telephone; - - @ExcelProperty("QQ") - private String qq; - - @ExcelProperty("微信") - private String wechat; - - @ExcelProperty("邮箱") - private String email; - - @ExcelProperty(value = "地区", converter = AreaConvert.class) - private Integer areaId; - - @ExcelProperty("详细地址") - private String detailAddress; - - @ExcelProperty(value = "所属行业", converter = DictConvert.class) - @DictFormat(CRM_CUSTOMER_INDUSTRY) - private Integer industryId; - - @ExcelProperty(value = "客户等级", converter = DictConvert.class) - @DictFormat(CRM_CUSTOMER_LEVEL) - private Integer level; - - @ExcelProperty(value = "客户来源", converter = DictConvert.class) - @DictFormat(CRM_CUSTOMER_SOURCE) - private Integer source; - - @ExcelProperty("备注") - private String remark; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportReqVO.java deleted file mode 100644 index bbf7163935..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportReqVO.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Data; -import org.springframework.web.multipart.MultipartFile; - -import javax.validation.constraints.NotNull; - -@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 则客户进入公海 - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportRespVO.java deleted file mode 100644 index dda5bc5d11..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportRespVO.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -import lombok.Data; - -import java.util.List; -import java.util.Map; - -@Schema(description = "管理后台 - 客户导入 Response VO") -@Data -@Builder -public class CrmCustomerImportRespVO { - - @Schema(description = "创建成功的客户名数组", requiredMode = Schema.RequiredMode.REQUIRED) - private List createCustomerNames; - - @Schema(description = "更新成功的客户名数组", requiredMode = Schema.RequiredMode.REQUIRED) - private List updateCustomerNames; - - @Schema(description = "导入失败的客户集合,key 为客户名,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED) - private Map failureCustomerNames; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerLockReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerLockReqVO.java deleted file mode 100644 index 10bf2e10af..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerLockReqVO.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Schema(description = "管理后台 - CRM 客户锁定/解锁 Request VO") -@Data -public class CrmCustomerLockReqVO { - - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - private Long id; - - @Schema(description = "客户锁定状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") - private Boolean lockStatus; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerPageReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerPageReqVO.java deleted file mode 100644 index 73af5d6b13..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerPageReqVO.java +++ /dev/null @@ -1,58 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -@Schema(description = "管理后台 - CRM 客户分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class CrmCustomerPageReqVO extends PageParam { - - /** - * 联系状态 - 今日需联系 - */ - public static final int CONTACT_TODAY = 1; - /** - * 联系状态 - 已逾期 - */ - public static final int CONTACT_EXPIRED = 2; - /** - * 联系状态 - 已联系 - */ - public static final int CONTACT_ALREADY = 3; - - @Schema(description = "客户名称", example = "赵六") - private String name; - - @Schema(description = "手机", example = "18000000000") - private String mobile; - - @Schema(description = "所属行业", example = "1") - private Integer industryId; - - @Schema(description = "客户等级", example = "1") - private Integer level; - - @Schema(description = "客户来源", example = "1") - private Integer source; - - @Schema(description = "场景类型", example = "1") - @InEnum(CrmSceneTypeEnum.class) - private Integer sceneType; // 场景类型,为 null 时则表示全部 - - @Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") - private Boolean pool; // null 则表示为不是公海数据 - - @Schema(description = "联系状态", example = "1") - private Integer contactStatus; // backlog 查询条件 - - @Schema(description = "跟进状态", example = "true") - private Boolean followUpStatus; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerRespVO.java deleted file mode 100644 index 236129918c..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerRespVO.java +++ /dev/null @@ -1,130 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; - -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; -import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; -import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - CRM 客户 Response VO") -@Data -@ExcelIgnoreUnannotated -public class CrmCustomerRespVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - @ExcelProperty("编号") - private Long id; - - @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - @ExcelProperty("客户名称") - private String name; - - @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - @ExcelProperty(value = "跟进状态", converter = DictConvert.class) - @DictFormat(DictTypeConstants.BOOLEAN_STRING) - private Boolean followUpStatus; - - @Schema(description = "最后跟进时间") - @ExcelProperty("最后跟进时间") - private LocalDateTime contactLastTime; - - @Schema(description = "最后跟进内容", example = "吃饭、睡觉、打逗逗") - @ExcelProperty("最后跟进内容") - private String contactLastContent; - - @Schema(description = "下次联系时间") - @ExcelProperty("下次联系时间") - private LocalDateTime contactNextTime; - - @Schema(description = "负责人的用户编号", example = "25682") - @ExcelProperty("负责人的用户编号") - private Long ownerUserId; - @Schema(description = "负责人名字", example = "25682") - @ExcelProperty("负责人名字") - private String ownerUserName; - @Schema(description = "负责人部门") - @ExcelProperty("负责人部门") - private String ownerUserDeptName; - - @Schema(description = "锁定状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - @ExcelProperty(value = "锁定状态", converter = DictConvert.class) - @DictFormat(DictTypeConstants.BOOLEAN_STRING) - private Boolean lockStatus; - - @Schema(description = "成交状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - @ExcelProperty(value = "成交状态", converter = DictConvert.class) - @DictFormat(DictTypeConstants.BOOLEAN_STRING) - private Boolean dealStatus; - - @Schema(description = "手机", example = "25682") - @ExcelProperty("手机") - private String mobile; - - @Schema(description = "电话", example = "25682") - @ExcelProperty("电话") - private String telephone; - - @Schema(description = "QQ", example = "25682") - @ExcelProperty("QQ") - private String qq; - - @Schema(description = "wechat", example = "25682") - @ExcelProperty("wechat") - private String wechat; - - @Schema(description = "email", example = "25682") - @ExcelProperty("email") - private String email; - - @Schema(description = "地区编号", example = "1024") - @ExcelProperty("地区编号") - private Integer areaId; - @Schema(description = "地区名称", example = "北京市") - @ExcelProperty("地区名称") - private String areaName; - @Schema(description = "详细地址", example = "北京市成华大道") - @ExcelProperty("详细地址") - private String detailAddress; - - @Schema(description = "所属行业", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - @ExcelProperty(value = "所属行业", converter = DictConvert.class) - @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY) - private Integer industryId; - - @Schema(description = "客户等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - @ExcelProperty(value = "客户等级", converter = DictConvert.class) - @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_LEVEL) - private Integer level; - - @Schema(description = "客户来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - @ExcelProperty(value = "客户来源", converter = DictConvert.class) - @DictFormat(cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_SOURCE) - private Integer source; - - @Schema(description = "负责人的用户编号", example = "25682") - @ExcelProperty("备注") - private String remark; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - - @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("更新时间") - private LocalDateTime updateTime; - - @Schema(description = "创建人", example = "1024") - @ExcelProperty("创建人") - private String creator; - @Schema(description = "创建人名字", example = "芋道源码") - @ExcelProperty("创建人名字") - private String creatorName; - - @Schema(description = "距离加入公海时间", example = "1") - private Long poolDay; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerSaveReqVO.java deleted file mode 100644 index daedb78300..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerSaveReqVO.java +++ /dev/null @@ -1,99 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.framework.common.validation.Mobile; -import cn.iocoder.yudao.framework.common.validation.Telephone; -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; -import cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLevelEnum; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerIndustryParseFunction; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerLevelParseFunction; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerSourceParseFunction; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysAreaParseFunction; -import com.mzt.logapi.starter.annotation.DiffLogField; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; - -import javax.validation.constraints.Email; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; - -@Schema(description = "管理后台 - CRM 客户新增/修改 Request VO") -@Data -public class CrmCustomerSaveReqVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - private Long id; - - @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") - @DiffLogField(name = "客户名称") - @NotEmpty(message = "客户名称不能为空") - private String name; - - @Schema(description = "下次联系时间") - @DiffLogField(name = "下次联系时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime contactNextTime; - - @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - @NotNull(message = "负责人的用户编号不能为空") - private Long ownerUserId; - - @Schema(description = "手机", example = "18000000000") - @DiffLogField(name = "手机") - @Mobile - private String mobile; - - @Schema(description = "电话", example = "18000000000") - @DiffLogField(name = "电话") - @Telephone - private String telephone; - - @Schema(description = "QQ", example = "123456789") - @DiffLogField(name = "QQ") - @Size(max = 20, message = "QQ长度不能超过 20 个字符") - private String qq; - - @Schema(description = "微信", example = "123456789") - @DiffLogField(name = "微信") - @Size(max = 255, message = "微信长度不能超过 255 个字符") - private String wechat; - - @Schema(description = "邮箱", example = "123456789@qq.com") - @DiffLogField(name = "邮箱") - @Email(message = "邮箱格式不正确") - @Size(max = 255, message = "邮箱长度不能超过 255 个字符") - private String email; - - @Schema(description = "地区编号", example = "20158") - @DiffLogField(name = "地区编号", function = SysAreaParseFunction.NAME) - private Integer areaId; - - @Schema(description = "详细地址", example = "北京市海淀区") - @DiffLogField(name = "详细地址") - private String detailAddress; - - @Schema(description = "所属行业", example = "1") - @DiffLogField(name = "所属行业", function = CrmCustomerIndustryParseFunction.NAME) - @DictFormat(CRM_CUSTOMER_INDUSTRY) - private Integer industryId; - - @Schema(description = "客户等级", example = "2") - @DiffLogField(name = "客户等级", function = CrmCustomerLevelParseFunction.NAME) - @InEnum(CrmCustomerLevelEnum.class) - private Integer level; - - @Schema(description = "客户来源", example = "3") - @DiffLogField(name = "客户来源", function = CrmCustomerSourceParseFunction.NAME) - private Integer source; - - @Schema(description = "备注", example = "随便") - @DiffLogField(name = "备注") - private String remark; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java deleted file mode 100644 index fb6bed0798..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer; - -import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import javax.validation.constraints.NotNull; - -@Schema(description = "管理后台 - CRM 客户转移 Request VO") -@Data -public class CrmCustomerTransferReqVO { - - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") - @NotNull(message = "客户编号不能为空") - private Long id; - - /** - * 新负责人的用户编号 - */ - @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") - @NotNull(message = "新负责人的用户编号不能为空") - private Long newOwnerUserId; - - /** - * 老负责人加入团队后的权限级别。如果 null 说明移除 - * - * 关联 {@link CrmPermissionLevelEnum} - */ - @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Integer oldOwnerPermissionLevel; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java deleted file mode 100644 index c36c572e51..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java +++ /dev/null @@ -1,105 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.followup; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordSaveReqVO; -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.followup.CrmFollowUpRecordDO; -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.followup.CrmFollowUpRecordService; -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.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.validation.Valid; -import java.util.ArrayList; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; - - -@Tag(name = "管理后台 - 跟进记录") -@RestController -@RequestMapping("/crm/follow-up-record") -@Validated -public class CrmFollowUpRecordController { - - @Resource - private CrmFollowUpRecordService followUpRecordService; - @Resource - private CrmContactService contactService; - @Resource - private CrmBusinessService businessService; - - @Resource - private AdminUserApi adminUserApi; - - @PostMapping("/create") - @Operation(summary = "创建跟进记录") - @PreAuthorize("@ss.hasPermission('crm:follow-up-record:create')") - public CommonResult createFollowUpRecord(@Valid @RequestBody CrmFollowUpRecordSaveReqVO createReqVO) { - return success(followUpRecordService.createFollowUpRecord(createReqVO)); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除跟进记录") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:follow-up-record:delete')") - public CommonResult deleteFollowUpRecord(@RequestParam("id") Long id) { - followUpRecordService.deleteFollowUpRecord(id, getLoginUserId()); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得跟进记录") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:follow-up-record:query')") - public CommonResult getFollowUpRecord(@RequestParam("id") Long id) { - CrmFollowUpRecordDO followUpRecord = followUpRecordService.getFollowUpRecord(id); - return success(BeanUtils.toBean(followUpRecord, CrmFollowUpRecordRespVO.class)); - } - - @GetMapping("/page") - @Operation(summary = "获得跟进记录分页") - @PreAuthorize("@ss.hasPermission('crm:follow-up-record:query')") - public CommonResult> getFollowUpRecordPage(@Valid CrmFollowUpRecordPageReqVO pageReqVO) { - PageResult pageResult = followUpRecordService.getFollowUpRecordPage(pageReqVO); - // 1.1 查询联系人和商机 - Map contactMap = contactService.getContactMap( - convertSetByFlatMap(pageResult.getList(), item -> item.getContactIds().stream())); - Map businessMap = businessService.getBusinessMap( - convertSetByFlatMap(pageResult.getList(), item -> item.getBusinessIds().stream())); - // 1.2 查询用户 - Map userMap = adminUserApi.getUserMap( - convertSet(pageResult.getList(), item -> Long.valueOf(item.getCreator()))); - // 2. 拼接数据 - PageResult voPageResult = BeanUtils.toBean(pageResult, CrmFollowUpRecordRespVO.class, record -> { - // 2.1 设置联系人和商机信息 - record.setBusinesses(new ArrayList<>()).setContacts(new ArrayList<>()); - record.getContactIds().forEach(id -> MapUtils.findAndThen(contactMap, id, contact -> - record.getContacts().add(new CrmBusinessRespVO().setId(contact.getId()).setName(contact.getName())))); - record.getContactIds().forEach(id -> MapUtils.findAndThen(businessMap, id, business -> - record.getBusinesses().add(new CrmBusinessRespVO().setId(business.getId()).setName(business.getName())))); - // 2.2 设置用户信息 - MapUtils.findAndThen(userMap, Long.valueOf(record.getCreator()), user -> record.setCreatorName(user.getNickname())); - }); - return success(voPageResult); - } - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordRespVO.java deleted file mode 100644 index 1ce10b73e3..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/vo/CrmFollowUpRecordRespVO.java +++ /dev/null @@ -1,64 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.followup.vo; - -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; -import java.util.List; - -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_FOLLOW_UP_TYPE; - -@Schema(description = "管理后台 - 跟进记录 Response VO") -@Data -@ExcelIgnoreUnannotated -public class CrmFollowUpRecordRespVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28800") - private Long id; - - @Schema(description = "数据类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Integer bizType; - - @Schema(description = "数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5564") - private Long bizId; - - @Schema(description = "跟进类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @DictFormat(CRM_FOLLOW_UP_TYPE) - private Integer type; - - @Schema(description = "跟进内容", requiredMode = Schema.RequiredMode.REQUIRED) - private String content; - - @Schema(description = "下次联系时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime nextTime; - - @Schema(description = "关联的商机编号数组") - private List businessIds; - @Schema(description = "关联的商机数组") - private List businesses; - - @Schema(description = "关联的联系人编号数组") - private List contactIds; - @Schema(description = "关联的联系人名称数组") - private List contacts; - - @Schema(description = "图片") - private List picUrls; - @Schema(description = "附件") - private List fileUrls; - - @Schema(description = "创建人", example = "1024") - @ExcelProperty("创建人") - private String creator; - @Schema(description = "创建人名字", example = "芋道源码") - @ExcelProperty("创建人名字") - private String creatorName; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime createTime; - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java deleted file mode 100644 index fa49076f8d..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/CrmOperateLogController.java +++ /dev/null @@ -1,64 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.operatelog; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo.CrmOperateLogPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo.CrmOperateLogRespVO; -import cn.iocoder.yudao.module.crm.enums.LogRecordConstants; -import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; -import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; -import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2PageReqDTO; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; -import javax.validation.Valid; -import java.util.HashMap; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; -import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; - -@Tag(name = "管理后台 - CRM 操作日志") -@RestController -@RequestMapping("/crm/operate-log") -@Validated -public class CrmOperateLogController { - - @Resource - private OperateLogApi operateLogApi; - - /** - * {@link CrmBizTypeEnum} 与 {@link LogRecordConstants} 的映射关系 - */ - private static final Map BIZ_TYPE_MAP = new HashMap<>(); - - static { - BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CLUE.getType(), CRM_CLUE_TYPE); - BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CUSTOMER.getType(), CRM_CUSTOMER_TYPE); - BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CONTACT.getType(), CRM_CONTACT_TYPE); - BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_BUSINESS.getType(), CRM_BUSINESS_TYPE); - BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_CONTRACT.getType(), CRM_CONTRACT_TYPE); - BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_PRODUCT.getType(), CRM_PRODUCT_TYPE); - BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_RECEIVABLE.getType(), CRM_RECEIVABLE_TYPE); - BIZ_TYPE_MAP.put(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), CRM_RECEIVABLE_PLAN_TYPE); - } - - @GetMapping("/page") - @Operation(summary = "获得操作日志") - @PreAuthorize("@ss.hasPermission('crm:operate-log:query')") - public CommonResult> getCustomerOperateLog(@Valid CrmOperateLogPageReqVO pageReqVO) { - OperateLogV2PageReqDTO reqDTO = new OperateLogV2PageReqDTO(); - reqDTO.setPageSize(PAGE_SIZE_NONE); // 默认不分页,需要分页需注释 - reqDTO.setBizType(BIZ_TYPE_MAP.get(pageReqVO.getBizType())).setBizId(pageReqVO.getBizId()); - return success(BeanUtils.toBean(operateLogApi.getOperateLogPage(reqDTO), CrmOperateLogRespVO.class)); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/vo/CrmOperateLogRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/vo/CrmOperateLogRespVO.java deleted file mode 100644 index 8e458a8a0f..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/operatelog/vo/CrmOperateLogRespVO.java +++ /dev/null @@ -1,44 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.operatelog.vo; - -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - CRM 操作日志 Response VO") -@Data -@ExcelIgnoreUnannotated -public class CrmOperateLogRespVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - private Long id; - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private Long userId; - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") - private String userName; - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer userType; - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - private String type; - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "修改客户") - private String subType; - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563") - private Long bizId; - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "将什么从什么改为了什么") - private String action; - - @Schema(description = "编号", example = "{orderId: 1}") - private String extra; - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-01-01") - private LocalDateTime createTime; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java deleted file mode 100644 index 51d0a0a571..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java +++ /dev/null @@ -1,135 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.permission; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionCreateReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; -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.permission.CrmPermissionService; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; -import cn.iocoder.yudao.module.system.api.dept.DeptApi; -import cn.iocoder.yudao.module.system.api.dept.PostApi; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import com.google.common.collect.Multimaps; -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 org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.validation.Valid; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; -import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; - -@Tag(name = "管理后台 - CRM 数据权限") -@RestController -@RequestMapping("/crm/permission") -@Validated -public class CrmPermissionController { - - @Resource - private CrmPermissionService permissionService; - - @Resource - private AdminUserApi adminUserApi; - @Resource - private DeptApi deptApi; - @Resource - private PostApi postApi; - - @PostMapping("/create") - @Operation(summary = "创建数据权限") - @PreAuthorize("@ss.hasPermission('crm:permission:create')") - @CrmPermission(bizTypeValue = "#reqVO.bizType", bizId = "#reqVO.bizId", level = CrmPermissionLevelEnum.OWNER) - public CommonResult addPermission(@Valid @RequestBody CrmPermissionCreateReqVO reqVO) { - permissionService.createPermission(BeanUtils.toBean(reqVO, CrmPermissionCreateReqBO.class)); - return success(true); - } - - @PutMapping("/update") - @Operation(summary = "编辑数据权限") - @PreAuthorize("@ss.hasPermission('crm:permission:update')") - @CrmPermission(bizTypeValue = "#updateReqVO.bizType", bizId = "#updateReqVO.bizId" - , level = CrmPermissionLevelEnum.OWNER) - public CommonResult updatePermission(@Valid @RequestBody CrmPermissionUpdateReqVO updateReqVO) { - permissionService.updatePermission(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除数据权限") - @Parameter(name = "ids", description = "数据权限编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:permission:delete')") - public CommonResult deletePermission(@RequestParam("ids") Collection ids) { - permissionService.deletePermissionBatch(ids, getLoginUserId()); - return success(true); - } - - @DeleteMapping("/delete-self") - @Operation(summary = "删除自己的数据权限") - @Parameter(name = "id", description = "数据权限编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:permission:delete')") - public CommonResult deleteSelfPermission(@RequestParam("id") Long id) { - permissionService.deleteSelfPermission(id, getLoginUserId()); - return success(true); - } - - @GetMapping("/list") - @Operation(summary = "获得数据权限列表") - @Parameters({ - @Parameter(name = "bizType", description = "CRM 类型", required = true, example = "2"), - @Parameter(name = "bizId", description = "CRM 类型数据编号", required = true, example = "1024") - }) - @PreAuthorize("@ss.hasPermission('crm:permission:query')") - public CommonResult> getPermissionList(@RequestParam("bizType") Integer bizType, - @RequestParam("bizId") Long bizId) { - List permissions = permissionService.getPermissionListByBiz(bizType, bizId); - if (CollUtil.isEmpty(permissions)) { - return success(Collections.emptyList()); - } - - // 查询相关数据 - Map userMap = adminUserApi.getUserMap( - convertSet(permissions, CrmPermissionDO::getUserId)); - Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); - Map postMap = postApi.getPostMap( - convertSetByFlatMap(userMap.values(), AdminUserRespDTO::getPostIds, - item -> item != null ? item.stream() : Stream.empty())); - // 拼接数据 - return success(CollectionUtils.convertList(BeanUtils.toBean(permissions, CrmPermissionRespVO.class), item -> { - findAndThen(userMap, item.getUserId(), user -> { - item.setNickname(user.getNickname()); - findAndThen(deptMap, user.getDeptId(), deptRespDTO -> item.setDeptName(deptRespDTO.getName())); - if (CollUtil.isEmpty(user.getPostIds())) { - item.setPostNames(Collections.emptySet()); - return; - } - List postList = MapUtils.getList(Multimaps.forMap(postMap), user.getPostIds()); - item.setPostNames(CollectionUtils.convertSet(postList, PostRespDTO::getName)); - }); - return item; - })); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java deleted file mode 100644 index f6f17da4ce..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/CrmProductController.java +++ /dev/null @@ -1,145 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.product; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -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.product.vo.product.CrmProductPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; -import cn.iocoder.yudao.module.crm.service.product.CrmProductCategoryService; -import cn.iocoder.yudao.module.crm.service.product.CrmProductService; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletResponse; -import javax.validation.Valid; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; -import static java.util.Collections.singletonList; - -@Tag(name = "管理后台 - CRM 产品") -@RestController -@RequestMapping("/crm/product") -@Validated -public class CrmProductController { - - @Resource - private CrmProductService productService; - @Resource - private CrmProductCategoryService productCategoryService; - - @Resource - private AdminUserApi adminUserApi; - - @PostMapping("/create") - @Operation(summary = "创建产品") - @PreAuthorize("@ss.hasPermission('crm:product:create')") - public CommonResult createProduct(@Valid @RequestBody CrmProductSaveReqVO createReqVO) { - return success(productService.createProduct(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新产品") - @PreAuthorize("@ss.hasPermission('crm:product:update')") - public CommonResult updateProduct(@Valid @RequestBody CrmProductSaveReqVO updateReqVO) { - productService.updateProduct(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除产品") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:product:delete')") - public CommonResult deleteProduct(@RequestParam("id") Long id) { - productService.deleteProduct(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得产品") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:product:query')") - public CommonResult getProduct(@RequestParam("id") Long id) { - CrmProductDO product = productService.getProduct(id); - return success(buildProductDetail(product)); - } - - private CrmProductRespVO buildProductDetail(CrmProductDO product) { - if (product == null) { - return null; - } - return buildProductDetailList(singletonList(product)).get(0); - } - - @GetMapping("/simple-list") - @Operation(summary = "获得产品精简列表", description = "只包含被开启的产品,主要用于前端的下拉选项") - public CommonResult> getProductSimpleList() { - List list = productService.getProductListByStatus(CommonStatusEnum.ENABLE.getStatus()); - return success(convertList(list, product -> new CrmProductRespVO().setId(product.getId()).setName(product.getName()) - .setUnit(product.getUnit()).setNo(product.getNo()).setPrice(product.getPrice()))); - } - - @GetMapping("/page") - @Operation(summary = "获得产品分页") - @PreAuthorize("@ss.hasPermission('crm:product:query')") - public CommonResult> getProductPage(@Valid CrmProductPageReqVO pageVO) { - PageResult pageResult = productService.getProductPage(pageVO); - return success(new PageResult<>(buildProductDetailList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出产品 Excel") - @PreAuthorize("@ss.hasPermission('crm:product:export')") - @OperateLog(type = EXPORT) - public void exportProductExcel(@Valid CrmProductPageReqVO exportReqVO, - HttpServletResponse response) throws IOException { - exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = productService.getProductPage(exportReqVO).getList(); - // 导出 Excel - ExcelUtils.write(response, "产品.xls", "数据", CrmProductRespVO.class, - buildProductDetailList(list)); - } - - private List buildProductDetailList(List list) { - if (CollUtil.isEmpty(list)) { - return Collections.emptyList(); - } - // 1.1 获得用户信息 - Map userMap = adminUserApi.getUserMap( - convertSetByFlatMap(list, user -> Stream.of(Long.valueOf(user.getCreator()), user.getOwnerUserId()))); - // 1.2 获得分类信息 - Map categoryMap = productCategoryService.getProductCategoryMap( - convertSet(list, CrmProductDO::getCategoryId)); - // 2. 拼接数据 - return BeanUtils.toBean(list, CrmProductRespVO.class, productVO -> { - // 2.1 设置用户信息 - MapUtils.findAndThen(userMap, productVO.getOwnerUserId(), user -> productVO.setOwnerUserName(user.getNickname())); - MapUtils.findAndThen(userMap, Long.valueOf(productVO.getCreator()), user -> productVO.setCreatorName(user.getNickname())); - // 2.2 设置分类名称 - MapUtils.findAndThen(categoryMap, productVO.getCategoryId(), category -> productVO.setCategoryName(category.getName())); - }); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductRespVO.java deleted file mode 100644 index 1f659aa77f..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductRespVO.java +++ /dev/null @@ -1,75 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.product.vo.product; - -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; -import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; -import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; -import com.alibaba.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - CRM 产品 Response VO") -@Data -@ExcelIgnoreUnannotated -public class CrmProductRespVO { - - @Schema(description = "产品编号", example = "20529") - @ExcelProperty("产品编号") - private Long id; - - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "好产品") - @ExcelProperty("产品名称") - private String name; - - @Schema(description = "产品编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "12306") - @ExcelProperty("产品编码") - private String no; - - @Schema(description = "单位", example = "2") - @ExcelProperty(value = "单位", converter = DictConvert.class) - @DictFormat(DictTypeConstants.CRM_PRODUCT_UNIT) - private Integer unit; - - @Schema(description = "价格, 单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") - @ExcelProperty("价格,单位:分") - private BigDecimal price; - - @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "上架") - @ExcelProperty(value = "单位", converter = DictConvert.class) - @DictFormat(DictTypeConstants.CRM_PRODUCT_STATUS) - private Integer status; - - @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Long categoryId; - @Schema(description = "产品分类名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "衣服") - @ExcelProperty("产品分类") - private String categoryName; - - @Schema(description = "产品描述", example = "你说的对") - @ExcelProperty("产品描述") - private String description; - - @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31926") - private Long ownerUserId; - @Schema(description = "负责人的用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") - @ExcelProperty("负责人") - private String ownerUserName; - - @Schema(description = "创建人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private String creator; - @Schema(description = "创建人名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") - @ExcelProperty("创建人") - private String creatorName; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - - @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("更新时间") - private LocalDateTime updateTime; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductSaveReqVO.java deleted file mode 100644 index 1c1a660677..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/product/vo/product/CrmProductSaveReqVO.java +++ /dev/null @@ -1,56 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.product.vo.product; - -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmProductStatusParseFunction; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmProductUnitParseFunction; -import com.mzt.logapi.starter.annotation.DiffLogField; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import javax.validation.constraints.NotNull; -import java.math.BigDecimal; - -@Schema(description = "管理后台 - CRM 产品创建/修改 Request VO") -@Data -public class CrmProductSaveReqVO { - - @Schema(description = "产品编号", example = "20529") - private Long id; - - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "好产品") - @NotNull(message = "产品名称不能为空") - @DiffLogField(name = "产品名称") - private String name; - - @Schema(description = "产品编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "12306") - @NotNull(message = "产品编码不能为空") - @DiffLogField(name = "产品编码") - private String no; - - @Schema(description = "单位", example = "2") - @DiffLogField(name = "单位", function = CrmProductUnitParseFunction.NAME) - private Integer unit; - - @Schema(description = "价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911") - @NotNull(message = "价格不能为空") - @DiffLogField(name = "价格") - private BigDecimal price; - - @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "上架") - @NotNull(message = "状态不能为空") - @DiffLogField(name = "状态", function = CrmProductStatusParseFunction.NAME) - private Integer status; - - @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @NotNull(message = "产品分类编号不能为空") - @DiffLogField(name = "产品分类编号") - private Long categoryId; - - @Schema(description = "产品描述", example = "你说的对") - @DiffLogField(name = "产品描述") - private String description; - - @Schema(description = "负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31926") - @NotNull(message = "负责人的用户编号不能为空") - private Long ownerUserId; - -} 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 deleted file mode 100644 index af1e08c037..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java +++ /dev/null @@ -1,182 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.receivable; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -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.contract.CrmContractRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; -import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; -import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; -import cn.iocoder.yudao.module.system.api.dept.DeptApi; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletResponse; -import javax.validation.Valid; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; -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; - -@Tag(name = "管理后台 - CRM 回款") -@RestController -@RequestMapping("/crm/receivable") -@Validated -public class CrmReceivableController { - - @Resource - private CrmReceivableService receivableService; - @Resource - private CrmContractService contractService; - @Resource - private CrmCustomerService customerService; - - @Resource - private AdminUserApi adminUserApi; - @Resource - private DeptApi deptApi; - - @PostMapping("/create") - @Operation(summary = "创建回款") - @PreAuthorize("@ss.hasPermission('crm:receivable:create')") - public CommonResult createReceivable(@Valid @RequestBody CrmReceivableSaveReqVO createReqVO) { - return success(receivableService.createReceivable(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新回款") - @PreAuthorize("@ss.hasPermission('crm:receivable:update')") - public CommonResult updateReceivable(@Valid @RequestBody CrmReceivableSaveReqVO updateReqVO) { - receivableService.updateReceivable(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除回款") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:receivable:delete')") - public CommonResult deleteReceivable(@RequestParam("id") Long id) { - receivableService.deleteReceivable(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得回款") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:receivable:query')") - public CommonResult getReceivable(@RequestParam("id") Long id) { - CrmReceivableDO receivable = receivableService.getReceivable(id); - return success(buildReceivableDetail(receivable)); - } - - private CrmReceivableRespVO buildReceivableDetail(CrmReceivableDO receivable) { - if (receivable == null) { - return null; - } - return buildReceivableDetailList(Collections.singletonList(receivable)).get(0); - } - - @GetMapping("/page") - @Operation(summary = "获得回款分页") - @PreAuthorize("@ss.hasPermission('crm:receivable:query')") - public CommonResult> getReceivablePage(@Valid CrmReceivablePageReqVO pageReqVO) { - PageResult pageResult = receivableService.getReceivablePage(pageReqVO, getLoginUserId()); - return success(new PageResult<>(buildReceivableDetailList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/page-by-customer") - @Operation(summary = "获得回款分页,基于指定客户") - public CommonResult> getReceivablePageByCustomer(@Valid CrmReceivablePageReqVO pageReqVO) { - Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空"); - PageResult pageResult = receivableService.getReceivablePageByCustomerId(pageReqVO); - return success(new PageResult<>(buildReceivableDetailList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出回款 Excel") - @PreAuthorize("@ss.hasPermission('crm:receivable:export')") - @OperateLog(type = EXPORT) - public void exportReceivableExcel(@Valid CrmReceivablePageReqVO exportReqVO, - HttpServletResponse response) throws IOException { - exportReqVO.setPageSize(PAGE_SIZE_NONE); - List list = receivableService.getReceivablePage(exportReqVO, getLoginUserId()).getList(); - // 导出 Excel - ExcelUtils.write(response, "回款.xls", "数据", CrmReceivableRespVO.class, - buildReceivableDetailList(list)); - } - - private List buildReceivableDetailList(List receivableList) { - if (CollUtil.isEmpty(receivableList)) { - return Collections.emptyList(); - } - // 1.1 获取客户列表 - Map customerMap = customerService.getCustomerMap( - convertSet(receivableList, CrmReceivableDO::getCustomerId)); - // 1.2 获取创建人、负责人列表 - Map userMap = adminUserApi.getUserMap(convertListByFlatMap(receivableList, - contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); - Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); - // 1.3 获得合同列表 - Map contractMap = contractService.getContractMap( - convertSet(receivableList, CrmReceivableDO::getContractId)); - // 2. 拼接结果 - return BeanUtils.toBean(receivableList, CrmReceivableRespVO.class, (receivableVO) -> { - // 2.1 拼接客户名称 - findAndThen(customerMap, receivableVO.getCustomerId(), customer -> receivableVO.setCustomerName(customer.getName())); - // 2.2 拼接负责人、创建人名称 - MapUtils.findAndThen(userMap, NumberUtils.parseLong(receivableVO.getCreator()), - user -> receivableVO.setCreatorName(user.getNickname())); - MapUtils.findAndThen(userMap, receivableVO.getOwnerUserId(), user -> { - receivableVO.setOwnerUserName(user.getNickname()); - MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> receivableVO.setOwnerUserDeptName(dept.getName())); - }); - // 2.3 拼接合同信息 - findAndThen(contractMap, receivableVO.getContractId(), contract -> - receivableVO.setContract(BeanUtils.toBean(contract, CrmContractRespVO.class))); - }); - } - - @PutMapping("/submit") - @Operation(summary = "提交回款审批") - @PreAuthorize("@ss.hasPermission('crm:receivable:update')") - public CommonResult submitContract(@RequestParam("id") Long id) { - receivableService.submitReceivable(id, getLoginUserId()); - return success(true); - } - - @GetMapping("/audit-count") - @Operation(summary = "获得待审核回款数量") - @PreAuthorize("@ss.hasPermission('crm:receivable:query')") - public CommonResult getAuditReceivableCount() { - return success(receivableService.getAuditReceivableCount(getLoginUserId())); - } - -} 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 deleted file mode 100644 index 5c9f852309..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java +++ /dev/null @@ -1,190 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.receivable; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -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.receivable.vo.plan.CrmReceivablePlanPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanSaveReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; -import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; -import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivablePlanService; -import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; -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 org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletResponse; -import javax.validation.Valid; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; -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; - -@Tag(name = "管理后台 - CRM 回款计划") -@RestController -@RequestMapping("/crm/receivable-plan") -@Validated -public class CrmReceivablePlanController { - - @Resource - private CrmReceivablePlanService receivablePlanService; - @Resource - private CrmReceivableService receivableService; - @Resource - private CrmContractService contractService; - @Resource - private CrmCustomerService customerService; - - @Resource - private AdminUserApi adminUserApi; - - @PostMapping("/create") - @Operation(summary = "创建回款计划") - @PreAuthorize("@ss.hasPermission('crm:receivable-plan:create')") - public CommonResult createReceivablePlan(@Valid @RequestBody CrmReceivablePlanSaveReqVO createReqVO) { - return success(receivablePlanService.createReceivablePlan(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新回款计划") - @PreAuthorize("@ss.hasPermission('crm:receivable-plan:update')") - public CommonResult updateReceivablePlan(@Valid @RequestBody CrmReceivablePlanSaveReqVO updateReqVO) { - receivablePlanService.updateReceivablePlan(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除回款计划") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('crm:receivable-plan:delete')") - public CommonResult deleteReceivablePlan(@RequestParam("id") Long id) { - receivablePlanService.deleteReceivablePlan(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得回款计划") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") - public CommonResult getReceivablePlan(@RequestParam("id") Long id) { - CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(id); - return success(buildReceivablePlanDetail(receivablePlan)); - } - - private CrmReceivablePlanRespVO buildReceivablePlanDetail(CrmReceivablePlanDO receivablePlan) { - if (receivablePlan == null) { - return null; - } - return buildReceivableDetailList(Collections.singletonList(receivablePlan)).get(0); - } - - @GetMapping("/page") - @Operation(summary = "获得回款计划分页") - @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") - public CommonResult> getReceivablePlanPage(@Valid CrmReceivablePlanPageReqVO pageReqVO) { - PageResult pageResult = receivablePlanService.getReceivablePlanPage(pageReqVO, getLoginUserId()); - return success(new PageResult<>(buildReceivableDetailList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/page-by-customer") - @Operation(summary = "获得回款计划分页,基于指定客户") - public CommonResult> getReceivablePlanPageByCustomer(@Valid CrmReceivablePlanPageReqVO pageReqVO) { - Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空"); - PageResult pageResult = receivablePlanService.getReceivablePlanPageByCustomerId(pageReqVO); - return success(new PageResult<>(buildReceivableDetailList(pageResult.getList()), pageResult.getTotal())); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出回款计划 Excel") - @PreAuthorize("@ss.hasPermission('crm:receivable-plan:export')") - @OperateLog(type = EXPORT) - public void exportReceivablePlanExcel(@Valid CrmReceivablePlanPageReqVO exportReqVO, - HttpServletResponse response) throws IOException { - exportReqVO.setPageSize(PAGE_SIZE_NONE); - List list = receivablePlanService.getReceivablePlanPage(exportReqVO, getLoginUserId()).getList(); - // 导出 Excel - ExcelUtils.write(response, "回款计划.xls", "数据", CrmReceivablePlanRespVO.class, - buildReceivableDetailList(list)); - } - - private List buildReceivableDetailList(List receivablePlanList) { - if (CollUtil.isEmpty(receivablePlanList)) { - return Collections.emptyList(); - } - // 1.1 获取客户 Map - Map customerMap = customerService.getCustomerMap( - convertSet(receivablePlanList, CrmReceivablePlanDO::getCustomerId)); - // 1.2 获取创建人、负责人列表 - Map userMap = adminUserApi.getUserMap(convertListByFlatMap(receivablePlanList, - contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); - // 1.3 获得合同 Map - Map contractMap = contractService.getContractMap( - convertSet(receivablePlanList, CrmReceivablePlanDO::getContractId)); - // 1.4 获得回款 Map - Map receivableMap = receivableService.getReceivableMap( - convertSet(receivablePlanList, CrmReceivablePlanDO::getReceivableId)); - // 2. 拼接数据 - return BeanUtils.toBean(receivablePlanList, CrmReceivablePlanRespVO.class, (receivablePlanVO) -> { - // 2.1 拼接客户信息 - findAndThen(customerMap, receivablePlanVO.getCustomerId(), customer -> receivablePlanVO.setCustomerName(customer.getName())); - // 2.2 拼接用户信息 - findAndThen(userMap, receivablePlanVO.getOwnerUserId(), user -> receivablePlanVO.setOwnerUserName(user.getNickname())); - findAndThen(userMap, Long.parseLong(receivablePlanVO.getCreator()), user -> receivablePlanVO.setCreatorName(user.getNickname())); - // 2.3 拼接合同信息 - findAndThen(contractMap, receivablePlanVO.getContractId(), contract -> receivablePlanVO.setContractNo(contract.getNo())); - // 2.4 拼接回款信息 - receivablePlanVO.setReceivable(BeanUtils.toBean(receivableMap.get(receivablePlanVO.getReceivableId()), CrmReceivableRespVO.class)); - }); - } - - @GetMapping("/simple-list") - @Operation(summary = "获得回款计划精简列表", description = "获得回款计划精简列表,主要用于前端的下拉选项") - @Parameters({ - @Parameter(name = "customerId", description = "客户编号", required = true), - @Parameter(name = "contractId", description = "合同编号", required = true) - }) - @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") - public CommonResult> getReceivablePlanSimpleList(@RequestParam("customerId") Long customerId, - @RequestParam("contractId") Long contractId) { - CrmReceivablePlanPageReqVO pageReqVO = new CrmReceivablePlanPageReqVO().setCustomerId(customerId).setContractId(contractId); - pageReqVO.setPageNo(PAGE_SIZE_NONE); - PageResult pageResult = receivablePlanService.getReceivablePlanPageByCustomerId(pageReqVO); - return success(convertList(pageResult.getList(), receivablePlan -> new CrmReceivablePlanRespVO() // 只返回 id、period 等信息 - .setId(receivablePlan.getId()).setPeriod(receivablePlan.getPeriod()).setReceivableId(receivablePlan.getReceivableId()) - .setPrice(receivablePlan.getPrice()).setReturnType(receivablePlan.getReturnType()))); - } - - @GetMapping("/remind-count") - @Operation(summary = "获得待回款提醒数量") - @PreAuthorize("@ss.hasPermission('crm:receivable-plan:query')") - public CommonResult getReceivablePlanRemindCount() { - return success(receivablePlanService.getReceivablePlanRemindCount(getLoginUserId())); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanPageReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanPageReqVO.java deleted file mode 100644 index b730128ce8..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanPageReqVO.java +++ /dev/null @@ -1,46 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -@Schema(description = "管理后台 - CRM 回款计划分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class CrmReceivablePlanPageReqVO extends PageParam { - - /** - * 提醒类型 - 待回款 - */ - public final static Integer REMIND_TYPE_NEEDED = 1; - /** - * 提醒类型 - 已逾期 - */ - public final static Integer REMIND_TYPE_EXPIRED = 2; - /** - * 提醒类型 - 已回款 - */ - public final static Integer REMIND_TYPE_RECEIVED = 3; - - @Schema(description = "客户编号", example = "18026") - private Long customerId; - - @Schema(description = "合同编号", example = "H3473") - private String contractNo; - - @Schema(description = "合同编号", example = "3473") - private Long contractId; - - @Schema(description = "场景类型", example = "1") - @InEnum(CrmSceneTypeEnum.class) - private Integer sceneType; // 场景类型,为 null 时则表示全部 - - @Schema(description = "提醒类型", example = "1") - private Integer remindType; // 提醒类型,为 null 时则表示全部 - -} 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 deleted file mode 100644 index 1c58766e1e..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanRespVO.java +++ /dev/null @@ -1,75 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; - -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO; -import com.alibaba.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -// TODO @puhui999:缺导出 -@Schema(description = "管理后台 - CRM 回款计划 Response VO") -@Data -public class CrmReceivablePlanRespVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Long id; - - @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; - - @Schema(description = "计划回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") - private BigDecimal price; - - @Schema(description = "回款编号", example = "19852") - private Long receivableId; - @Schema(description = "回款信息") - private CrmReceivableRespVO receivable; - - @Schema(description = "提前几天提醒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer remindDays; - - @Schema(description = "提醒日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") - private LocalDateTime remindTime; - - @Schema(description = "备注", example = "备注") - private String remark; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - - @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("更新时间") - private LocalDateTime updateTime; - - @Schema(description = "创建人", example = "1024") - @ExcelProperty("创建人") - private String creator; - @Schema(description = "创建人名字", example = "芋道源码") - @ExcelProperty("创建人名字") - private String creatorName; - -} 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 deleted file mode 100644 index cefb02a9e2..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/plan/CrmReceivablePlanSaveReqVO.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import javax.validation.constraints.NotNull; -import java.math.BigDecimal; -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - CRM 回款计划新增/修改 Request VO") -@Data -public class CrmReceivablePlanSaveReqVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - private Long id; - - @Schema(description = "客户编号", hidden = true, example = "2") - private Long customerId; // 该字段不通过前端传递,而是 contractId 查询出来设置进去 - - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @NotNull(message = "合同编号不能为空") - private Long contractId; - - @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @NotNull(message = "负责人编号不能为空") - private Long ownerUserId; - - @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/CrmReceivablePageReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivablePageReqVO.java deleted file mode 100644 index 415816c5dc..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivablePageReqVO.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; -import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -@Schema(description = "管理后台 - CRM 回款分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class CrmReceivablePageReqVO extends PageParam { - - @Schema(description = "回款编号") - private String no; - - @Schema(description = "回款计划编号", example = "31177") - private Long planId; - - @Schema(description = "客户编号", example = "4963") - private Long customerId; - - @Schema(description = "合同编号", example = "4963") - private Long contractId; - - @Schema(description = "场景类型", example = "1") - @InEnum(CrmSceneTypeEnum.class) - private Integer sceneType; // 场景类型,为 null 时则表示全部 - - @Schema(description = "审批状态", example = "20") - @InEnum(CrmAuditStatusEnum.class) - private Integer auditStatus; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java deleted file mode 100644 index a9fcb1b8b1..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableRespVO.java +++ /dev/null @@ -1,75 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; - -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractRespVO; -import com.alibaba.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -// TODO 芋艿:导出的 VO,可以考虑使用 @Excel 注解,实现导出功能 -@Schema(description = "管理后台 - CRM 回款 Response VO") -@Data -public class CrmReceivableRespVO { - - @Schema(description = "编号", example = "25787") - private Long id; - - @Schema(description = "回款编号", example = "31177") - private String no; - - @Schema(description = "回款计划编号", example = "1024") - private Long planId; - - @Schema(description = "回款方式", example = "2") - private Integer 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 = "客户编号", 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 = "合同信息") - private CrmContractRespVO contract; - - @Schema(description = "负责人的用户编号", example = "25682") - @ExcelProperty("负责人的用户编号") - private Long ownerUserId; - @Schema(description = "负责人名字", example = "25682") - @ExcelProperty("负责人名字") - private String ownerUserName; - @Schema(description = "负责人部门") - @ExcelProperty("负责人部门") - private String ownerUserDeptName; - - @Schema(description = "工作流编号", example = "1043") - @ExcelProperty("工作流编号") - private String processInstanceId; - - @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") - private Integer auditStatus; - - @Schema(description = "备注", example = "备注") - private String remark; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime createTime; - - @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime updateTime; - - @Schema(description = "创建人", example = "25682") - private String creator; - @Schema(description = "创建人名字", example = "test") - private String creatorName; - -} 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 deleted file mode 100644 index 1064fc9248..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/vo/receivable/CrmReceivableSaveReqVO.java +++ /dev/null @@ -1,58 +0,0 @@ -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.CrmReceivableReturnTypeEnum; -import cn.iocoder.yudao.module.crm.framework.operatelog.core.*; -import com.mzt.logapi.starter.annotation.DiffLogField; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import javax.validation.constraints.NotNull; -import java.math.BigDecimal; -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - CRM 回款新增/修改 Request VO") -@Data -public class CrmReceivableSaveReqVO { - - @Schema(description = "编号", example = "25787") - private Long id; - - @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) - @NotNull(message = "负责人编号不能为空") - private Long ownerUserId; - - @Schema(description = "客户编号", example = "2") - @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) - private Long customerId; // 该字段不通过前端传递,而是 contractId 查询出来设置进去 - - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @DiffLogField(name = "合同", function = CrmContractParseFunction.NAME) - @NotNull(message = "合同编号不能为空") - private Long contractId; - - @Schema(description = "回款计划编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @DiffLogField(name = "合同", function = CrmReceivablePlanParseFunction.NAME) - private Long planId; - - @Schema(description = "回款方式", example = "2") - @DiffLogField(name = "回款方式", function = CrmReceivableReturnTypeParseFunction.NAME) - @InEnum(CrmReceivableReturnTypeEnum.class) - private Integer returnType; - - @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "9000") - @DiffLogField(name = "回款金额") - @NotNull(message = "回款金额不能为空") - private BigDecimal price; - - @Schema(description = "回款日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02") - @NotNull(message = "回款日期不能为空") - @DiffLogField(name = "回款日期") - private LocalDateTime returnTime; - - @Schema(description = "备注", example = "备注") - @DiffLogField(name = "备注") - private String remark; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.http b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.http deleted file mode 100644 index e878ba1a93..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.http +++ /dev/null @@ -1,9 +0,0 @@ -### 合同金额排行榜 -GET {{baseUrl}}/crm/statistics-rank/get-contract-price-rank?deptId=100×[0]=2022-12-12 00:00:00×[1]=2024-12-12 23:59:59 -Authorization: Bearer {{token}} -tenant-id: {{adminTenentId}} - -### 回款金额排行榜 -GET {{baseUrl}}/crm/statistics-rank/get-receivable-price-rank?deptId=100×[0]=2022-12-12 00:00:00×[1]=2024-12-12 23:59:59 -Authorization: Bearer {{token}} -tenant-id: {{adminTenentId}} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java deleted file mode 100644 index d73d7637e6..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java +++ /dev/null @@ -1,87 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.statistics; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRanKRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRankReqVO; -import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsRankingService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; -import javax.validation.Valid; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - - -@Tag(name = "管理后台 - CRM 排行榜统计") -@RestController -@RequestMapping("/crm/statistics-rank") -@Validated -public class CrmStatisticsRankController { - - @Resource - private CrmStatisticsRankingService rankingService; - - @GetMapping("/get-contract-price-rank") - @Operation(summary = "获得合同金额排行榜") - @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getContractPriceRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getContractPriceRank(rankingReqVO)); - } - - @GetMapping("/get-receivable-price-rank") - @Operation(summary = "获得回款金额排行榜") - @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getReceivablePriceRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getReceivablePriceRank(rankingReqVO)); - } - - @GetMapping("/get-contract-count-rank") - @Operation(summary = "获得签约合同数量排行榜") - @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getContractCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getContractCountRank(rankingReqVO)); - } - - @GetMapping("/get-product-sales-rank") - @Operation(summary = "获得产品销量排行榜") - @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getProductSalesRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getProductSalesRank(rankingReqVO)); - } - - @GetMapping("/get-customer-count-rank") - @Operation(summary = "获得新增客户数排行榜") - @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getCustomerCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getCustomerCountRank(rankingReqVO)); - } - - @GetMapping("/get-contacts-count-rank") - @Operation(summary = "获得新增联系人数排行榜") - @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getContactsCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getContactsCountRank(rankingReqVO)); - } - - @GetMapping("/get-follow-count-rank") - @Operation(summary = "获得跟进次数排行榜") - @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getFollowCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getFollowCountRank(rankingReqVO)); - } - - @GetMapping("/get-follow-customer-count-rank") - @Operation(summary = "获得跟进客户数排行榜") - @PreAuthorize("@ss.hasPermission('crm:statistics-rank:query')") - public CommonResult> getFollowCustomerCountRank(@Valid CrmStatisticsRankReqVO rankingReqVO) { - return success(rankingService.getFollowCustomerCountRank(rankingReqVO)); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRanKRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRanKRespVO.java deleted file mode 100644 index d5c865fd34..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRanKRespVO.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - - -@Schema(description = "管理后台 - CRM BI 排行榜统计 Response VO") -@Data -public class CrmStatisticsRanKRespVO { - - @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Long ownerUserId; - - @Schema(description = "姓名", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private String nickname; - - @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private String deptName; - - /** - * 数量是个特别“抽象”的概念,在不同排行下,代表不同含义 - * - * 1. 金额:合同金额排行、回款金额排行 - * 2. 个数:签约合同排行、产品销量排行、产品销量排行、新增客户数排行、新增联系人排行、跟进次数排行、跟进客户数排行 - */ - @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer count; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRankReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRankReqVO.java deleted file mode 100644 index 029e3e7284..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/CrmStatisticsRankReqVO.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.time.LocalDateTime; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -@Schema(description = "管理后台 - CRM 排行榜统计 Request VO") -@Data -public class CrmStatisticsRankReqVO { - - @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "部门 id 不能为空") - private Long deptId; - - /** - * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 - * - * 后续,可能会支持选择部分用户进行查询 - */ - @Schema(description = "负责人用户 id 集合", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2") - private List userIds; - - @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.REQUIRED) - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @NotEmpty(message = "时间范围不能为空") - private LocalDateTime[] times; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessDO.java deleted file mode 100644 index a30ece21f8..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessDO.java +++ /dev/null @@ -1,111 +0,0 @@ -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.customer.CrmCustomerDO; -import cn.iocoder.yudao.module.crm.enums.business.CrmBusinessEndStatusEnum; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -/** - * CRM 商机 DO - * - * @author ljlleo - */ -@TableName("crm_business") -@KeySequence("crm_business_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class CrmBusinessDO extends BaseDO { - - /** - * 编号 - */ - @TableId - private Long id; - /** - * 商机名称 - */ - private String name; - /** - * 客户编号 - * - * 关联 {@link CrmCustomerDO#getId()} - */ - private Long customerId; - - /** - * 跟进状态 - */ - private Boolean followUpStatus; - /** - * 最后跟进时间 - */ - private LocalDateTime contactLastTime; - /** - * 下次联系时间 - */ - private LocalDateTime contactNextTime; - - /** - * 负责人的用户编号 - * - * 关联 AdminUserDO 的 id 字段 - */ - private Long ownerUserId; - - /** - * 商机状态组编号 - * - * 关联 {@link CrmBusinessStatusTypeDO#getId()} - */ - private Long statusTypeId; - /** - * 商机状态编号 - * - * 关联 {@link CrmBusinessStatusDO#getId()} - */ - private Long statusId; - /** - * 结束状态 - * - * 枚举 {@link CrmBusinessEndStatusEnum} - */ - private Integer endStatus; - /** - * 结束时的备注 - */ - private String endRemark; - - /** - * 预计成交日期 - */ - private LocalDateTime dealTime; - /** - * 产品总金额,单位:元 - * - * productPrice = ∑({@link CrmBusinessProductDO#getTotalPrice()}) - */ - private BigDecimal totalProductPrice; - /** - * 整单折扣,百分比 - */ - private BigDecimal discountPercent; - /** - * 商机总金额,单位:元 - */ - private BigDecimal totalPrice; - /** - * 备注 - */ - private String remark; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java deleted file mode 100644 index 2f66fc34da..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessProductDO.java +++ /dev/null @@ -1,67 +0,0 @@ -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.product.CrmProductDO; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.math.BigDecimal; - -/** - * CRM 商机产品关联表 DO - * - * CrmBusinessDO : CrmBusinessProductDO = 1 : N - * - * @author lzxhqs - */ -@TableName("crm_business_product") -@KeySequence("crm_business_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class CrmBusinessProductDO extends BaseDO { - - /** - * 主键 - */ - @TableId - private Long id; - /** - * 商机编号 - * - * 关联 {@link CrmBusinessDO#getId()} - */ - private Long businessId; - /** - * 产品编号 - * - * 关联 {@link CrmProductDO#getId()} - */ - private Long productId; - /** - * 产品单价,单位:元 - * - * 冗余 {@link CrmProductDO#getPrice()} - */ - private BigDecimal productPrice; - /** - * 商机价格, 单位:元 - */ - private BigDecimal businessPrice; - /** - * 数量 - */ - private BigDecimal count; - /** - * 总计价格,单位:元 - * - * totalPrice = businessPrice * count - */ - private BigDecimal totalPrice; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusDO.java deleted file mode 100644 index 4ec8bbe4a1..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusDO.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.dataobject.business; - -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -/** - * CRM 商机状态 DO - * - * 注意,它是个配置表 - * - * @author ljlleo - */ -@TableName("crm_business_status") -@KeySequence("crm_business_status_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class CrmBusinessStatusDO { - - /** - * 主键 - */ - @TableId - private Long id; - /** - * 状态类型编号 - * - * 关联 {@link CrmBusinessStatusTypeDO#getId()} - */ - private Long typeId; - /** - * 状态名 - */ - private String name; - /** - * 赢单率,百分比 - */ - private Integer percent; - /** - * 排序 - */ - private Integer sort; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusTypeDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusTypeDO.java deleted file mode 100644 index 95b7a1f26f..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/CrmBusinessStatusTypeDO.java +++ /dev/null @@ -1,46 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.dataobject.business; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.util.List; - -/** - * CRM 商机状态组 DO - * - * 注意,它是个配置表 - * - * @author ljlleo - */ -@TableName(value = "crm_business_status_type", autoResultMap = true) -@KeySequence("crm_business_status_type_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class CrmBusinessStatusTypeDO extends BaseDO { - - /** - * 主键 - */ - @TableId - private Long id; - /** - * 状态类型名 - */ - private String name; - - /** - * 使用的部门编号 - */ - @TableField(typeHandler = LongListTypeHandler.class) - private List deptIds; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java deleted file mode 100644 index 3af6feec43..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/clue/CrmClueDO.java +++ /dev/null @@ -1,128 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.dataobject.clue; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; -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; -import lombok.*; - -import java.time.LocalDateTime; - -/** - * CRM 线索 DO - * - * @author Wanwan - */ -@TableName("crm_clue") -@KeySequence("crm_clue_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class CrmClueDO extends BaseDO { - - /** - * 编号,主键自增 - */ - @TableId - private Long id; - /** - * 线索名称 - */ - private String name; - - /** - * 跟进状态 - */ - private Boolean followUpStatus; - /** - * 最后跟进时间 - */ - private LocalDateTime contactLastTime; - /** - * 最后跟进内容 - */ - private String contactLastContent; - /** - * 下次联系时间 - */ - private LocalDateTime contactNextTime; - - /** - * 负责人的用户编号 - * - * 关联 AdminUserDO 的 id 字段 - */ - private Long ownerUserId; - - /** - * 转化状态 - * - * true 表示已转换,会更新 {@link #customerId} 字段 - */ - private Boolean transformStatus; - /** - * 客户编号 - * - * 关联 {@link CrmCustomerDO#getId()} - */ - private Long customerId; - - /** - * 手机号 - */ - private String mobile; - /** - * 电话 - */ - private String telephone; - /** - * QQ - */ - private String qq; - /** - * wechat - */ - private String wechat; - /** - * email - */ - private String email; - /** - * 所在地 - * - * 关联 {@link cn.iocoder.yudao.framework.ip.core.Area#getId()} 字段 - */ - private Integer areaId; - /** - * 详细地址 - */ - private String detailAddress; - /** - * 所属行业 - * - * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_INDUSTRY} - */ - private Integer industryId; - /** - * 客户等级 - * - * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_LEVEL} - */ - private Integer level; - /** - * 客户来源 - * - * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_SOURCE} - */ - private Integer source; - /** - * 备注 - */ - private String remark; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java deleted file mode 100644 index 5a891eb9c3..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java +++ /dev/null @@ -1,118 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.dataobject.contact; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.time.LocalDateTime; - -/** - * CRM 联系人 DO - * - * @author 芋道源码 - */ -@TableName("crm_contact") -@KeySequence("crm_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class CrmContactDO extends BaseDO { - - /** - * 主键 - */ - @TableId - private Long id; - /** - * 联系人姓名 - */ - private String name; - /** - * 客户编号 - * - * 关联 {@link CrmCustomerDO#getId()} - */ - private Long customerId; - - /** - * 最后跟进时间 - */ - private LocalDateTime contactLastTime; - /** - * 最后跟进内容 - */ - private String contactLastContent; - /** - * 下次联系时间 - */ - private LocalDateTime contactNextTime; - - /** - * 负责人用户编号 - * - * 关联 AdminUserDO 的 id 字段 - */ - private Long ownerUserId; - - /** - * 手机号 - */ - private String mobile; - /** - * 电话 - */ - private String telephone; - /** - * 电子邮箱 - */ - private String email; - /** - * QQ - */ - private Long qq; - /** - * 微信 - */ - private String wechat; - /** - * 所在地 - * - * 关联 {@link cn.iocoder.yudao.framework.ip.core.Area#getId()} 字段 - */ - private Integer areaId; - /** - * 详细地址 - */ - private String detailAddress; - /** - * 性别 - * - * 枚举 {@link cn.iocoder.yudao.module.system.enums.common.SexEnum} - */ - private Integer sex; - /** - * 是否关键决策人 - */ - private Boolean master; - /** - * 职位 - */ - private String post; - /** - * 直属上级 - * - * 关联 {@link CrmContactDO#id} - */ - private Long parentId; - /** - * 备注 - */ - private String remark; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractConfigDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractConfigDO.java deleted file mode 100644 index ab0c2d28e8..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractConfigDO.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.dataobject.contract; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import com.baomidou.mybatisplus.annotation.*; -import lombok.*; - -@TableName("crm_contract_config") -@KeySequence("crm_contract_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class CrmContractConfigDO extends BaseDO { - - /** - * 编号 - */ - @TableId - private Long id; - /** - * 是否开启提前提醒 - */ - @TableField(updateStrategy = FieldStrategy.ALWAYS) - private Boolean notifyEnabled; - /** - * 提前提醒天数 - */ - @TableField(updateStrategy = FieldStrategy.ALWAYS) - private Integer notifyDays; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java deleted file mode 100644 index 89f4fd98ac..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractDO.java +++ /dev/null @@ -1,123 +0,0 @@ -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.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.enums.common.CrmAuditStatusEnum; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -/** - * CRM 合同 DO - * - * @author dhb52 - */ -@TableName("crm_contract") -@KeySequence("crm_contract_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class CrmContractDO extends BaseDO { - - /** - * 合同编号 - */ - @TableId - private Long id; - /** - * 合同名称 - */ - private String name; - /** - * 合同编号 - */ - private String no; - /** - * 客户编号 - * - * 关联 {@link CrmCustomerDO#getId()} - */ - private Long customerId; - /** - * 商机编号,非必须 - * - * 关联 {@link CrmBusinessDO#getId()} - */ - private Long businessId; - - /** - * 最后跟进时间 - */ - private LocalDateTime contactLastTime; - - /** - * 负责人的用户编号 - * - * 关联 AdminUserDO 的 id 字段 - */ - private Long ownerUserId; - - /** - * 工作流编号 - * - * 关联 ProcessInstance 的 id 属性 - */ - private String processInstanceId; - /** - * 审批状态 - * - * 枚举 {@link CrmAuditStatusEnum} - */ - private Integer auditStatus; - - /** - * 下单日期 - */ - private LocalDateTime orderDate; - /** - * 开始时间 - */ - private LocalDateTime startTime; - /** - * 结束时间 - */ - private LocalDateTime endTime; - /** - * 产品总金额,单位:元 - */ - private BigDecimal totalProductPrice; - /** - * 整单折扣 - */ - private BigDecimal discountPercent; - /** - * 合同总金额,单位:分 - */ - private BigDecimal totalPrice; - /** - * 客户签约人,非必须 - * - * 关联 {@link CrmContactDO#getId()} - */ - private Long signContactId; - /** - * 公司签约人,非必须 - * - * 关联 AdminUserDO 的 id 字段 - */ - private Long signUserId; - /** - * 备注 - */ - private String remark; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractProductDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractProductDO.java deleted file mode 100644 index 6bb3e6bf0b..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contract/CrmContractProductDO.java +++ /dev/null @@ -1,63 +0,0 @@ -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.*; - -import java.math.BigDecimal; - -/** - * CRM 合同产品关联表 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 CrmContractDO#getId()} - */ - private Long contractId; - /** - * 产品编号 - * - * 关联 {@link CrmProductDO#getId()} - */ - private Long productId; - /** - * 产品单价,单位:元 - */ - private BigDecimal productPrice; - /** - * 合同价格, 单位:元 - */ - private BigDecimal contractPrice; - /** - * 数量 - */ - private BigDecimal count; - /** - * 总计价格,单位:元 - * - * totalPrice = businessPrice * count - */ - private BigDecimal totalPrice; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java deleted file mode 100644 index 76d5111154..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java +++ /dev/null @@ -1,127 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.dataobject.customer; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -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; -import lombok.*; - -import java.time.LocalDateTime; - -/** - * CRM 客户 DO - * - * @author Wanwan - */ -@TableName(value = "crm_customer") -@KeySequence("crm_customer_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class CrmCustomerDO extends BaseDO { - - /** - * 编号 - */ - @TableId - private Long id; - /** - * 客户名称 - */ - private String name; - - /** - * 跟进状态 - */ - private Boolean followUpStatus; - /** - * 最后跟进时间 - */ - private LocalDateTime contactLastTime; - /** - * 最后跟进内容 - */ - private String contactLastContent; - /** - * 下次联系时间 - */ - private LocalDateTime contactNextTime; - - /** - * 负责人的用户编号 - * - * 关联 AdminUserDO 的 id 字段 - */ - private Long ownerUserId; - /** - * 成为负责人的时间 - */ - private LocalDateTime ownerTime; - - /** - * 锁定状态 - */ - private Boolean lockStatus; - /** - * 成交状态 - */ - private Boolean dealStatus; - - /** - * 手机 - */ - private String mobile; - /** - * 电话 - */ - private String telephone; - /** - * QQ - */ - private String qq; - /** - * wechat - */ - private String wechat; - /** - * email - */ - private String email; - /** - * 所在地 - * - * 关联 {@link cn.iocoder.yudao.framework.ip.core.Area#getId()} 字段 - */ - private Integer areaId; - /** - * 详细地址 - */ - private String detailAddress; - /** - * 所属行业 - * - * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_INDUSTRY} - */ - private Integer industryId; - /** - * 客户等级 - * - * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_LEVEL} - */ - private Integer level; - /** - * 客户来源 - * - * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_SOURCE} - */ - private Integer source; - /** - * 备注 - */ - private String remark; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductDO.java deleted file mode 100644 index caeeb53d2b..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/product/CrmProductDO.java +++ /dev/null @@ -1,74 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.dataobject.product; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; -import cn.iocoder.yudao.module.crm.enums.product.CrmProductStatusEnum; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.math.BigDecimal; - -/** - * CRM 产品 DO - * - * @author ZanGe丶 - */ -@TableName("crm_product") -@KeySequence("crm_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class CrmProductDO extends BaseDO { - - /** - * 编号 - */ - @TableId - private Long id; - /** - * 产品名称 - */ - private String name; - /** - * 产品编码 - */ - private String no; - /** - * 单位 - * - * 字典 {@link DictTypeConstants#CRM_PRODUCT_UNIT} - */ - private Integer unit; - /** - * 价格,单位:元 - */ - private BigDecimal price; - /** - * 状态 - * - * 关联 {@link CrmProductStatusEnum} - */ - private Integer status; - /** - * 产品分类 ID - * - * 关联 {@link CrmProductCategoryDO#getId()} 字段 - */ - private Long categoryId; - /** - * 产品描述 - */ - private String description; - /** - * 负责人的用户编号 - * - * 关联 AdminUserDO 的 id 字段 - */ - private Long ownerUserId; - -} 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 deleted file mode 100644 index 269cac6cc2..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java +++ /dev/null @@ -1,94 +0,0 @@ -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.crm.enums.common.CrmAuditStatusEnum; -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; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -/** - * 回款 DO - * - * @author 赤焰 - */ -@TableName("crm_receivable") -@KeySequence("crm_receivable_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class CrmReceivableDO extends BaseDO { - - /** - * ID - */ - @TableId - private Long id; - /** - * 回款编号 - */ - private String no; - /** - * 回款计划编号 - * - * 关联 {@link CrmReceivablePlanDO#getId()},非必须 - */ - private Long planId; - /** - * 客户编号 - * - * 关联 {@link CrmCustomerDO#getId()} - */ - private Long customerId; - /** - * 合同编号 - * - * 关联 {@link CrmContractDO#getId()} - */ - private Long contractId; - /** - * 负责人编号,关联 {@link AdminUserRespDTO#getId()} - */ - private Long ownerUserId; - - /** - * 回款日期 - */ - private LocalDateTime returnTime; - /** - * 回款方式,关联枚举{@link CrmReceivableReturnTypeEnum} - */ - private Integer returnType; - /** - * 计划回款金额,单位:元 - */ - private BigDecimal price; - /** - * 备注 - */ - private String remark; - - /** - * 工作流编号 - * - * 关联 ProcessInstance 的 id 属性 - */ - private String processInstanceId; - /** - * 审批状态 - * - * 枚举 {@link CrmAuditStatusEnum} - */ - private Integer auditStatus; - -} 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 deleted file mode 100644 index 5ddefc5597..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivablePlanDO.java +++ /dev/null @@ -1,92 +0,0 @@ -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.crm.enums.receivable.CrmReceivableReturnTypeEnum; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -/** - * CRM 回款计划 DO - * - * @author 芋道源码 - */ -@TableName("crm_receivable_plan") -@KeySequence("crm_receivable_plan_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class CrmReceivablePlanDO extends BaseDO { - - /** - * 编号 - */ - @TableId - private Long id; - /** - * 期数 - */ - private Integer period; - /** - * 客户编号 - * - * 关联 {@link CrmCustomerDO#getId()} - */ - private Long customerId; - /** - * 合同编号 - * - * 关联 {@link CrmContractDO#getId()} - */ - 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 Integer remindDays; - /** - * 提醒日期 - */ - private LocalDateTime remindTime; - /** - * 备注 - */ - private String remark; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java deleted file mode 100644 index 4718a8d7ae..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java +++ /dev/null @@ -1,60 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.mysql.business; - -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.business.vo.business.CrmBusinessPageReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; -import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; -import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import org.apache.ibatis.annotations.Mapper; - -import java.util.Collection; - -/** - * 商机 Mapper - * - * @author ljlleo - */ -@Mapper -public interface CrmBusinessMapper extends BaseMapperX { - - default int updateOwnerUserIdById(Long id, Long ownerUserId) { - return update(new LambdaUpdateWrapper() - .eq(CrmBusinessDO::getId, id) - .set(CrmBusinessDO::getOwnerUserId, ownerUserId)); - } - - default PageResult selectPageByCustomerId(CrmBusinessPageReqVO pageReqVO) { - return selectPage(pageReqVO, new LambdaQueryWrapperX() - .eq(CrmBusinessDO::getCustomerId, pageReqVO.getCustomerId()) // 指定客户编号 - .likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName()) - .orderByDesc(CrmBusinessDO::getId)); - } - - default PageResult selectPageByContactId(CrmBusinessPageReqVO pageReqVO, Collection businessIds) { - return selectPage(pageReqVO, new LambdaQueryWrapperX() - .in(CrmBusinessDO::getId, businessIds) // 指定商机编号 - .likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName()) - .orderByDesc(CrmBusinessDO::getId)); - } - - default PageResult selectPage(CrmBusinessPageReqVO pageReqVO, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_BUSINESS.getType(), - CrmBusinessDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); - // 拼接自身的查询条件 - query.selectAll(CrmBusinessDO.class) - .likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName()) - .orderByDesc(CrmBusinessDO::getId); - return selectJoinPage(pageReqVO, CrmBusinessDO.class, query); - } - - default Long selectCountByStatusTypeId(Long statusTypeId) { - return selectCount(CrmBusinessDO::getStatusTypeId, statusTypeId); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessProductMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessProductMapper.java deleted file mode 100644 index a91a0fd141..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessProductMapper.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.mysql.business; - - -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * 商机产品 Mapper - * - * @author lzxhqs - */ -@Mapper -public interface CrmBusinessProductMapper extends BaseMapperX { - - default List selectListByBusinessId(Long businessId) { - return selectList(CrmBusinessProductDO::getBusinessId, businessId); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusMapper.java deleted file mode 100644 index dfe7afcc30..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusMapper.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.mysql.business; - -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * 商机状态 Mapper - * - * @author ljlleo - */ -@Mapper -public interface CrmBusinessStatusMapper extends BaseMapperX { - - default int deleteByTypeId(Long typeId) { - return delete(CrmBusinessStatusDO::getTypeId, typeId); - } - - default List selectListByTypeId(Long typeId) { - return selectList(CrmBusinessStatusDO::getTypeId, typeId); - } - - default CrmBusinessStatusDO selectByTypeIdAndId(Long statusTypeId, Long statusId) { - return selectOne(CrmBusinessStatusDO::getTypeId, statusTypeId, - CrmBusinessStatusDO::getId, statusId); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusTypeMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusTypeMapper.java deleted file mode 100644 index 3444e58a7c..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessStatusTypeMapper.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.mysql.business; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; -import org.apache.ibatis.annotations.Mapper; - -/** - * 商机状态组 Mapper - * - * @author ljlleo - */ -@Mapper -public interface CrmBusinessStatusTypeMapper extends BaseMapperX { - - default PageResult selectPage(PageParam reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .orderByDesc(CrmBusinessStatusTypeDO::getId)); - } - - default CrmBusinessStatusTypeDO selectByName(String name) { - return selectOne(CrmBusinessStatusTypeDO::getName, name); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java deleted file mode 100644 index d0665c604d..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java +++ /dev/null @@ -1,63 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.mysql.clue; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; -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.CrmPermissionUtils; -import org.apache.ibatis.annotations.Mapper; - -import java.util.Collection; -import java.util.List; - -/** - * 线索 Mapper - * - * @author Wanwan - */ -@Mapper -public interface CrmClueMapper extends BaseMapperX { - - default PageResult selectPage(CrmCluePageReqVO pageReqVO, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CLUE.getType(), - CrmClueDO::getId, userId, pageReqVO.getSceneType(), pageReqVO.getPool()); - // 拼接自身的查询条件 - query.selectAll(CrmClueDO.class) - .likeIfPresent(CrmClueDO::getName, pageReqVO.getName()) - .eqIfPresent(CrmClueDO::getTransformStatus, pageReqVO.getTransformStatus()) - .likeIfPresent(CrmClueDO::getTelephone, pageReqVO.getTelephone()) - .likeIfPresent(CrmClueDO::getMobile, pageReqVO.getMobile()) - .eqIfPresent(CrmClueDO::getIndustryId, pageReqVO.getIndustryId()) - .eqIfPresent(CrmClueDO::getLevel, pageReqVO.getLevel()) - .eqIfPresent(CrmClueDO::getSource, pageReqVO.getSource()) - .eqIfPresent(CrmClueDO::getFollowUpStatus, pageReqVO.getFollowUpStatus()) - .orderByDesc(CrmClueDO::getId); - return selectJoinPage(pageReqVO, CrmClueDO.class, query); - } - - default List selectBatchIds(Collection ids, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CLUE.getType(), ids, userId); - query.selectAll(CrmClueDO.class).in(CrmClueDO::getId, ids).orderByDesc(CrmClueDO::getId); - // 拼接自身的查询条件 - return selectJoinList(CrmClueDO.class, query); - } - - default Long selectCountByFollow(Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 我负责的 + 非公海 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CLUE.getType(), - CrmClueDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); - // 未跟进 + 未转化 - query.eq(CrmClueDO::getFollowUpStatus, false) - .eq(CrmClueDO::getTransformStatus, false); - return selectCount(query); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactBusinessMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactBusinessMapper.java deleted file mode 100644 index 7bff0c2046..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactBusinessMapper.java +++ /dev/null @@ -1,44 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.mysql.contact; - -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import org.apache.ibatis.annotations.Mapper; - -import java.util.Collection; -import java.util.List; - -/** - * CRM 联系人商机关联 Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface CrmContactBusinessMapper extends BaseMapperX { - - default CrmContactBusinessDO selectByContactIdAndBusinessId(Long contactId, Long businessId) { - return selectOne(CrmContactBusinessDO::getContactId, contactId, - CrmContactBusinessDO::getBusinessId, businessId); - } - - default void deleteByContactIdAndBusinessId(Long contactId, Collection businessIds) { - delete(new LambdaQueryWrapper() - .eq(CrmContactBusinessDO::getContactId, contactId) - .in(CrmContactBusinessDO::getBusinessId, businessIds)); - } - - default void deleteByBusinessIdAndContactId(Long businessId, List contactIds) { - delete(new LambdaQueryWrapper() - .eq(CrmContactBusinessDO::getBusinessId, businessId) - .in(CrmContactBusinessDO::getContactId, contactIds)); - } - - default List selectListByContactId(Long contactId) { - return selectList(CrmContactBusinessDO::getContactId, contactId); - } - - default List selectListByBusinessId(Long businessId) { - return selectList(CrmContactBusinessDO::getBusinessId, businessId); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java deleted file mode 100644 index 4a77665ad7..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java +++ /dev/null @@ -1,76 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.mysql.contact; - -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.contact.vo.CrmContactPageReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; -import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; -import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import org.apache.ibatis.annotations.Mapper; - -import java.util.Collection; -import java.util.List; - -/** - * CRM 联系人 Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface CrmContactMapper extends BaseMapperX { - - default int updateOwnerUserIdByCustomerId(Long customerId, Long ownerUserId) { - return update(new LambdaUpdateWrapper() - .eq(CrmContactDO::getCustomerId, customerId) - .set(CrmContactDO::getOwnerUserId, ownerUserId)); - } - - default PageResult selectPageByCustomerId(CrmContactPageReqVO pageVO) { - return selectPage(pageVO, new LambdaQueryWrapperX() - .eq(CrmContactDO::getCustomerId, pageVO.getCustomerId()) // 指定客户编号 - .likeIfPresent(CrmContactDO::getName, pageVO.getName()) - .eqIfPresent(CrmContactDO::getMobile, pageVO.getMobile()) - .eqIfPresent(CrmContactDO::getTelephone, pageVO.getTelephone()) - .eqIfPresent(CrmContactDO::getEmail, pageVO.getEmail()) - .eqIfPresent(CrmContactDO::getQq, pageVO.getQq()) - .eqIfPresent(CrmContactDO::getWechat, pageVO.getWechat()) - .orderByDesc(CrmContactDO::getId)); - } - - default PageResult selectPageByBusinessId(CrmContactPageReqVO pageVO, Collection ids) { - return selectPage(pageVO, new LambdaQueryWrapperX() - .in(CrmContactDO::getId, ids) // 指定联系人编号 - .likeIfPresent(CrmContactDO::getName, pageVO.getName()) - .eqIfPresent(CrmContactDO::getMobile, pageVO.getMobile()) - .eqIfPresent(CrmContactDO::getTelephone, pageVO.getTelephone()) - .eqIfPresent(CrmContactDO::getEmail, pageVO.getEmail()) - .eqIfPresent(CrmContactDO::getQq, pageVO.getQq()) - .eqIfPresent(CrmContactDO::getWechat, pageVO.getWechat()) - .orderByDesc(CrmContactDO::getId)); - } - - default PageResult selectPage(CrmContactPageReqVO pageReqVO, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTACT.getType(), - CrmContactDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); - // 拼接自身的查询条件 - query.selectAll(CrmContactDO.class) - .likeIfPresent(CrmContactDO::getName, pageReqVO.getName()) - .eqIfPresent(CrmContactDO::getMobile, pageReqVO.getMobile()) - .eqIfPresent(CrmContactDO::getTelephone, pageReqVO.getTelephone()) - .eqIfPresent(CrmContactDO::getEmail, pageReqVO.getEmail()) - .eqIfPresent(CrmContactDO::getQq, pageReqVO.getQq()) - .eqIfPresent(CrmContactDO::getWechat, pageReqVO.getWechat()) - .orderByDesc(CrmContactDO::getId); - return selectJoinPage(pageReqVO, CrmContactDO.class, query); - } - - default List selectListByCustomerId(Long customerId) { - return selectList(CrmContactDO::getCustomerId, customerId); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractConfigMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractConfigMapper.java deleted file mode 100644 index 64e6f918bc..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractConfigMapper.java +++ /dev/null @@ -1,20 +0,0 @@ -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.QueryWrapperX; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractConfigDO; -import org.apache.ibatis.annotations.Mapper; - -/** - * 合同配置 Mapper - * - * @author Wanwan - */ -@Mapper -public interface CrmContractConfigMapper extends BaseMapperX { - - default CrmContractConfigDO selectOne() { - return selectOne(new QueryWrapperX().limitN(1)); - } - -} \ No newline at end of file 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 deleted file mode 100644 index e06afb2571..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java +++ /dev/null @@ -1,120 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.mysql.contract; - -import cn.hutool.core.date.LocalDateTimeUtil; -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.contract.vo.contract.CrmContractPageReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractConfigDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; -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.CrmPermissionUtils; -import org.apache.ibatis.annotations.Mapper; - -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; - -/** - * CRM 合同 Mapper - * - * @author dhb52 - */ -@Mapper -public interface CrmContractMapper extends BaseMapperX { - - default CrmContractDO selectByNo(String no) { - return selectOne(CrmContractDO::getNo, no); - } - - default PageResult selectPageByCustomerId(CrmContractPageReqVO pageReqVO) { - return selectPage(pageReqVO, new LambdaQueryWrapperX() - .eq(CrmContractDO::getCustomerId, pageReqVO.getCustomerId()) - .likeIfPresent(CrmContractDO::getNo, pageReqVO.getNo()) - .likeIfPresent(CrmContractDO::getName, pageReqVO.getName()) - .eqIfPresent(CrmContractDO::getCustomerId, pageReqVO.getCustomerId()) - .eqIfPresent(CrmContractDO::getBusinessId, pageReqVO.getBusinessId()) - .orderByDesc(CrmContractDO::getId)); - } - - default PageResult selectPageByBusinessId(CrmContractPageReqVO pageReqVO) { - return selectPage(pageReqVO, new LambdaQueryWrapperX() - .eq(CrmContractDO::getBusinessId, pageReqVO.getBusinessId()) - .likeIfPresent(CrmContractDO::getNo, pageReqVO.getNo()) - .likeIfPresent(CrmContractDO::getName, pageReqVO.getName()) - .eqIfPresent(CrmContractDO::getCustomerId, pageReqVO.getCustomerId()) - .eqIfPresent(CrmContractDO::getBusinessId, pageReqVO.getBusinessId()) - .orderByDesc(CrmContractDO::getId)); - } - - default PageResult selectPage(CrmContractPageReqVO pageReqVO, Long userId, CrmContractConfigDO config) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTRACT.getType(), - CrmContractDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); - // 拼接自身的查询条件 - query.selectAll(CrmContractDO.class) - .likeIfPresent(CrmContractDO::getNo, pageReqVO.getNo()) - .likeIfPresent(CrmContractDO::getName, pageReqVO.getName()) - .eqIfPresent(CrmContractDO::getCustomerId, pageReqVO.getCustomerId()) - .eqIfPresent(CrmContractDO::getBusinessId, pageReqVO.getBusinessId()) - .eqIfPresent(CrmContractDO::getAuditStatus, pageReqVO.getAuditStatus()) - .orderByDesc(CrmContractDO::getId); - - // Backlog: 即将到期的合同 - LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); - LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); - if (CrmContractPageReqVO.EXPIRY_TYPE_ABOUT_TO_EXPIRE.equals(pageReqVO.getExpiryType())) { // 即将到期 - query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.APPROVE.getStatus()) - .between(CrmContractDO::getEndTime, beginOfToday, endOfToday.plusDays(config.getNotifyDays())); - } else if (CrmContractPageReqVO.EXPIRY_TYPE_EXPIRED.equals(pageReqVO.getExpiryType())) { // 已到期 - query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.APPROVE.getStatus()) - .lt(CrmContractDO::getEndTime, endOfToday); - } - return selectJoinPage(pageReqVO, CrmContractDO.class, query); - } - - default List selectBatchIds(Collection ids, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 构建数据权限连表条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTRACT.getType(), ids, userId); - // 拼接自身的查询条件 - query.selectAll(CrmContractDO.class).in(CrmContractDO::getId, ids).orderByDesc(CrmContractDO::getId); - return selectJoinList(CrmContractDO.class, query); - } - - default Long selectCountByContactId(Long contactId) { - return selectCount(CrmContractDO::getSignContactId, contactId); - } - - default Long selectCountByBusinessId(Long businessId) { - return selectCount(CrmContractDO::getBusinessId, businessId); - } - - default Long selectCountByAudit(Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 我负责的 + 非公海 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTRACT.getType(), - CrmContractDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); - // 未审核 - query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.PROCESS.getStatus()); - return selectCount(query); - } - - default Long selectCountByRemind(Long userId, CrmContractConfigDO config) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 我负责的 + 非公海 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTRACT.getType(), - CrmContractDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); - // 即将到期 - LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); - LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); - query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.APPROVE.getStatus()) // 必须审批通过! - .between(CrmContractDO::getEndTime, beginOfToday, endOfToday.plusDays(config.getNotifyDays())); - return selectCount(query); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractProductMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractProductMapper.java deleted file mode 100644 index feafbc4443..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractProductMapper.java +++ /dev/null @@ -1,23 +0,0 @@ -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 { - - default List selectListByContractId(Long contractId) { - return selectList(new LambdaQueryWrapperX().eq(CrmContractProductDO::getContractId, contractId)); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java deleted file mode 100644 index 5034453887..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java +++ /dev/null @@ -1,189 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.mysql.customer; - -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.hutool.core.util.ObjUtil; -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.customer.vo.customer.CrmCustomerPageReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; -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.CrmPermissionUtils; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import org.apache.ibatis.annotations.Mapper; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; - -/** - * 客户 Mapper - * - * @author Wanwan - */ -@Mapper -public interface CrmCustomerMapper extends BaseMapperX { - - default Long selectCountByLockStatusAndOwnerUserId(Boolean lockStatus, Long ownerUserId) { - return selectCount(new LambdaUpdateWrapper() - .eq(CrmCustomerDO::getLockStatus, lockStatus) - .eq(CrmCustomerDO::getOwnerUserId, ownerUserId)); - } - - default Long selectCountByDealStatusAndOwnerUserId(@Nullable Boolean dealStatus, Long ownerUserId) { - return selectCount(new LambdaQueryWrapperX() - .eqIfPresent(CrmCustomerDO::getDealStatus, dealStatus) - .eq(CrmCustomerDO::getOwnerUserId, ownerUserId)); - } - - default int updateOwnerUserIdById(Long id, Long ownerUserId) { - return update(new LambdaUpdateWrapper() - .eq(CrmCustomerDO::getId, id) - .set(CrmCustomerDO::getOwnerUserId, ownerUserId)); - } - - default PageResult selectPage(CrmCustomerPageReqVO pageReqVO, Long ownerUserId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), - CrmCustomerDO::getId, ownerUserId, pageReqVO.getSceneType(), pageReqVO.getPool()); - // 拼接自身的查询条件 - query.selectAll(CrmCustomerDO.class) - .likeIfPresent(CrmCustomerDO::getName, pageReqVO.getName()) - .eqIfPresent(CrmCustomerDO::getMobile, pageReqVO.getMobile()) - .eqIfPresent(CrmCustomerDO::getIndustryId, pageReqVO.getIndustryId()) - .eqIfPresent(CrmCustomerDO::getLevel, pageReqVO.getLevel()) - .eqIfPresent(CrmCustomerDO::getSource, pageReqVO.getSource()) - .eqIfPresent(CrmCustomerDO::getFollowUpStatus, pageReqVO.getFollowUpStatus()); - - // backlog 查询 - if (ObjUtil.isNotNull(pageReqVO.getContactStatus())) { - Assert.isNull(pageReqVO.getPool(), "pool 必须是 null"); - LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); - LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); - if (pageReqVO.getContactStatus().equals(CrmCustomerPageReqVO.CONTACT_TODAY)) { // 今天需联系 - query.between(CrmCustomerDO::getContactNextTime, beginOfToday, endOfToday); - } else if (pageReqVO.getContactStatus().equals(CrmCustomerPageReqVO.CONTACT_EXPIRED)) { // 已逾期 - query.lt(CrmCustomerDO::getContactNextTime, beginOfToday); - } else if (pageReqVO.getContactStatus().equals(CrmCustomerPageReqVO.CONTACT_ALREADY)) { // 已联系 - query.between(CrmCustomerDO::getContactLastTime, beginOfToday, endOfToday); - } else { - throw new IllegalArgumentException("未知联系状态:" + pageReqVO.getContactStatus()); - } - } - return selectJoinPage(pageReqVO, CrmCustomerDO.class, query); - } - - default List selectBatchIds(Collection ids, Long ownerUserId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), ids, ownerUserId); - // 拼接自身的查询条件 - query.selectAll(CrmCustomerDO.class).in(CrmCustomerDO::getId, ids).orderByDesc(CrmCustomerDO::getId); - return selectJoinList(CrmCustomerDO.class, query); - } - - default CrmCustomerDO selectByCustomerName(String name) { - return selectOne(CrmCustomerDO::getName, name); - } - - default PageResult selectPutPoolRemindCustomerPage(CrmCustomerPageReqVO pageReqVO, - CrmCustomerPoolConfigDO poolConfig, - Long ownerUserId) { - final MPJLambdaWrapperX query = buildPutPoolRemindCustomerQuery(pageReqVO, poolConfig, ownerUserId); - return selectJoinPage(pageReqVO, CrmCustomerDO.class, query.selectAll(CrmCustomerDO.class)); - } - - default Long selectPutPoolRemindCustomerCount(CrmCustomerPageReqVO pageReqVO, - CrmCustomerPoolConfigDO poolConfigDO, - Long userId) { - final MPJLambdaWrapperX query = buildPutPoolRemindCustomerQuery(pageReqVO, poolConfigDO, userId); - return selectCount(query); - } - - static MPJLambdaWrapperX buildPutPoolRemindCustomerQuery(CrmCustomerPageReqVO pageReqVO, - CrmCustomerPoolConfigDO poolConfig, - Long ownerUserId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), - CrmCustomerDO::getId, ownerUserId, pageReqVO.getSceneType(), null); - - // 未锁定 + 未成交 - query.eq(CrmCustomerDO::getLockStatus, false).eq(CrmCustomerDO::getDealStatus, false); - - // 情况一:未成交提醒日期区间 - Integer dealExpireDays = poolConfig.getDealExpireDays(); - LocalDateTime startDealRemindTime = LocalDateTime.now().minusDays(dealExpireDays); - LocalDateTime endDealRemindTime = LocalDateTime.now() - .minusDays(Math.max(dealExpireDays - poolConfig.getNotifyDays(), 0)); - // 情况二:未跟进提醒日期区间 - Integer contactExpireDays = poolConfig.getContactExpireDays(); - LocalDateTime startContactRemindTime = LocalDateTime.now().minusDays(contactExpireDays); - LocalDateTime endContactRemindTime = LocalDateTime.now() - .minusDays(Math.max(contactExpireDays - poolConfig.getNotifyDays(), 0)); - query.and(q -> { - // 情况一:成交超时提醒 - q.between(CrmCustomerDO::getOwnerTime, startDealRemindTime, endDealRemindTime) - // 情况二:跟进超时提醒 - .or(w -> w.between(CrmCustomerDO::getOwnerTime, startContactRemindTime, endContactRemindTime) - .and(p -> p.between(CrmCustomerDO::getContactLastTime, startContactRemindTime, endContactRemindTime) - .or().isNull(CrmCustomerDO::getContactLastTime))); - }); - return query; - } - - /** - * 获得需要过期到公海的客户列表 - * - * @return 客户列表 - */ - default List selectListByAutoPool(CrmCustomerPoolConfigDO poolConfig) { - LambdaQueryWrapper query = new LambdaQueryWrapper<>(); - query.gt(CrmCustomerDO::getOwnerUserId, 0); - // 未锁定 + 未成交 - query.eq(CrmCustomerDO::getLockStatus, false).eq(CrmCustomerDO::getDealStatus, false); - // 已经超时 - LocalDateTime dealExpireTime = LocalDateTime.now().minusDays(poolConfig.getDealExpireDays()); - LocalDateTime contactExpireTime = LocalDateTime.now().minusDays(poolConfig.getContactExpireDays()); - query.and(q -> { - // 情况一:成交超时 - q.lt(CrmCustomerDO::getOwnerTime, dealExpireTime) - // 情况二:跟进超时 - .or(w -> w.lt(CrmCustomerDO::getOwnerTime, contactExpireTime) - .and(p -> p.lt(CrmCustomerDO::getContactLastTime, contactExpireTime) - .or().isNull(CrmCustomerDO::getContactLastTime))); - }); - return selectList(query); - } - - default Long selectCountByTodayContact(Long ownerUserId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 我负责的 + 非公海 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), - CrmCustomerDO::getId, ownerUserId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); - // 今天需联系 - LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); - LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); - query.between(CrmCustomerDO::getContactNextTime, beginOfToday, endOfToday); - return selectCount(query); - } - - default Long selectCountByFollow(Long ownerUserId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 我负责的 + 非公海 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), - CrmCustomerDO::getId, ownerUserId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); - // 未跟进 - query.eq(CrmClueDO::getFollowUpStatus, false); - return selectCount(query); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductMapper.java deleted file mode 100644 index 4d1d61809d..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/product/CrmProductMapper.java +++ /dev/null @@ -1,39 +0,0 @@ -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.MPJLambdaWrapperX; -import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * CRM 产品 Mapper - * - * @author ZanGe丶 - */ -@Mapper -public interface CrmProductMapper extends BaseMapperX { - - default PageResult selectPage(CrmProductPageReqVO reqVO) { - return selectPage(reqVO, new MPJLambdaWrapperX() - .likeIfPresent(CrmProductDO::getName, reqVO.getName()) - .eqIfPresent(CrmProductDO::getStatus, reqVO.getStatus()) - .orderByDesc(CrmProductDO::getId)); - } - - default CrmProductDO selectByNo(String no) { - return selectOne(CrmProductDO::getNo, no); - } - - default Long selectCountByCategoryId(Long categoryId) { - return selectCount(CrmProductDO::getCategoryId, categoryId); - } - - default List selectListByStatus(Integer status) { - return selectList(CrmProductDO::getStatus, status); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java deleted file mode 100644 index 5a5e9ce2b6..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java +++ /dev/null @@ -1,102 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.mysql.receivable; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; -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.CrmPermissionUtils; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import org.apache.ibatis.annotations.Mapper; - -import java.math.BigDecimal; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; - -/** - * 回款 Mapper - * - * @author 赤焰 - */ -@Mapper -public interface CrmReceivableMapper extends BaseMapperX { - - default CrmReceivableDO selectByNo(String no) { - return selectOne(CrmReceivableDO::getNo, no); - } - - default PageResult selectPageByCustomerId(CrmReceivablePageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eq(CrmReceivableDO::getCustomerId, reqVO.getCustomerId()) // 必须传递 - .eqIfPresent(CrmReceivableDO::getNo, reqVO.getNo()) - .eqIfPresent(CrmReceivableDO::getContractId, reqVO.getContractId()) - .eqIfPresent(CrmReceivableDO::getPlanId, reqVO.getPlanId()) - .orderByDesc(CrmReceivableDO::getId)); - } - - default PageResult selectPage(CrmReceivablePageReqVO pageReqVO, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE.getType(), - CrmReceivableDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); - // 拼接自身的查询条件 - query.selectAll(CrmReceivableDO.class) - .eqIfPresent(CrmReceivableDO::getNo, pageReqVO.getNo()) - .eqIfPresent(CrmReceivableDO::getPlanId, pageReqVO.getPlanId()) - .eqIfPresent(CrmReceivableDO::getContractId, pageReqVO.getContractId()) - .eqIfPresent(CrmReceivableDO::getAuditStatus, pageReqVO.getAuditStatus()) - .orderByDesc(CrmReceivableDO::getId); - return selectJoinPage(pageReqVO, CrmReceivableDO.class, query); - } - - default List selectBatchIds(Collection ids, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE.getType(), ids, userId); - // 拼接自身的查询条件 - query.selectAll(CrmReceivableDO.class).in(CrmReceivableDO::getId, ids).orderByDesc(CrmReceivableDO::getId); - return selectJoinList(CrmReceivableDO.class, query); - } - - default Long selectCountByAudit(Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 我负责的 + 非公海 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE.getType(), - CrmReceivableDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); - // 未审核 - query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.PROCESS.getStatus()); - return selectCount(query); - } - - default List selectListByContractIdAndStatus(Long contractId, Collection auditStatuses) { - return selectList(new LambdaQueryWrapperX() - .eq(CrmReceivableDO::getContractId, contractId) - .in(CrmReceivableDO::getAuditStatus, auditStatuses)); - } - - default Map selectReceivablePriceMapByContractId(Collection contractIds) { - if (CollUtil.isEmpty(contractIds)) { - return Collections.emptyMap(); - } - // SQL sum 查询 - List> result = selectMaps(new QueryWrapper() - .select("contract_id, SUM(price) AS total_price") - .in("audit_status", CrmAuditStatusEnum.DRAFT.getStatus(), // 草稿 + 审批中 + 审批通过 - CrmAuditStatusEnum.PROCESS, CrmAuditStatusEnum.APPROVE.getStatus()) - .groupBy("contract_id") - .in("contract_id", contractIds)); - // 获得金额 - return convertMap(result, obj -> (Long) obj.get("contract_id"), obj -> (BigDecimal) obj.get("total_price")); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java deleted file mode 100644 index 4d53897936..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java +++ /dev/null @@ -1,99 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.mysql.receivable; - -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanPageReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; -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.CrmPermissionUtils; -import org.apache.ibatis.annotations.Mapper; - -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; -import java.util.Objects; - -/** - * 回款计划 Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface CrmReceivablePlanMapper extends BaseMapperX { - - default CrmReceivablePlanDO selectMaxPeriodByContractId(Long contractId) { - return selectOne(new MPJLambdaWrapperX() - .eq(CrmReceivablePlanDO::getContractId, contractId) - .orderByDesc(CrmReceivablePlanDO::getPeriod) - .last("LIMIT 1")); - } - - default PageResult selectPageByCustomerId(CrmReceivablePlanPageReqVO reqVO) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - if (Objects.nonNull(reqVO.getContractNo())) { // 根据合同编号检索 - query.innerJoin(CrmContractDO.class, on -> on.like(CrmContractDO::getNo, reqVO.getContractNo()) - .eq(CrmContractDO::getId, CrmReceivablePlanDO::getContractId)); - } - query.eq(CrmReceivablePlanDO::getCustomerId, reqVO.getCustomerId()) // 必须传递 - .eqIfPresent(CrmReceivablePlanDO::getContractId, reqVO.getContractId()) - .orderByDesc(CrmReceivablePlanDO::getPeriod); - return selectJoinPage(reqVO, CrmReceivablePlanDO.class, query); - } - - default PageResult selectPage(CrmReceivablePlanPageReqVO pageReqVO, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), - CrmReceivablePlanDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); - // 拼接自身的查询条件 - query.selectAll(CrmReceivablePlanDO.class) - .eqIfPresent(CrmReceivablePlanDO::getCustomerId, pageReqVO.getCustomerId()) - .eqIfPresent(CrmReceivablePlanDO::getContractId, pageReqVO.getContractId()) - .orderByDesc(CrmReceivablePlanDO::getPeriod); - if (Objects.nonNull(pageReqVO.getContractNo())) { // 根据合同编号检索 - query.innerJoin(CrmContractDO.class, on -> on.like(CrmContractDO::getNo, pageReqVO.getContractNo()) - .eq(CrmContractDO::getId, CrmReceivablePlanDO::getContractId)); - } - - // Backlog: 回款提醒类型 - LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); - if (CrmReceivablePlanPageReqVO.REMIND_TYPE_NEEDED.equals(pageReqVO.getRemindType())) { // 待回款 - query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款 - .lt(CrmReceivablePlanDO::getReturnTime, beginOfToday) // 已逾期 - .lt(CrmReceivablePlanDO::getRemindTime, beginOfToday); // 今天开始提醒 - } else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_EXPIRED.equals(pageReqVO.getRemindType())) { // 已逾期 - query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款 - .ge(CrmReceivablePlanDO::getReturnTime, beginOfToday); // 已逾期 - } else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_RECEIVED.equals(pageReqVO.getRemindType())) { // 已回款 - query.isNotNull(CrmReceivablePlanDO::getReceivableId); - } - return selectJoinPage(pageReqVO, CrmReceivablePlanDO.class, query); - } - - default List selectBatchIds(Collection ids, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), ids, userId); - // 拼接自身的查询条件 - query.selectAll(CrmReceivablePlanDO.class).in(CrmReceivablePlanDO::getId, ids).orderByDesc(CrmReceivablePlanDO::getId); - return selectJoinList(CrmReceivablePlanDO.class, query); - } - - default Long selectReceivablePlanCountByRemind(Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 我负责的 + 非公海 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), - CrmReceivablePlanDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); - // 未回款 + 已逾期 + 今天开始提醒 - LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); - query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款 - .lt(CrmReceivablePlanDO::getReturnTime, beginOfToday) // 已逾期 - .lt(CrmReceivablePlanDO::getRemindTime, beginOfToday); // 今天开始提醒 - return selectCount(query); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankingMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankingMapper.java deleted file mode 100644 index 4b51ab2fe9..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsRankingMapper.java +++ /dev/null @@ -1,81 +0,0 @@ -package cn.iocoder.yudao.module.crm.dal.mysql.statistics; - -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRanKRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRankReqVO; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * CRM 排行榜统计 Mapper - * - * @author anhaohao - */ -@Mapper -public interface CrmStatisticsRankingMapper { - - /** - * 查询合同金额排行榜 - * - * @param rankReqVO 参数 - * @return 合同金额排行榜 - */ - List selectContractPriceRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 查询回款金额排行榜 - * - * @param rankReqVO 参数 - * @return 回款金额排行榜 - */ - List selectReceivablePriceRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 查询签约合同数量排行榜 - * - * @param rankReqVO 参数 - * @return 签约合同数量排行榜 - */ - List selectContractCountRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 查询产品销量排行榜 - * - * @param rankReqVO 参数 - * @return 产品销量排行榜 - */ - List selectProductSalesRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 查询新增客户数排行榜 - * - * @param rankReqVO 参数 - * @return 新增客户数排行榜 - */ - List selectCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 查询联系人数量排行榜 - * - * @param rankReqVO 参数 - * @return 联系人数量排行榜 - */ - List selectContactsCountRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 查询跟进次数排行榜 - * - * @param rankReqVO 参数 - * @return 跟进次数排行榜 - */ - List selectFollowCountRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 查询跟进客户数排行榜 - * - * @param rankReqVO 参数 - * @return 跟进客户数排行榜 - */ - List selectFollowCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); - -} 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 deleted file mode 100644 index 2932c1db14..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/RedisKeyConstants.java +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index 68f0835ecc..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java +++ /dev/null @@ -1,52 +0,0 @@ -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 org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.stereotype.Repository; - -import javax.annotation.Resource; -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/framework/operatelog/core/CrmCustomerIndustryParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerIndustryParseFunction.java deleted file mode 100644 index 495255056d..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerIndustryParseFunction.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.operatelog.core; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.dict.util.DictFrameworkUtils; -import com.mzt.logapi.service.IParseFunction; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; - -/** - * 行业的 {@link IParseFunction} 实现类 - * - * @author HUIHUI - */ -@Component -@Slf4j -public class CrmCustomerIndustryParseFunction implements IParseFunction { - - public static final String NAME = "getCustomerIndustry"; - - @Override - public boolean executeBefore() { - return true; // 先转换值后对比 - } - - @Override - public String functionName() { - return NAME; - } - - @Override - public String apply(Object value) { - if (StrUtil.isEmptyIfStr(value)) { - return ""; - } - return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, value.toString()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerLevelParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerLevelParseFunction.java deleted file mode 100644 index 0cf44c8543..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerLevelParseFunction.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.operatelog.core; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.dict.util.DictFrameworkUtils; -import com.mzt.logapi.service.IParseFunction; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_LEVEL; - -/** - * 客户等级的 {@link IParseFunction} 实现类 - * - * @author HUIHUI - */ -@Component -@Slf4j -public class CrmCustomerLevelParseFunction implements IParseFunction { - - public static final String NAME = "getCustomerLevel"; - - @Override - public boolean executeBefore() { - return true; // 先转换值后对比 - } - - @Override - public String functionName() { - return NAME; - } - - @Override - public String apply(Object value) { - if (StrUtil.isEmptyIfStr(value)) { - return ""; - } - return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_LEVEL, value.toString()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerSourceParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerSourceParseFunction.java deleted file mode 100644 index 638ca79511..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmCustomerSourceParseFunction.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.operatelog.core; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.dict.util.DictFrameworkUtils; -import com.mzt.logapi.service.IParseFunction; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_SOURCE; - -/** - * CRM 客户来源的 {@link IParseFunction} 实现类 - * - * @author HUIHUI - */ -@Component -@Slf4j -public class CrmCustomerSourceParseFunction implements IParseFunction { - - public static final String NAME = "getCustomerSource"; - - @Override - public boolean executeBefore() { - return true; // 先转换值后对比 - } - - @Override - public String functionName() { - return NAME; - } - - @Override - public String apply(Object value) { - if (StrUtil.isEmptyIfStr(value)) { - return ""; - } - return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_SOURCE, value.toString()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductStatusParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductStatusParseFunction.java deleted file mode 100644 index 4c626faddb..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductStatusParseFunction.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.operatelog.core; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.dict.util.DictFrameworkUtils; -import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; -import com.mzt.logapi.service.IParseFunction; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -/** - * 产品状态的 {@link IParseFunction} 实现类 - * - * @author anhaohao - */ -@Component -@Slf4j -public class CrmProductStatusParseFunction implements IParseFunction { - - public static final String NAME = "getProductStatusName"; - - @Override - public boolean executeBefore() { - return true; // 先转换值后对比 - } - - @Override - public String functionName() { - return NAME; - } - - @Override - public String apply(Object value) { - if (StrUtil.isEmptyIfStr(value)) { - return ""; - } - return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.CRM_PRODUCT_STATUS, value.toString()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductUnitParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductUnitParseFunction.java deleted file mode 100644 index da7b82d164..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmProductUnitParseFunction.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.operatelog.core; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.dict.util.DictFrameworkUtils; -import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; -import com.mzt.logapi.service.IParseFunction; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -/** - * 产品单位的 {@link IParseFunction} 实现类 - * - * @author anhaohao - */ -@Component -@Slf4j -public class CrmProductUnitParseFunction implements IParseFunction { - - public static final String NAME = "getProductUnitName"; - - @Override - public boolean executeBefore() { - return true; // 先转换值后对比 - } - - @Override - public String functionName() { - return NAME; - } - - @Override - public String apply(Object value) { - if (StrUtil.isEmptyIfStr(value)) { - return ""; - } - return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.CRM_PRODUCT_UNIT, value.toString()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivablePlanParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivablePlanParseFunction.java deleted file mode 100644 index e9943eb671..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivablePlanParseFunction.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.operatelog.core; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; -import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivablePlanService; -import com.mzt.logapi.service.IParseFunction; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * CRM 回款计划的 {@link IParseFunction} 实现类 - * - * @author HUIHUI - */ -@Component -@Slf4j -public class CrmReceivablePlanParseFunction implements IParseFunction { - - public static final String NAME = "getReceivablePlanServiceById"; - - @Resource - private CrmReceivablePlanService receivablePlanService; - - @Override - public boolean executeBefore() { - return true; // 先转换值后对比 - } - - @Override - public String functionName() { - return NAME; - } - - @Override - public String apply(Object value) { - if (StrUtil.isEmptyIfStr(value)) { - return ""; - } - CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(Long.parseLong(value.toString())); - return receivablePlan == null ? "" : receivablePlan.getPeriod().toString(); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivableReturnTypeParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivableReturnTypeParseFunction.java deleted file mode 100644 index a8e8f8d130..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmReceivableReturnTypeParseFunction.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.operatelog.core; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.dict.util.DictFrameworkUtils; -import com.mzt.logapi.service.IParseFunction; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_RECEIVABLE_RETURN_TYPE; - -/** - * CRM 回款方式的 {@link IParseFunction} 实现类 - * - * @author HUIHUI - */ -@Slf4j -@Component -public class CrmReceivableReturnTypeParseFunction implements IParseFunction { - - public static final String NAME = "getReceivableReturnType"; - - @Override - public boolean executeBefore() { - return true; // 先转换值后对比 - } - - @Override - public String functionName() { - return NAME; - } - - @Override - public String apply(Object value) { - if (StrUtil.isEmptyIfStr(value)) { - return ""; - } - return DictFrameworkUtils.getDictDataLabel(CRM_RECEIVABLE_RETURN_TYPE, value.toString()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysBooleanParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysBooleanParseFunction.java deleted file mode 100644 index 1a7e2358ad..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysBooleanParseFunction.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.operatelog.core; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.dict.util.DictFrameworkUtils; -import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; -import com.mzt.logapi.service.IParseFunction; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -/** - * 是否类型的 {@link IParseFunction} 实现类 - * - * @author HUIHUI - */ -@Component -@Slf4j -public class SysBooleanParseFunction implements IParseFunction { - - public static final String NAME = "getBoolean"; - - @Override - public boolean executeBefore() { - return true; // 先转换值后对比 - } - - @Override - public String functionName() { - return NAME; - } - - @Override - public String apply(Object value) { - if (StrUtil.isEmptyIfStr(value)) { - return ""; - } - return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.BOOLEAN_STRING, value.toString()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysSexParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysSexParseFunction.java deleted file mode 100644 index 29d2706d15..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/SysSexParseFunction.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.operatelog.core; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.dict.util.DictFrameworkUtils; -import cn.iocoder.yudao.module.system.enums.DictTypeConstants; -import com.mzt.logapi.service.IParseFunction; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -/** - * 行业的 {@link IParseFunction} 实现类 - * - * @author HUIHUI - */ -@Component -@Slf4j -public class SysSexParseFunction implements IParseFunction { - - public static final String NAME = "getSex"; - - @Override - public boolean executeBefore() { - return true; // 先转换值后对比 - } - - @Override - public String functionName() { - return NAME; - } - - @Override - public String apply(Object value) { - if (StrUtil.isEmptyIfStr(value)) { - return ""; - } - return DictFrameworkUtils.getDictDataLabel(DictTypeConstants.USER_SEX, value.toString()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java deleted file mode 100644 index deeb04e5f1..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java +++ /dev/null @@ -1,130 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.permission.core.aop; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; -import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; -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.util.CrmPermissionUtils; -import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; -import lombok.extern.slf4j.Slf4j; -import org.aspectj.lang.JoinPoint; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import java.util.*; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CRM_PERMISSION_DENIED; - -/** - * Crm 数据权限校验 AOP 切面 - * - * @author HUIHUI - */ -@Component -@Aspect -@Slf4j -public class CrmPermissionAspect { - - @Resource - private CrmPermissionService crmPermissionService; - - @Before("@annotation(crmPermission)") - public void doBefore(JoinPoint joinPoint, CrmPermission crmPermission) { - // 1.1 获取相关属性值 - Map expressionValues = parseExpressions(joinPoint, crmPermission); - Integer bizType = StrUtil.isEmpty(crmPermission.bizTypeValue()) ? - crmPermission.bizType()[0].getType() : (Integer) expressionValues.get(crmPermission.bizTypeValue()); // 模块类型 - // 1.2 处理兼容多个 bizId 的情况 - Object object = expressionValues.get(crmPermission.bizId()); // 模块数据编号 - Set bizIds = new HashSet<>(); - if (object instanceof Collection) { - bizIds.addAll(convertSet((Collection) object, item -> Long.parseLong(item.toString()))); - } else { - bizIds.add(Long.parseLong(object.toString())); - } - Integer permissionLevel = crmPermission.level().getLevel(); // 需要的权限级别 - - // 2. 逐个校验权限 - List permissionList = crmPermissionService.getPermissionListByBiz(bizType, bizIds); - Map> multiMap = convertMultiMap(permissionList, CrmPermissionDO::getBizId); - bizIds.forEach(bizId -> validatePermission(bizType, multiMap.get(bizId), permissionLevel)); - } - - private void validatePermission(Integer bizType, List bizPermissions, Integer permissionLevel) { - // 1. 如果是超级管理员则直接通过 - if (CrmPermissionUtils.isCrmAdmin()) { - return; - } - // 1.1 没有数据权限的情况 - if (CollUtil.isEmpty(bizPermissions)) { - // 公海数据如果没有团队成员大家也因该有读权限才对 - if (CrmPermissionLevelEnum.isRead(permissionLevel)) { - return; - } - // 没有数据权限的情况下超出了读权限直接报错,避免后面校验空指针 - throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.getNameByType(bizType)); - } else { // 1.2 有数据权限但是没有负责人的情况 - if (!anyMatch(bizPermissions, item -> CrmPermissionLevelEnum.isOwner(item.getLevel()))) { - if (CrmPermissionLevelEnum.isRead(permissionLevel)) { - return; - } - } - } - - // 2.1 情况一:如果自己是负责人,则默认有所有权限 - CrmPermissionDO userPermission = CollUtil.findOne(bizPermissions, permission -> ObjUtil.equal(permission.getUserId(), getUserId())); - if (userPermission != null) { - if (CrmPermissionLevelEnum.isOwner(userPermission.getLevel())) { - return; - } - // 2.2 情况二:校验自己是否有读权限 - if (CrmPermissionLevelEnum.isRead(permissionLevel)) { - if (CrmPermissionLevelEnum.isRead(userPermission.getLevel()) // 校验当前用户是否有读权限 - || CrmPermissionLevelEnum.isWrite(userPermission.getLevel())) { // 校验当前用户是否有写权限 - return; - } - } - // 2.3 情况三:校验自己是否有写权限 - if (CrmPermissionLevelEnum.isWrite(permissionLevel)) { - if (CrmPermissionLevelEnum.isWrite(userPermission.getLevel())) { // 校验当前用户是否有写权限 - return; - } - } - } - // 2.4 没有权限,抛出异常 - log.info("[doBefore][userId({}) 要求权限({}) 实际权限({}) 数据校验错误]", // 打个 info 日志,方便后续排查问题、审计 - getUserId(), permissionLevel, toJsonString(userPermission)); - throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.getNameByType(bizType)); - } - - /** - * 获得用户编号 - * - * @return 用户编号 - */ - private static Long getUserId() { - return WebFrameworkUtils.getLoginUserId(); - } - - private static Map parseExpressions(JoinPoint joinPoint, CrmPermission crmPermission) { - // 1. 需要解析的表达式 - List expressionStrings = new ArrayList<>(2); - expressionStrings.add(crmPermission.bizId()); - if (StrUtil.isNotEmpty(crmPermission.bizTypeValue())) { // 为空则表示 bizType 有值 - expressionStrings.add(crmPermission.bizTypeValue()); - } - // 2. 执行解析 - return SpringExpressionUtils.parseExpressions(joinPoint, expressionStrings); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/config/CrmWebConfiguration.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/config/CrmWebConfiguration.java deleted file mode 100644 index 4f50375324..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/config/CrmWebConfiguration.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.web.config; - -import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; -import org.springdoc.core.GroupedOpenApi; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * crm 模块的 web 组件的 Configuration - * - * @author 芋道源码 - */ -@Configuration(proxyBeanMethods = false) -public class CrmWebConfiguration { - - /** - * crm 模块的 API 分组 - */ - @Bean - public GroupedOpenApi crmGroupedOpenApi() { - return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("crm"); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/package-info.java deleted file mode 100644 index e18c3cdb51..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * trade 模块的 web 配置 - */ -package cn.iocoder.yudao.module.crm.framework.web; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/job/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/job/package-info.java deleted file mode 100644 index 2214e6b952..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/job/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 定时任务 - */ -package cn.iocoder.yudao.module.crm.job; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java deleted file mode 100644 index f71680acd8..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java +++ /dev/null @@ -1,188 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.business; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -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.business.CrmBusinessUpdateStatusReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; -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.enums.business.CrmBusinessEndStatusEnum; - -import javax.validation.Valid; -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; - -/** - * 商机 Service 接口 - * - * @author ljlleo - */ -public interface CrmBusinessService { - - /** - * 创建商机 - * - * @param createReqVO 创建信息 - * @param userId 用户编号 - * @return 编号 - */ - Long createBusiness(@Valid CrmBusinessSaveReqVO createReqVO, Long userId); - - /** - * 更新商机 - * - * @param updateReqVO 更新信息 - */ - void updateBusiness(@Valid CrmBusinessSaveReqVO updateReqVO); - - /** - * 更新商机相关跟进信息 - * - * @param id 编号 - * @param contactNextTime 下次联系时间 - * @param contactLastContent 最后联系内容 - */ - void updateBusinessFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent); - - /** - * 更新商机的下次联系时间 - * - * @param ids 编号数组 - * @param contactNextTime 下次联系时间 - */ - void updateBusinessContactNextTime(Collection ids, LocalDateTime contactNextTime); - - /** - * 更新商机的状态 - * - * @param reqVO 更新请求 - */ - void updateBusinessStatus(CrmBusinessUpdateStatusReqVO reqVO); - - /** - * 删除商机 - * - * @param id 编号 - */ - void deleteBusiness(Long id); - - /** - * 商机转移 - * - * @param reqVO 请求 - * @param userId 用户编号 - */ - void transferBusiness(CrmBusinessTransferReqVO reqVO, Long userId); - - /** - * 获得商机 - * - * @param id 编号 - * @return 商机 - */ - CrmBusinessDO getBusiness(Long id); - - /** - * 校验商机是否有效 - * - * @param id 编号 - * @return 商机 - */ - CrmBusinessDO validateBusiness(Long id); - - /** - * 获得商机列表 - * - * @param ids 编号 - * @return 商机列表 - */ - List getBusinessList(Collection ids); - - /** - * 获得商机 Map - * - * @param ids 编号 - * @return 商机 Map - */ - default Map getBusinessMap(Collection ids) { - return convertMap(getBusinessList(ids), CrmBusinessDO::getId); - } - - /** - * 获得指定商机编号的产品列表 - * - * @param businessId 商机编号 - * @return 商机产品列表 - */ - List getBusinessProductListByBusinessId(Long businessId); - - /** - * 获得商机分页 - * - * 数据权限:基于 {@link CrmBusinessDO} - * - * @param pageReqVO 分页查询 - * @param userId 用户编号 - * @return 商机分页 - */ - PageResult getBusinessPage(CrmBusinessPageReqVO pageReqVO, Long userId); - - /** - * 获得商机分页,基于指定客户 - * - * 数据权限:基于 {@link CrmCustomerDO} 读取 - * - * @param pageReqVO 分页查询 - * @return 商机分页 - */ - PageResult getBusinessPageByCustomerId(CrmBusinessPageReqVO pageReqVO); - - /** - * 获得商机分页,基于指定联系人 - * - * 数据权限:基于 {@link CrmContactDO} 读取 - * - * @param pageReqVO 分页参数 - * @return 商机分页 - */ - PageResult getBusinessPageByContact(CrmBusinessPageReqVO pageReqVO); - - /** - * 获取关联客户的商机数量 - * - * @param customerId 客户编号 - * @return 数量 - */ - Long getBusinessCountByCustomerId(Long customerId); - - /** - * 获得使用指定商机状态组的商机数量 - * - * @param statusTypeId 商机状态组编号 - * @return 数量 - */ - Long getBusinessCountByStatusTypeId(Long statusTypeId); - - /** - * 获得商机状态名称 - * - * @param endStatus 结束状态 - * @param status 商机状态 - * @return 商机状态名称 - */ - default String getBusinessStatusName(Integer endStatus, CrmBusinessStatusDO status) { - if (endStatus != null) { - return CrmBusinessEndStatusEnum.fromStatus(endStatus).getName(); - } - return status.getName(); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java deleted file mode 100644 index 47865c64f6..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java +++ /dev/null @@ -1,373 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.business; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.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.business.CrmBusinessUpdateStatusReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO; -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.contact.CrmContactBusinessService; -import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; -import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; -import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; -import cn.iocoder.yudao.module.crm.service.product.CrmProductService; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import com.mzt.logapi.context.LogRecordContext; -import com.mzt.logapi.service.impl.DiffParseFunction; -import com.mzt.logapi.starter.annotation.LogRecord; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.math.BigDecimal; -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -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.*; - -/** - * 商机 Service 实现类 - * - * @author ljlleo - */ -@Service -@Validated -public class CrmBusinessServiceImpl implements CrmBusinessService { - - @Resource - private CrmBusinessMapper businessMapper; - @Resource - private CrmBusinessProductMapper businessProductMapper; - - @Resource - private CrmBusinessStatusService businessStatusService; - @Resource - @Lazy // 延迟加载,避免循环依赖 - private CrmContractService contractService; - @Resource - private CrmCustomerService customerService; - @Resource - @Lazy // 延迟加载,避免循环依赖 - private CrmContactService contactService; - @Resource - private CrmPermissionService permissionService; - @Resource - private CrmContactBusinessService contactBusinessService; - @Resource - private CrmProductService productService; - - @Resource - private AdminUserApi adminUserApi; - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_CREATE_SUB_TYPE, bizNo = "{{#business.id}}", - success = CRM_BUSINESS_CREATE_SUCCESS) - public Long createBusiness(CrmBusinessSaveReqVO createReqVO, Long userId) { - // 1.1 校验产品项的有效性 - List businessProducts = validateBusinessProducts(createReqVO.getProducts()); - // 1.2 校验关联字段 - validateRelationDataExists(createReqVO); - - // 2.1 插入商机 - CrmBusinessDO business = BeanUtils.toBean(createReqVO, CrmBusinessDO.class); - business.setStatusId(businessStatusService.getBusinessStatusListByTypeId(createReqVO.getStatusTypeId()).get(0).getId()); // 默认状态 - calculateTotalPrice(business, businessProducts); - businessMapper.insert(business); - // 2.2 插入商机关联商品 - if (CollUtil.isNotEmpty(businessProducts)) { - businessProducts.forEach(item -> item.setBusinessId(business.getId())); - businessProductMapper.insertBatch(businessProducts); - } - - // 3. 创建数据权限 - permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(business.getOwnerUserId()) - .setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType()).setBizId(business.getId()) - .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); - - // 4. 在联系人的详情页,如果直接【新建商机】,则需要关联下 - if (createReqVO.getContactId() != null) { - contactBusinessService.createContactBusinessList(new CrmContactBusinessReqVO().setContactId(createReqVO.getContactId()) - .setBusinessIds(Collections.singletonList(business.getId()))); - } - - // 5. 记录操作日志上下文 - LogRecordContext.putVariable("business", business); - return business.getId(); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", - success = CRM_BUSINESS_UPDATE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) - public void updateBusiness(CrmBusinessSaveReqVO updateReqVO) { - updateReqVO.setOwnerUserId(null).setStatusTypeId(null); // 不允许更新的字段 - // 1.1 校验存在 - CrmBusinessDO oldBusiness = validateBusinessExists(updateReqVO.getId()); - // 1.2 校验产品项的有效性 - List businessProducts = validateBusinessProducts(updateReqVO.getProducts()); - // 1.3 校验关联字段 - validateRelationDataExists(updateReqVO); - - // 2.1 更新商机 - CrmBusinessDO updateObj = BeanUtils.toBean(updateReqVO, CrmBusinessDO.class); - calculateTotalPrice(updateObj, businessProducts); - businessMapper.updateById(updateObj); - // 2.2 更新商机关联商品 - updateBusinessProduct(updateObj.getId(), businessProducts); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldBusiness, CrmBusinessSaveReqVO.class)); - LogRecordContext.putVariable("businessName", oldBusiness.getName()); - } - - @Override - @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}", - success = CRM_BUSINESS_FOLLOW_UP_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) - public void updateBusinessFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) { - // 1. 校验存在 - CrmBusinessDO business = validateBusinessExists(id); - - // 2. 更新联系人的跟进信息 - businessMapper.updateById(new CrmBusinessDO().setId(id).setFollowUpStatus(true).setContactNextTime(contactNextTime) - .setContactLastTime(LocalDateTime.now())); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable("businessName", business.getName()); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#ids", level = CrmPermissionLevelEnum.WRITE) - public void updateBusinessContactNextTime(Collection ids, LocalDateTime contactNextTime) { - businessMapper.updateBatch(convertList(ids, id -> new CrmBusinessDO().setId(id).setContactNextTime(contactNextTime))); - } - - private void updateBusinessProduct(Long id, List newList) { - List oldList = businessProductMapper.selectListByBusinessId(id); - List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 - (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); - if (CollUtil.isNotEmpty(diffList.get(0))) { - diffList.get(0).forEach(o -> o.setBusinessId(id)); - 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 void validateRelationDataExists(CrmBusinessSaveReqVO saveReqVO) { - // 校验商机状态 - if (saveReqVO.getStatusTypeId() != null) { - businessStatusService.validateBusinessStatusType(saveReqVO.getStatusTypeId()); - } - // 校验客户 - if (saveReqVO.getCustomerId() != null) { - customerService.validateCustomer(saveReqVO.getCustomerId()); - } - // 校验联系人 - if (saveReqVO.getContactId() != null) { - contactService.validateContact(saveReqVO.getContactId()); - } - // 校验负责人 - if (saveReqVO.getOwnerUserId() != null) { - adminUserApi.validateUser(saveReqVO.getOwnerUserId()); - } - } - - private List validateBusinessProducts(List list) { - // 1. 校验产品存在 - productService.validProductList(convertSet(list, CrmBusinessSaveReqVO.Product::getProductId)); - // 2. 转化为 CrmBusinessProductDO 列表 - return convertList(list, o -> BeanUtils.toBean(o, CrmBusinessProductDO.class, - item -> item.setTotalPrice(MoneyUtils.priceMultiply(item.getBusinessPrice(), item.getCount())))); - } - - private void calculateTotalPrice(CrmBusinessDO business, List businessProducts) { - business.setTotalProductPrice(getSumValue(businessProducts, CrmBusinessProductDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); - BigDecimal discountPrice = MoneyUtils.priceMultiplyPercent(business.getTotalProductPrice(), business.getDiscountPercent()); - business.setTotalPrice(business.getTotalProductPrice().subtract(discountPrice)); - } - - @Override - @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_UPDATE_STATUS_SUB_TYPE, bizNo = "{{#reqVO.id}}", - success = CRM_BUSINESS_UPDATE_STATUS_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.WRITE) - public void updateBusinessStatus(CrmBusinessUpdateStatusReqVO reqVO) { - // 1.1 校验存在 - CrmBusinessDO business = validateBusinessExists(reqVO.getId()); - // 1.2 校验商机未结束 - if (business.getEndStatus() != null) { - throw exception(BUSINESS_UPDATE_STATUS_FAIL_END_STATUS); - } - // 1.3 校验商机状态 - CrmBusinessStatusDO status = null; - if (reqVO.getStatusId() != null) { - status = businessStatusService.validateBusinessStatus(business.getStatusTypeId(), reqVO.getStatusId()); - } - // 1.4 校验是不是状态没变更 - if ((reqVO.getStatusId() != null && reqVO.getStatusId().equals(business.getStatusId())) - || (reqVO.getEndStatus() != null && reqVO.getEndStatus().equals(business.getEndStatus()))) { - throw exception(BUSINESS_UPDATE_STATUS_FAIL_STATUS_EQUALS); - } - - // 2. 更新商机状态 - businessMapper.updateById(new CrmBusinessDO().setId(reqVO.getId()).setStatusId(reqVO.getStatusId()) - .setEndStatus(reqVO.getEndStatus())); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable("businessName", business.getName()); - LogRecordContext.putVariable("oldStatusName", getBusinessStatusName(business.getEndStatus(), - businessStatusService.getBusinessStatus(business.getStatusId()))); - LogRecordContext.putVariable("newStatusName", getBusinessStatusName(reqVO.getEndStatus(), status)); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_DELETE_SUB_TYPE, bizNo = "{{#id}}", - success = CRM_BUSINESS_DELETE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) - public void deleteBusiness(Long id) { - // 1.1 校验存在 - CrmBusinessDO business = validateBusinessExists(id); - // 1.2 校验是否关联合同 - validateContractExists(id); - - // 删除商机 - businessMapper.deleteById(id); - // 删除数据权限 - permissionService.deletePermission(CrmBizTypeEnum.CRM_BUSINESS.getType(), id); - - // 记录操作日志上下文 - LogRecordContext.putVariable("businessName", business.getName()); - } - - /** - * 删除校验合同是关联合同 - * - * @param businessId 商机id - * @author lzxhqs - */ - private void validateContractExists(Long businessId) { - if (contractService.getContractCountByBusinessId(businessId) > 0) { - throw exception(BUSINESS_DELETE_FAIL_CONTRACT_EXISTS); - } - } - - private CrmBusinessDO validateBusinessExists(Long id) { - CrmBusinessDO crmBusiness = businessMapper.selectById(id); - if (crmBusiness == null) { - throw exception(BUSINESS_NOT_EXISTS); - } - return crmBusiness; - } - - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_BUSINESS_TYPE, subType = CRM_BUSINESS_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", - success = CRM_BUSINESS_TRANSFER_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) - public void transferBusiness(CrmBusinessTransferReqVO reqVO, Long userId) { - // 1 校验商机是否存在 - CrmBusinessDO business = validateBusinessExists(reqVO.getId()); - - // 2.1 数据权限转移 - permissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_BUSINESS.getType(), - reqVO.getNewOwnerUserId(), reqVO.getId(), CrmPermissionLevelEnum.OWNER.getLevel())); - // 2.2 设置新的负责人 - businessMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); - - // 记录操作日志上下文 - LogRecordContext.putVariable("business", business); - } - - //======================= 查询相关 ======================= - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#id", level = CrmPermissionLevelEnum.READ) - public CrmBusinessDO getBusiness(Long id) { - return businessMapper.selectById(id); - } - - @Override - public CrmBusinessDO validateBusiness(Long id) { - return validateBusinessExists(id); - } - - @Override - public List getBusinessList(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return ListUtil.empty(); - } - return businessMapper.selectBatchIds(ids); - } - - @Override - public List getBusinessProductListByBusinessId(Long businessId) { - return businessProductMapper.selectListByBusinessId(businessId); - } - - @Override - public PageResult getBusinessPage(CrmBusinessPageReqVO pageReqVO, Long userId) { - return businessMapper.selectPage(pageReqVO, userId); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#pageReqVO.customerId", level = CrmPermissionLevelEnum.READ) - public PageResult getBusinessPageByCustomerId(CrmBusinessPageReqVO pageReqVO) { - return businessMapper.selectPageByCustomerId(pageReqVO); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#pageReqVO.contactId", level = CrmPermissionLevelEnum.READ) - public PageResult getBusinessPageByContact(CrmBusinessPageReqVO pageReqVO) { - // 1. 查询关联的商机编号 - List contactBusinessList = contactBusinessService.getContactBusinessListByContactId( - pageReqVO.getContactId()); - if (CollUtil.isEmpty(contactBusinessList)) { - return PageResult.empty(); - } - // 2. 查询商机分页 - return businessMapper.selectPageByContactId(pageReqVO, - convertSet(contactBusinessList, CrmContactBusinessDO::getBusinessId)); - } - - @Override - public Long getBusinessCountByCustomerId(Long customerId) { - return businessMapper.selectCount(CrmBusinessDO::getCustomerId, customerId); - } - - @Override - public Long getBusinessCountByStatusTypeId(Long statusTypeId) { - return businessMapper.selectCountByStatusTypeId(statusTypeId); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusService.java deleted file mode 100644 index 285e984d22..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusService.java +++ /dev/null @@ -1,135 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.business; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; - -import javax.validation.Valid; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; - -/** - * 商机状态 Service 接口 - * - * @author ljlleo - */ -public interface CrmBusinessStatusService { - - /** - * 创建商机状态 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createBusinessStatus(@Valid CrmBusinessStatusSaveReqVO createReqVO); - - /** - * 更新商机状态 - * - * @param updateReqVO 更新信息 - */ - void updateBusinessStatus(@Valid CrmBusinessStatusSaveReqVO updateReqVO); - - /** - * 删除商机状态 - * - * @param id 编号 - */ - void deleteBusinessStatusType(Long id); - - /** - * 获得商机状态组 - * - * @param id 编号 - * @return 商机状态组 - */ - CrmBusinessStatusTypeDO getBusinessStatusType(Long id); - - /** - * 校验商机状态组 - * - * @param id 编号 - */ - void validateBusinessStatusType(Long id); - - /** - * 获得商机状态组列表 - * - * @return 商机状态组列表 - */ - List getBusinessStatusTypeList(); - - /** - * 获得商机状态组分页 - * - * @param pageReqVO 分页查询 - * @return 商机状态组分页 - */ - PageResult getBusinessStatusTypePage(PageParam pageReqVO); - - /** - * 获得商机状态组列表 - * - * @param ids 编号数组 - * @return 商机状态组列表 - */ - List getBusinessStatusTypeList(Collection ids); - - /** - * 获得商机状态组 Map - * - * @param ids 编号数组 - * @return 商机状态组 Map - */ - default Map getBusinessStatusTypeMap(Collection ids) { - return convertMap(getBusinessStatusTypeList(ids), CrmBusinessStatusTypeDO::getId); - } - - /** - * 获得指定类型的商机状态列表 - * - * @param typeId 商机状态组编号 - * @return 商机状态列表 - */ - List getBusinessStatusListByTypeId(Long typeId); - - /** - * 获得商机状态列表 - * - * @param ids 编号数组 - * @return 商机状态列表 - */ - List getBusinessStatusList(Collection ids); - - /** - * 获得商机状态 Map - * - * @param ids 编号数组 - * @return 商机状态 Map - */ - default Map getBusinessStatusMap(Collection ids) { - return convertMap(getBusinessStatusList(ids), CrmBusinessStatusDO::getId); - } - - /** - * 获得商机状态 - * - * @param id 编号 - * @return 商机状态 - */ - CrmBusinessStatusDO getBusinessStatus(Long id); - - /** - * 校验商机状态 - * - * @param statusTypeId 商机状态组编号 - * @param statusId 商机状态编号 - */ - CrmBusinessStatusDO validateBusinessStatus(Long statusTypeId, Long statusId); - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusServiceImpl.java deleted file mode 100644 index 3c2e0b6646..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusServiceImpl.java +++ /dev/null @@ -1,195 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.business; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO; -import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessStatusMapper; -import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessStatusTypeMapper; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; - -/** - * 商机状态 Service 实现类 - * - * @author ljlleo - */ -@Service -@Validated -public class CrmBusinessStatusServiceImpl implements CrmBusinessStatusService { - - @Resource - private CrmBusinessStatusTypeMapper businessStatusTypeMapper; - @Resource - private CrmBusinessStatusMapper businessStatusMapper; - - @Resource - @Lazy // 延迟加载,避免循环依赖 - private CrmBusinessService businessService; - - @Override - @Transactional(rollbackFor = Exception.class) - public Long createBusinessStatus(CrmBusinessStatusSaveReqVO createReqVO) { - // 1.1 检验名称是否存在 - validateBusinessStatusTypeNameUnique(createReqVO.getName(), null); - // 1.2 设置状态的排序 - int sort = 0; - for (CrmBusinessStatusSaveReqVO.Status status : createReqVO.getStatuses()) { - status.setSort(sort++); - } - - // 2.1 插入类型 - CrmBusinessStatusTypeDO statusType = BeanUtils.toBean(createReqVO, CrmBusinessStatusTypeDO.class); - businessStatusTypeMapper.insert(statusType); - // 2.2 插入状态 - List statuses = BeanUtils.toBean(createReqVO.getStatuses(), CrmBusinessStatusDO.class, - status -> status.setTypeId(statusType.getId())); - businessStatusMapper.insertBatch(statuses); - return statusType.getId(); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updateBusinessStatus(CrmBusinessStatusSaveReqVO updateReqVO) { - // 1.1 校验存在 - validateBusinessStatusTypeExists(updateReqVO.getId()); - // 1.2 校验名称是否存在 - validateBusinessStatusTypeNameUnique(updateReqVO.getName(), updateReqVO.getId()); - // 1.3 设置状态的排序 - int sort = 0; - for (CrmBusinessStatusSaveReqVO.Status status : updateReqVO.getStatuses()) { - status.setSort(sort++); - } - // 1.4 已经使用,无法更新 - if (businessService.getBusinessCountByStatusTypeId(updateReqVO.getId()) > 0) { - throw exception(BUSINESS_STATUS_UPDATE_FAIL_USED); - } - - // 2.1 更新类型 - CrmBusinessStatusTypeDO updateObj = BeanUtils.toBean(updateReqVO, CrmBusinessStatusTypeDO.class); - businessStatusTypeMapper.updateById(updateObj); - // 2.2 更新状态 - updateBusinessStatus(updateReqVO.getId(), BeanUtils.toBean(updateReqVO.getStatuses(), CrmBusinessStatusDO.class)); - } - - private void updateBusinessStatus(Long id, List newList) { - List oldList = businessStatusMapper.selectListByTypeId(id); - List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 - (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); - if (CollUtil.isNotEmpty(diffList.get(0))) { - diffList.get(0).forEach(o -> o.setTypeId(id)); - businessStatusMapper.insertBatch(diffList.get(0)); - } - if (CollUtil.isNotEmpty(diffList.get(1))) { - businessStatusMapper.updateBatch(diffList.get(1)); - } - if (CollUtil.isNotEmpty(diffList.get(2))) { - businessStatusMapper.deleteBatchIds(convertSet(diffList.get(2), CrmBusinessStatusDO::getId)); - } - } - - private void validateBusinessStatusTypeExists(Long id) { - if (businessStatusTypeMapper.selectById(id) == null) { - throw exception(BUSINESS_STATUS_TYPE_NOT_EXISTS); - } - } - - private void validateBusinessStatusTypeNameUnique(String name, Long id) { - CrmBusinessStatusTypeDO statusType = businessStatusTypeMapper.selectByName(name); - if (statusType == null - || statusType.getId().equals(id)) { - return; - } - throw exception(BUSINESS_STATUS_TYPE_NAME_EXISTS); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void deleteBusinessStatusType(Long id) { - // 1.1 校验存在 - validateBusinessStatusTypeExists(id); - // 1.2 已经使用,无法更新 - if (businessService.getBusinessCountByStatusTypeId(id) > 0) { - throw exception(BUSINESS_STATUS_DELETE_FAIL_USED); - } - - // 2.1 删除类型 - businessStatusTypeMapper.deleteById(id); - // 2.2 删除状态 - businessStatusMapper.deleteByTypeId(id); - } - - @Override - public CrmBusinessStatusTypeDO getBusinessStatusType(Long id) { - return businessStatusTypeMapper.selectById(id); - } - - @Override - public void validateBusinessStatusType(Long id) { - validateBusinessStatusTypeExists(id); - } - - @Override - public List getBusinessStatusTypeList() { - return businessStatusTypeMapper.selectList(); - } - - @Override - public PageResult getBusinessStatusTypePage(PageParam pageReqVO) { - return businessStatusTypeMapper.selectPage(pageReqVO); - } - - @Override - public List getBusinessStatusTypeList(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return Collections.emptyList(); - } - return businessStatusTypeMapper.selectBatchIds(ids); - } - - @Override - public List getBusinessStatusListByTypeId(Long typeId) { - List list = businessStatusMapper.selectListByTypeId(typeId); - list.sort(Comparator.comparingInt(CrmBusinessStatusDO::getSort)); - return list; - } - - @Override - public List getBusinessStatusList(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return Collections.emptyList(); - } - return businessStatusMapper.selectBatchIds(ids); - } - - @Override - public CrmBusinessStatusDO getBusinessStatus(Long id) { - return businessStatusMapper.selectById(id); - } - - @Override - public CrmBusinessStatusDO validateBusinessStatus(Long statusTypeId, Long statusId) { - CrmBusinessStatusDO status = businessStatusMapper.selectByTypeIdAndId(statusTypeId, statusId); - if (status == null) { - throw exception(BUSINESS_STATUS_NOT_EXISTS); - } - return status; - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java deleted file mode 100644 index b325bfd257..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java +++ /dev/null @@ -1,101 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.clue; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueSaveReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransferReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; - -import javax.validation.Valid; -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; - -/** - * 线索 Service 接口 - * - * @author Wanwan - */ -public interface CrmClueService { - - /** - * 创建线索 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createClue(@Valid CrmClueSaveReqVO createReqVO); - - /** - * 更新线索 - * - * @param updateReqVO 更新信息 - */ - void updateClue(@Valid CrmClueSaveReqVO updateReqVO); - - /** - * 更新线索相关的跟进信息 - * - * @param id 编号 - * @param contactNextTime 下次联系时间 - * @param contactLastContent 最后联系内容 - */ - void updateClueFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent); - - /** - * 删除线索 - * - * @param id 编号 - */ - void deleteClue(Long id); - - /** - * 获得线索 - * - * @param id 编号 - * @return 线索 - */ - CrmClueDO getClue(Long id); - - /** - * 获得线索列表 - * - * @param ids 编号 - * @return 线索列表 - */ - List getClueList(Collection ids, Long userId); - - /** - * 获得线索分页 - * - * @param pageReqVO 分页查询 - * @param userId 用户编号 - * @return 线索分页 - */ - PageResult getCluePage(CrmCluePageReqVO pageReqVO, Long userId); - - /** - * 线索转移 - * - * @param reqVO 请求 - * @param userId 用户编号 - */ - void transferClue(CrmClueTransferReqVO reqVO, Long userId); - - /** - * 线索转化为客户 - * - * @param id 线索编号 - * @param userId 用户编号 - */ - void transformClue(Long id, Long userId); - - /** - * 获得分配给我的、待跟进的线索数量 - * - * @param userId 用户编号 - * @return 数量 - */ - Long getFollowClueCount(Long userId); - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java deleted file mode 100644 index 304dcc2078..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java +++ /dev/null @@ -1,241 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.clue; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; -import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueSaveReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmClueTransferReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.CrmCustomerSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; -import cn.iocoder.yudao.module.crm.dal.mysql.clue.CrmClueMapper; -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.customer.CrmCustomerService; -import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO; -import cn.iocoder.yudao.module.crm.service.followup.CrmFollowUpRecordService; -import cn.iocoder.yudao.module.crm.service.followup.bo.CrmFollowUpCreateReqBO; -import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import com.mzt.logapi.context.LogRecordContext; -import com.mzt.logapi.service.impl.DiffParseFunction; -import com.mzt.logapi.starter.annotation.LogRecord; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; -import java.util.Objects; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.singleton; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CLUE_NOT_EXISTS; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CLUE_TRANSFORM_FAIL_ALREADY; -import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS; - -/** - * 线索 Service 实现类 - * - * @author Wanwan - */ -@Service -@Validated -public class CrmClueServiceImpl implements CrmClueService { - - @Resource - private CrmClueMapper clueMapper; - - @Resource - private CrmCustomerService customerService; - @Resource - private CrmPermissionService crmPermissionService; - @Resource - private CrmFollowUpRecordService followUpRecordService; - - @Resource - private AdminUserApi adminUserApi; - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_CREATE_SUB_TYPE, bizNo = "{{#clue.id}}", - success = CRM_CLUE_CREATE_SUCCESS) - public Long createClue(CrmClueSaveReqVO createReqVO) { - // 1.1 校验关联数据 - validateRelationDataExists(createReqVO); - // 1.2 校验负责人是否存在 - adminUserApi.validateUser(createReqVO.getOwnerUserId()); - - // 2. 插入线索 - CrmClueDO clue = BeanUtils.toBean(createReqVO, CrmClueDO.class); - clueMapper.insert(clue); - - // 3. 创建数据权限 - CrmPermissionCreateReqBO createReqBO = new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CLUE.getType()) - .setBizId(clue.getId()).setUserId(clue.getOwnerUserId()).setLevel(CrmPermissionLevelEnum.OWNER.getLevel()); - crmPermissionService.createPermission(createReqBO); - - // 4. 记录操作日志上下文 - LogRecordContext.putVariable("clue", clue); - return clue.getId(); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", - success = CRM_CLUE_UPDATE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#updateReq.id", level = CrmPermissionLevelEnum.OWNER) - public void updateClue(CrmClueSaveReqVO updateReq) { - Assert.notNull(updateReq.getId(), "线索编号不能为空"); - // 1.1 校验线索是否存在 - CrmClueDO oldClue = validateClueExists(updateReq.getId()); - // 1.2 校验关联数据 - validateRelationDataExists(updateReq); - - // 2. 更新线索 - CrmClueDO updateObj = BeanUtils.toBean(updateReq, CrmClueDO.class); - clueMapper.updateById(updateObj); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldClue, CrmCustomerSaveReqVO.class)); - LogRecordContext.putVariable("clueName", oldClue.getName()); - } - - private void validateRelationDataExists(CrmClueSaveReqVO reqVO) { - // 校验负责人 - if (Objects.nonNull(reqVO.getOwnerUserId()) && - Objects.isNull(adminUserApi.getUser(reqVO.getOwnerUserId()))) { - throw exception(USER_NOT_EXISTS); - } - } - - @Override - @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}", - success = CRM_CLUE_FOLLOW_UP_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) - public void updateClueFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) { - // 校验线索是否存在 - CrmClueDO oldClue = validateClueExists(id); - - // 更新线索 - clueMapper.updateById(new CrmClueDO().setId(id).setFollowUpStatus(true).setContactNextTime(contactNextTime) - .setContactLastTime(LocalDateTime.now()).setContactLastContent(contactLastContent)); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable("clueName", oldClue.getName()); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_DELETE_SUB_TYPE, bizNo = "{{#id}}", - success = CRM_CLUE_DELETE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) - public void deleteClue(Long id) { - // 1. 校验存在 - CrmClueDO clue = validateClueExists(id); - - // 2. 删除 - clueMapper.deleteById(id); - - // 3. 删除数据权限 - crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_CLUE.getType(), id); - - // 4. 删除跟进 - followUpRecordService.deleteFollowUpRecordByBiz(CrmBizTypeEnum.CRM_CLUE.getType(), id); - - // 5. 记录操作日志上下文 - LogRecordContext.putVariable("clueName", clue.getName()); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", - success = CRM_CLUE_TRANSFER_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) - public void transferClue(CrmClueTransferReqVO reqVO, Long userId) { - // 1 校验线索是否存在 - CrmClueDO clue = validateClueExists(reqVO.getId()); - - // 2.1 数据权限转移 - crmPermissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CLUE.getType(), - reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); - // 2.2 设置新的负责人 - clueMapper.updateById(new CrmClueDO().setId(reqVO.getId()).setOwnerUserId(reqVO.getNewOwnerUserId())); - - // 3. 记录转移日志 - LogRecordContext.putVariable("clue", clue); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CLUE_TYPE, subType = CRM_CLUE_TRANSLATE_SUB_TYPE, bizNo = "{{#id}}", - success = CRM_CLUE_TRANSLATE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) - public void transformClue(Long id, Long userId) { - // 1.1 校验线索都存在 - CrmClueDO clue = validateClueExists(id); - // 1.2 存在已经转化的 - if (clue.getTransformStatus()) { - throw exception(CLUE_TRANSFORM_FAIL_ALREADY); - } - - // 2.1 遍历线索(未转化的线索),创建对应的客户 - Long customerId = customerService.createCustomer(BeanUtils.toBean(clue, CrmCustomerCreateReqBO.class), userId); - // 2.2 更新线索 - clueMapper.updateById(new CrmClueDO().setId(id).setTransformStatus(Boolean.TRUE).setCustomerId(customerId)); - // 2.3 复制跟进记录 - List followUpRecords = followUpRecordService.getFollowUpRecordByBiz( - CrmBizTypeEnum.CRM_CLUE.getType(), singleton(clue.getId())); - if (CollUtil.isNotEmpty(followUpRecords)) { - followUpRecordService.createFollowUpRecordBatch(convertList(followUpRecords, record -> - BeanUtils.toBean(record, CrmFollowUpCreateReqBO.class) - .setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()).setBizId(customerId))); - } - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable("clueName", clue.getName()); - } - - private CrmClueDO validateClueExists(Long id) { - CrmClueDO crmClueDO = clueMapper.selectById(id); - if (crmClueDO == null) { - throw exception(CLUE_NOT_EXISTS); - } - return crmClueDO; - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CLUE, bizId = "#id", level = CrmPermissionLevelEnum.READ) - public CrmClueDO getClue(Long id) { - return clueMapper.selectById(id); - } - - @Override - public List getClueList(Collection ids, Long userId) { - if (CollUtil.isEmpty(ids)) { - return ListUtil.empty(); - } - return clueMapper.selectBatchIds(ids, userId); - } - - @Override - public PageResult getCluePage(CrmCluePageReqVO pageReqVO, Long userId) { - return clueMapper.selectPage(pageReqVO, userId); - } - - @Override - public Long getFollowClueCount(Long userId) { - return clueMapper.selectCountByFollow(userId); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessService.java deleted file mode 100644 index e3e94cab75..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessService.java +++ /dev/null @@ -1,68 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.contact; - -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusiness2ReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO; - -import javax.validation.Valid; -import java.util.List; - -/** - * CRM 联系人与商机的关联 Service 接口 - * - * @author 芋道源码 - */ -public interface CrmContactBusinessService { - - /** - * 创建联系人与商机的关联【通过联系人,关联商机】 - * - * @param createReqVO 创建信息 - */ - void createContactBusinessList(@Valid CrmContactBusinessReqVO createReqVO); - - /** - * 创建联系人与商机的关联【通过商机,关联联系人】 - * - * @param createReqVO 创建信息 - */ - void createContactBusinessList2(@Valid CrmContactBusiness2ReqVO createReqVO); - - /** - * 删除联系人与商机的关联【通过联系人,取关商机】 - * - * @param deleteReqVO 删除信息 - */ - void deleteContactBusinessList(@Valid CrmContactBusinessReqVO deleteReqVO); - - /** - * 删除联系人与商机的关联【通过商机,取关联系人】 - * - * @param deleteReqVO 删除信息 - */ - void deleteContactBusinessList2(@Valid CrmContactBusiness2ReqVO deleteReqVO); - - /** - * 删除联系人与商机的关联,基于联系人编号 - * - * @param contactId 联系人编号 - */ - void deleteContactBusinessByContactId(Long contactId); - - /** - * 获得联系人与商机的关联列表,基于联系人编号 - * - * @param contactId 联系人编号 - * @return 联系人商机关联 - */ - List getContactBusinessListByContactId(Long contactId); - - /** - * 获得联系人与商机的关联列表,基于商机编号 - * - * @param businessId 商机编号 - * @return 联系人商机关联 - */ - List getContactBusinessListByBusinessId(Long businessId); - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessServiceImpl.java deleted file mode 100644 index c8249460bb..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessServiceImpl.java +++ /dev/null @@ -1,139 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.contact; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusiness2ReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; -import cn.iocoder.yudao.module.crm.dal.mysql.contact.CrmContactBusinessMapper; -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.CrmBusinessService; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CONTACT_NOT_EXISTS; - -/** - * 联系人与商机的关联 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class CrmContactBusinessServiceImpl implements CrmContactBusinessService { - - @Resource - private CrmContactBusinessMapper contactBusinessMapper; - - @Resource - @Lazy // 延迟加载,为了解决延迟加载 - private CrmBusinessService businessService; - @Resource - @Lazy // 延迟加载,为了解决延迟加载 - private CrmContactService contactService; - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#createReqVO.contactId", level = CrmPermissionLevelEnum.WRITE) - public void createContactBusinessList(CrmContactBusinessReqVO createReqVO) { - CrmContactDO contact = contactService.getContact(createReqVO.getContactId()); - if (contact == null) { - throw exception(CONTACT_NOT_EXISTS); - } - // 遍历处理,考虑到一般数量不会太多,代码处理简单 - List saveDOList = new ArrayList<>(); - createReqVO.getBusinessIds().forEach(businessId -> { - CrmBusinessDO business = businessService.getBusiness(businessId); - if (business == null) { - throw exception(BUSINESS_NOT_EXISTS); - } - // 关联判重 - if (contactBusinessMapper.selectByContactIdAndBusinessId(createReqVO.getContactId(), businessId) != null) { - return; - } - saveDOList.add(new CrmContactBusinessDO(null, createReqVO.getContactId(), businessId)); - }); - // 批量插入 - if (CollUtil.isNotEmpty(saveDOList)) { - contactBusinessMapper.insertBatch(saveDOList); - } - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#createReqVO.businessId", level = CrmPermissionLevelEnum.WRITE) - public void createContactBusinessList2(CrmContactBusiness2ReqVO createReqVO) { - CrmBusinessDO business = businessService.getBusiness(createReqVO.getBusinessId()); - if (business == null) { - throw exception(BUSINESS_NOT_EXISTS); - } - // 遍历处理,考虑到一般数量不会太多,代码处理简单 - List saveDOList = new ArrayList<>(); - createReqVO.getContactIds().forEach(contactId -> { - CrmContactDO contact = contactService.getContact(contactId); - if (contact == null) { - throw exception(CONTACT_NOT_EXISTS); - } - // 关联判重 - if (contactBusinessMapper.selectByContactIdAndBusinessId(contactId, createReqVO.getBusinessId()) != null) { - return; - } - saveDOList.add(new CrmContactBusinessDO(null, contactId, createReqVO.getBusinessId())); - }); - // 批量插入 - if (CollUtil.isNotEmpty(saveDOList)) { - contactBusinessMapper.insertBatch(saveDOList); - } - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#deleteReqVO.contactId", level = CrmPermissionLevelEnum.WRITE) - public void deleteContactBusinessList(CrmContactBusinessReqVO deleteReqVO) { - CrmContactDO contact = contactService.getContact(deleteReqVO.getContactId()); - if (contact == null) { - throw exception(CONTACT_NOT_EXISTS); - } - // 直接删除 - contactBusinessMapper.deleteByContactIdAndBusinessId( - deleteReqVO.getContactId(), deleteReqVO.getBusinessIds()); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#deleteReqVO.businessId", level = CrmPermissionLevelEnum.WRITE) - public void deleteContactBusinessList2(CrmContactBusiness2ReqVO deleteReqVO) { - CrmBusinessDO business = businessService.getBusiness(deleteReqVO.getBusinessId()); - if (business == null) { - throw exception(BUSINESS_NOT_EXISTS); - } - // 直接删除 - contactBusinessMapper.deleteByBusinessIdAndContactId( - deleteReqVO.getBusinessId(), deleteReqVO.getContactIds()); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#contactId", level = CrmPermissionLevelEnum.WRITE) - public void deleteContactBusinessByContactId(Long contactId) { - contactBusinessMapper.delete(CrmContactBusinessDO::getContactId, contactId); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#contactId", level = CrmPermissionLevelEnum.READ) - public List getContactBusinessListByContactId(Long contactId) { - return contactBusinessMapper.selectListByContactId(contactId); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#businessId", level = CrmPermissionLevelEnum.READ) - public List getContactBusinessListByBusinessId(Long businessId) { - return contactBusinessMapper.selectListByBusinessId(businessId); - } - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java deleted file mode 100644 index 72ddd37bd9..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java +++ /dev/null @@ -1,163 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.contact; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactSaveReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactTransferReqVO; -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 javax.validation.Valid; -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; - -/** - * CRM 联系人 Service 接口 - * - * @author 芋道源码 - */ -public interface CrmContactService { - - /** - * 创建联系人 - * - * @param createReqVO 创建信息 - * @param userId 用户编号 - * @return 编号 - */ - Long createContact(@Valid CrmContactSaveReqVO createReqVO, Long userId); - - /** - * 更新联系人 - * - * @param updateReqVO 更新信息 - */ - void updateContact(@Valid CrmContactSaveReqVO updateReqVO); - - /** - * 删除联系人 - * - * @param id 编号 - */ - void deleteContact(Long id); - - /** - * 联系人转移 - * - * @param reqVO 请求 - * @param userId 用户编号 - */ - void transferContact(CrmContactTransferReqVO reqVO, Long userId); - - /** - * 更新指定客户的联系人的负责人 - * 数据权限基于 【客户】 - * - * @param customerId 客户编号 - * @param ownerUserId 用户编号 - */ - void updateOwnerUserIdByCustomerId(Long customerId, Long ownerUserId); - - /** - * 更新联系人相关跟进信息 - * - * @param id 编号 - * @param contactNextTime 下次联系时间 - * @param contactLastContent 最后联系内容 - */ - void updateContactFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent); - - /** - * 更新联系人的下次联系时间 - * - * @param ids 编号数组 - * @param contactNextTime 下次联系时间 - */ - void updateContactContactNextTime(Collection ids, LocalDateTime contactNextTime); - - /** - * 获得联系人 - * - * @param id 编号 - * @return 联系人 - */ - CrmContactDO getContact(Long id); - - /** - * 校验联系人 - * - * @param id 编号 - */ - void validateContact(Long id); - - /** - * 获得联系人列表 - * - * @param ids 编号 - * @return 联系人列表 - */ - List getContactList(Collection ids); - - /** - * 获得联系人 Map - * - * @param ids 编号 - * @return 联系人 Map - */ - default Map getContactMap(Collection ids) { - return convertMap(getContactList(ids), CrmContactDO::getId); - } - - /** - * 获取联系人列表(校验权限) - * - * @param userId 用户编号 - * @return 联系人列表 - */ - List getContactList(Long userId); - - /** - * 获得联系人分页 - * - * 数据权限:基于 {@link CrmContactDO} - * - * @param pageReqVO 分页查询 - * @param userId 用户编号 - * @return 联系人分页 - */ - PageResult getContactPage(CrmContactPageReqVO pageReqVO, Long userId); - - /** - * 获得联系人分页 - * - * 数据权限:基于 {@link CrmCustomerDO} - * - * @param pageVO 分页查询 - * @return 联系人分页 - */ - PageResult getContactPageByCustomerId(CrmContactPageReqVO pageVO); - - /** - * 获得联系人分页 - * - * 数据权限:基于 {@link CrmBusinessDO} - * - * @param pageVO 分页查询 - * @return 联系人分页 - */ - PageResult getContactPageByBusinessId(CrmContactPageReqVO pageVO); - - /** - * 获取关联客户的联系人数量 - * - * @param customerId 客户编号 - * @return 数量 - */ - Long getContactCountByCustomerId(Long customerId); - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java deleted file mode 100644 index fb5a23ac53..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java +++ /dev/null @@ -1,301 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.contact; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactSaveReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactTransferReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; -import cn.iocoder.yudao.module.crm.dal.mysql.contact.CrmContactMapper; -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.CrmBusinessService; -import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; -import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import com.mzt.logapi.context.LogRecordContext; -import com.mzt.logapi.service.impl.DiffParseFunction; -import com.mzt.logapi.starter.annotation.LogRecord; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; -import static java.util.Collections.singletonList; - -/** - * CRM 联系人 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class CrmContactServiceImpl implements CrmContactService { - - @Resource - private CrmContactMapper contactMapper; - - @Resource - private CrmCustomerService customerService; - @Resource - private CrmPermissionService permissionService; - @Resource - @Lazy - private CrmContractService contractService; - @Resource - private CrmContactBusinessService contactBusinessService; - @Resource - private CrmBusinessService businessService; - - @Resource - private AdminUserApi adminUserApi; - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_CREATE_SUB_TYPE, bizNo = "{{#contact.id}}", - success = CRM_CONTACT_CREATE_SUCCESS) - public Long createContact(CrmContactSaveReqVO createReqVO, Long userId) { - createReqVO.setId(null); - // 1. 校验关联数据 - validateRelationDataExists(createReqVO); - - // 2. 插入联系人 - CrmContactDO contact = BeanUtils.toBean(createReqVO, CrmContactDO.class); - contactMapper.insert(contact); - - // 3. 创建数据权限 - permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId) - .setBizType(CrmBizTypeEnum.CRM_CONTACT.getType()).setBizId(contact.getId()) - .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); - - // 4. 如果有关联商机,则需要创建关联 - if (createReqVO.getBusinessId() != null) { - contactBusinessService.createContactBusinessList(new CrmContactBusinessReqVO() - .setContactId(contact.getId()).setBusinessIds(singletonList(createReqVO.getBusinessId()))); - } - - // 5. 记录操作日志 - LogRecordContext.putVariable("contact", contact); - return contact.getId(); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", - success = CRM_CONTACT_UPDATE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) - public void updateContact(CrmContactSaveReqVO updateReqVO) { - // 1.1 校验存在 - CrmContactDO oldContact = validateContactExists(updateReqVO.getId()); - // 1.2 校验关联数据 - validateRelationDataExists(updateReqVO); - - // 2. 更新联系人 - CrmContactDO updateObj = BeanUtils.toBean(updateReqVO, CrmContactDO.class); - contactMapper.updateById(updateObj); - - // 3. 记录操作日志 - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContact, CrmContactSaveReqVO.class)); - LogRecordContext.putVariable("contactName", oldContact.getName()); - } - - /** - * 校验关联的数据都存在 - * - * @param saveReqVO 新增/修改请求 VO - */ - private void validateRelationDataExists(CrmContactSaveReqVO saveReqVO) { - // 1. 校验客户 - if (saveReqVO.getCustomerId() != null && customerService.getCustomer(saveReqVO.getCustomerId()) == null) { - customerService.validateCustomer(saveReqVO.getCustomerId()); - } - // 2. 校验负责人 - if (saveReqVO.getOwnerUserId() != null) { - adminUserApi.validateUser(saveReqVO.getOwnerUserId()); - } - // 3. 直属上级 - if (saveReqVO.getParentId() != null) { - validateContactExists(saveReqVO.getParentId()); - } - // 4. 如果有关联商机,则需要校验存在 - if (saveReqVO.getBusinessId() != null && businessService.getBusiness(saveReqVO.getBusinessId()) == null) { - throw exception(BUSINESS_NOT_EXISTS); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_DELETE_SUB_TYPE, bizNo = "{{#id}}", - success = CRM_CONTACT_DELETE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) - public void deleteContact(Long id) { - // 1.1 校验存在 - CrmContactDO contact = validateContactExists(id); - // 1.2 校验是否关联合同 - if (contractService.getContractCountByContactId(id) > 0) { - throw exception(CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS); - } - - // 2. 删除联系人 - contactMapper.deleteById(id); - - // 4.1 删除数据权限 - permissionService.deletePermission(CrmBizTypeEnum.CRM_CONTACT.getType(), id); - // 4.2 删除商机关联 - contactBusinessService.deleteContactBusinessByContactId(id); - - // 记录操作日志上下文 - LogRecordContext.putVariable("contactName", contact.getName()); - } - - private CrmContactDO validateContactExists(Long id) { - CrmContactDO contact = contactMapper.selectById(id); - if (contact == null) { - throw exception(CONTACT_NOT_EXISTS); - } - return contact; - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", - success = CRM_CONTACT_TRANSFER_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) - public void transferContact(CrmContactTransferReqVO reqVO, Long userId) { - // 1 校验联系人是否存在 - CrmContactDO contact = validateContactExists(reqVO.getId()); - - // 2.1 数据权限转移 - permissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CONTACT.getType(), - reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); - // 2.2 设置新的负责人 - contactMapper.updateById(new CrmContactDO().setId(reqVO.getId()).setOwnerUserId(reqVO.getNewOwnerUserId())); - - // 3. 记录转移日志 - LogRecordContext.putVariable("contact", contact); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#customerId", level = CrmPermissionLevelEnum.OWNER) - public void updateOwnerUserIdByCustomerId(Long customerId, Long ownerUserId) { - // 1. 校验存在 - List contacts = contactMapper.selectListByCustomerId(customerId); - if (CollUtil.isEmpty(contacts)) { - return; - } - int count = contactMapper.updateOwnerUserIdByCustomerId(customerId, ownerUserId); - if (count == 0) { - throw exception(CONTACT_UPDATE_OWNER_USER_FAIL); - } - - // 2. 记录操作日志 - for (CrmContactDO contact : contacts) { - receiveContactLog(contact, ownerUserId); - } - } - - @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_UPDATE_OWNER_USER_SUB_TYPE, bizNo = "{{#contact.id}", - success = CRM_CONTACT_UPDATE_OWNER_USER_SUCCESS) - public void receiveContactLog(CrmContactDO contact, Long ownerUserId) { - // 记录操作日志上下文 - LogRecordContext.putVariable("contact", contact); - LogRecordContext.putVariable("ownerUserId", ownerUserId); - } - - @Override - @LogRecord(type = CRM_CONTACT_TYPE, subType = CRM_CONTACT_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}", - success = CRM_CONTACT_FOLLOW_UP_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) - public void updateContactFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) { - // 1. 校验存在 - CrmContactDO contact = validateContactExists(id); - - // 2. 更新联系人的跟进信息 - contactMapper.updateById(new CrmContactDO().setId(id).setContactNextTime(contactNextTime) - .setContactLastTime(LocalDateTime.now()).setContactLastContent(contactLastContent)); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable("contactName", contact.getName()); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#ids", level = CrmPermissionLevelEnum.WRITE) - public void updateContactContactNextTime(Collection ids, LocalDateTime contactNextTime) { - contactMapper.updateBatch(convertList(ids, id -> new CrmContactDO().setId(id).setContactNextTime(contactNextTime))); - } - - //======================= 查询相关 ======================= - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#id", level = CrmPermissionLevelEnum.READ) - public CrmContactDO getContact(Long id) { - return contactMapper.selectById(id); - } - - @Override - public void validateContact(Long id) { - validateContactExists(id); - } - - @Override - public List getContactList(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return ListUtil.empty(); - } - return contactMapper.selectBatchIds(ids); - } - - @Override - public List getContactList(Long userId) { - CrmContactPageReqVO reqVO = new CrmContactPageReqVO(); - reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 - return contactMapper.selectPage(reqVO, userId).getList(); - } - - @Override - public PageResult getContactPage(CrmContactPageReqVO pageReqVO, Long userId) { - return contactMapper.selectPage(pageReqVO, userId); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#pageVO.customerId", level = CrmPermissionLevelEnum.READ) - public PageResult getContactPageByCustomerId(CrmContactPageReqVO pageVO) { - return contactMapper.selectPageByCustomerId(pageVO); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#pageVO.businessId", level = CrmPermissionLevelEnum.READ) - public PageResult getContactPageByBusinessId(CrmContactPageReqVO pageVO) { - List contactBusinessList = contactBusinessService.getContactBusinessListByBusinessId(pageVO.getBusinessId()); - if (CollUtil.isEmpty(contactBusinessList)) { - return PageResult.empty(); - } - return contactMapper.selectPageByBusinessId(pageVO, convertSet(contactBusinessList, CrmContactBusinessDO::getContactId)); - } - - @Override - public Long getContactCountByCustomerId(Long customerId) { - return contactMapper.selectCount(CrmContactDO::getCustomerId, customerId); - } - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigService.java deleted file mode 100644 index 39a06649a1..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigService.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.contract; - -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config.CrmContractConfigSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractConfigDO; - -import javax.validation.Valid; - -/** - * 合同配置 Service 接口 - * - * @author 芋道源码 - */ -public interface CrmContractConfigService { - - /** - * 获得合同配置 - * - * @return 合同配置 - */ - CrmContractConfigDO getContractConfig(); - - /** - * 保存合同配置 - * - * @param saveReqVO 更新信息 - */ - void saveContractConfig(@Valid CrmContractConfigSaveReqVO saveReqVO); - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigServiceImpl.java deleted file mode 100644 index 2580cc30c8..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractConfigServiceImpl.java +++ /dev/null @@ -1,56 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.contract; - -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.config.CrmContractConfigSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractConfigDO; -import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractConfigMapper; -import com.mzt.logapi.context.LogRecordContext; -import com.mzt.logapi.starter.annotation.LogRecord; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.util.Objects; - -import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; - -/** - * 合同配置 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class CrmContractConfigServiceImpl implements CrmContractConfigService { - - @Resource - private CrmContractConfigMapper contractConfigMapper; - - @Override - public CrmContractConfigDO getContractConfig() { - return contractConfigMapper.selectOne(); - } - - @Override - @LogRecord(type = CRM_CONTRACT_CONFIG_TYPE, subType = CRM_CONTRACT_CONFIG_SUB_TYPE, bizNo = "{{#configId}}", - success = CRM_CONTRACT_CONFIG_SUCCESS) - public void saveContractConfig(CrmContractConfigSaveReqVO saveReqVO) { - // 1. 存在,则进行更新 - CrmContractConfigDO dbConfig = getContractConfig(); - CrmContractConfigDO config = BeanUtils.toBean(saveReqVO, CrmContractConfigDO.class); - if (Objects.nonNull(dbConfig)) { - contractConfigMapper.updateById(config.setId(dbConfig.getId())); - // 记录操作日志上下文 - LogRecordContext.putVariable("isConfigUpdate", Boolean.TRUE); - LogRecordContext.putVariable("configId", config.getId()); - return; - } - - // 2. 不存在,则进行插入 - contractConfigMapper.insert(config); - // 记录操作日志上下文 - LogRecordContext.putVariable("isConfigUpdate", Boolean.FALSE); - LogRecordContext.putVariable("configId", config.getId()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java deleted file mode 100644 index 10be39142f..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java +++ /dev/null @@ -1,196 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.contract; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractSaveReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractTransferReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; -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 javax.validation.Valid; -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; - -/** - * CRM 合同 Service 接口 - * - * @author dhb52 - */ -public interface CrmContractService { - - /** - * 创建合同 - * - * @param createReqVO 创建信息 - * @param userId 用户编号 - * @return 编号 - */ - Long createContract(@Valid CrmContractSaveReqVO createReqVO, Long userId); - - /** - * 更新合同 - * - * @param updateReqVO 更新信息 - */ - void updateContract(@Valid CrmContractSaveReqVO updateReqVO); - - /** - * 删除合同 - * - * @param id 编号 - */ - void deleteContract(Long id); - - /** - * 合同转移 - * - * @param reqVO 请求 - * @param userId 用户编号 - */ - void transferContract(CrmContractTransferReqVO reqVO, Long userId); - - /** - * 更新合同相关的更进信息 - * - * @param id 合同编号 - * @param contactNextTime 下次联系时间 - * @param contactLastContent 最后联系内容 - */ - void updateContractFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent); - - /** - * 发起合同审批流程 - * - * @param id 合同编号 - * @param userId 用户编号 - */ - void submitContract(Long id, Long userId); - - /** - * 更新合同流程审批结果 - * - * @param id 合同编号 - * @param bpmResult BPM 审批结果 - */ - void updateContractAuditStatus(Long id, Integer bpmResult); - - /** - * 获得合同 - * - * @param id 编号 - * @return 合同 - */ - CrmContractDO getContract(Long id); - - /** - * 校验合同是否合法 - * - * @param id 编号 - * @return 合同 - */ - CrmContractDO validateContract(Long id); - - /** - * 获得合同列表 - * - * @param ids 编号 - * @return 合同列表 - */ - List getContractList(Collection ids); - - /** - * 获得合同 Map - * - * @param ids 编号 - * @return 合同 Map - */ - default Map getContractMap(Collection ids) { - return convertMap(getContractList(ids), CrmContractDO::getId); - } - - /** - * 获得合同分页 - * - * 数据权限:基于 {@link CrmContractDO} 读取 - * - * @param pageReqVO 分页查询 - * @param userId 用户编号 - * @return 合同分页 - */ - PageResult getContractPage(CrmContractPageReqVO pageReqVO, Long userId); - - /** - * 获得合同分页,基于指定客户 - * - * 数据权限:基于 {@link CrmCustomerDO} 读取 - * - * @param pageReqVO 分页查询 - * @return 合同分页 - */ - PageResult getContractPageByCustomerId(CrmContractPageReqVO pageReqVO); - - /** - * 获得合同分页,基于指定商机 - * - * 数据权限:基于 {@link CrmBusinessDO} 读取 - * - * @param pageReqVO 分页查询 - * @return 合同分页 - */ - PageResult getContractPageByBusinessId(CrmContractPageReqVO pageReqVO); - - /** - * 查询属于某个联系人的合同数量 - * - * @param contactId 联系人ID - * @return 合同 - */ - Long getContractCountByContactId(Long contactId); - - /** - * 获取关联客户的合同数量 - * - * @param customerId 客户编号 - * @return 数量 - */ - Long getContractCountByCustomerId(Long customerId); - - /** - * 根据商机编号,获取关联客户的合同数量 - * - * @param businessId 商机编号 - * @return 数量 - */ - Long getContractCountByBusinessId(Long businessId); - - /** - * 根据合同编号,获得合同的产品列表 - * - * @param contactId 合同编号 - * @return 产品列表 - */ - List getContractProductListByContractId(Long contactId); - - /** - * 获得待审核合同数量 - * - * @param userId 用户编号 - * @return 提醒数量 - */ - Long getAuditContractCount(Long userId); - - /** - * 获得即将到期(提醒)的合同数量 - * - * @param userId 用户编号 - * @return 提醒数量 - */ - Long getRemindContractCount(Long userId); - -} 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 deleted file mode 100644 index 54304be5df..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java +++ /dev/null @@ -1,399 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.contract; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; -import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.ObjUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; -import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractSaveReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.contract.CrmContractTransferReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractConfigDO; -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; -import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; -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.customer.CrmCustomerService; -import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; -import cn.iocoder.yudao.module.crm.service.product.CrmProductService; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import com.mzt.logapi.context.LogRecordContext; -import com.mzt.logapi.service.impl.DiffParseFunction; -import com.mzt.logapi.starter.annotation.LogRecord; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.math.BigDecimal; -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -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.*; -import static cn.iocoder.yudao.module.crm.util.CrmAuditStatusUtils.convertBpmResultToAuditStatus; - -/** - * CRM 合同 Service 实现类 - * - * @author dhb52 - */ -@Service -@Validated -@Slf4j -public class CrmContractServiceImpl implements CrmContractService { - - /** - * BPM 合同审批流程标识 - */ - public static final String BPM_PROCESS_DEFINITION_KEY = "crm-contract-audit"; - - @Resource - private CrmContractMapper contractMapper; - @Resource - private CrmContractProductMapper contractProductMapper; - - @Resource - private CrmNoRedisDAO noRedisDAO; - - @Resource - private CrmPermissionService crmPermissionService; - @Resource - private CrmProductService productService; - @Resource - private CrmCustomerService customerService; - @Resource - private CrmBusinessService businessService; - @Resource - private CrmContactService contactService; - @Resource - private CrmContractConfigService contractConfigService; - - @Resource - private AdminUserApi adminUserApi; - @Resource - private BpmProcessInstanceApi bpmProcessInstanceApi; - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_CREATE_SUB_TYPE, bizNo = "{{#contract.id}}", - success = CRM_CONTRACT_CREATE_SUCCESS) - public Long createContract(CrmContractSaveReqVO createReqVO, Long userId) { - // 1.1 校验产品项的有效性 - List contractProducts = validateContractProducts(createReqVO.getProducts()); - // 1.2 校验关联字段 - validateRelationDataExists(createReqVO); - // 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).setNo(no); - calculateTotalPrice(contract, contractProducts); - contractMapper.insert(contract); - // 2.2 插入合同关联商品 - if (CollUtil.isNotEmpty(contractProducts)) { - contractProducts.forEach(item -> item.setContractId(contract.getId())); - contractProductMapper.insertBatch(contractProducts); - } - - // 3. 创建数据权限 - crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(contract.getOwnerUserId()) - .setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()).setBizId(contract.getId()) - .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); - - // 4. 记录操作日志上下文 - LogRecordContext.putVariable("contract", contract); - return contract.getId(); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", - success = CRM_CONTRACT_UPDATE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) - public void updateContract(CrmContractSaveReqVO updateReqVO) { - Assert.notNull(updateReqVO.getId(), "合同编号不能为空"); - updateReqVO.setOwnerUserId(null); // 不允许更新的字段 - // 1.1 校验存在 - CrmContractDO contract = validateContractExists(updateReqVO.getId()); - // 1.2 只有草稿、审批中,可以编辑; - if (!ObjectUtils.equalsAny(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(), - CrmAuditStatusEnum.PROCESS.getStatus())) { - throw exception(CONTRACT_UPDATE_FAIL_NOT_DRAFT); - } - // 1.3 校验产品项的有效性 - List contractProducts = validateContractProducts(updateReqVO.getProducts()); - // 1.4 校验关联字段 - validateRelationDataExists(updateReqVO); - - // 2.1 更新合同 - CrmContractDO updateObj = BeanUtils.toBean(updateReqVO, CrmContractDO.class); - calculateTotalPrice(updateObj, contractProducts); - contractMapper.updateById(updateObj); - // 2.2 更新合同关联商品 - updateContractProduct(updateReqVO.getId(), contractProducts); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(contract, CrmContractSaveReqVO.class)); - LogRecordContext.putVariable("contractName", contract.getName()); - } - - private void updateContractProduct(Long id, List newList) { - List oldList = contractProductMapper.selectListByContractId(id); - List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 - (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); - if (CollUtil.isNotEmpty(diffList.get(0))) { - diffList.get(0).forEach(o -> o.setContractId(id)); - contractProductMapper.insertBatch(diffList.get(0)); - } - if (CollUtil.isNotEmpty(diffList.get(1))) { - contractProductMapper.updateBatch(diffList.get(1)); - } - if (CollUtil.isNotEmpty(diffList.get(2))) { - contractProductMapper.deleteBatchIds(convertSet(diffList.get(2), CrmContractProductDO::getId)); - } - } - - /** - * 校验关联数据是否存在 - * - * @param reqVO 请求 - */ - private void validateRelationDataExists(CrmContractSaveReqVO reqVO) { - // 1. 校验客户 - if (reqVO.getCustomerId() != null) { - customerService.validateCustomer(reqVO.getCustomerId()); - } - // 2. 校验负责人 - if (reqVO.getOwnerUserId() != null) { - adminUserApi.validateUser(reqVO.getOwnerUserId()); - } - // 3. 如果有关联商机,则需要校验存在 - if (reqVO.getBusinessId() != null) { - businessService.validateBusiness(reqVO.getBusinessId()); - } - // 4. 校验签约相关字段 - if (reqVO.getSignContactId() != null) { - contactService.validateContact(reqVO.getSignContactId()); - } - if (reqVO.getSignUserId() != null) { - adminUserApi.validateUser(reqVO.getSignUserId()); - } - } - - private List validateContractProducts(List list) { - // 1. 校验产品存在 - productService.validProductList(convertSet(list, CrmContractSaveReqVO.Product::getProductId)); - // 2. 转化为 CrmContractProductDO 列表 - return convertList(list, o -> BeanUtils.toBean(o, CrmContractProductDO.class, - item -> item.setTotalPrice(MoneyUtils.priceMultiply(item.getContractPrice(), item.getCount())))); - } - - private void calculateTotalPrice(CrmContractDO contract, List contractProducts) { - contract.setTotalProductPrice(getSumValue(contractProducts, CrmContractProductDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); - BigDecimal discountPrice = MoneyUtils.priceMultiplyPercent(contract.getTotalProductPrice(), contract.getDiscountPercent()); - contract.setTotalPrice(contract.getTotalProductPrice().subtract(discountPrice)); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_DELETE_SUB_TYPE, bizNo = "{{#id}}", - success = CRM_CONTRACT_DELETE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) - public void deleteContract(Long id) { - // TODO @puhui999:如果被 CrmReceivableDO 所使用,则不允许删除 - // 校验存在 - CrmContractDO contract = validateContractExists(id); - // 删除 - contractMapper.deleteById(id); - // 删除数据权限 - crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_CONTRACT.getType(), id); - - // 记录操作日志上下文 - LogRecordContext.putVariable("contractName", contract.getName()); - } - - private CrmContractDO validateContractExists(Long id) { - CrmContractDO contract = contractMapper.selectById(id); - if (contract == null) { - throw exception(CONTRACT_NOT_EXISTS); - } - return contract; - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", - success = CRM_CONTRACT_TRANSFER_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) - public void transferContract(CrmContractTransferReqVO reqVO, Long userId) { - // 1. 校验合同是否存在 - CrmContractDO contract = validateContractExists(reqVO.getId()); - - // 2.1 数据权限转移 - crmPermissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CONTRACT.getType(), - reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); - // 2.2 设置负责人 - contractMapper.updateById(new CrmContractDO().setId(reqVO.getId()).setOwnerUserId(reqVO.getNewOwnerUserId())); - - // 3. 记录转移日志 - LogRecordContext.putVariable("contract", contract); - } - - @Override - @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}", - success = CRM_CONTRACT_FOLLOW_UP_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) - public void updateContractFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) { - // 1. 校验存在 - CrmContractDO contract = validateContractExists(id); - - // 2. 更新联系人的跟进信息 - contractMapper.updateById(new CrmContractDO().setId(id).setContactLastTime(LocalDateTime.now())); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable("contractName", contract.getName()); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @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); - if (ObjUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus())) { - throw exception(CONTRACT_SUBMIT_FAIL_NOT_DRAFT); - } - - // 2. 创建合同审批流程实例 - String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO() - .setProcessDefinitionKey(BPM_PROCESS_DEFINITION_KEY).setBusinessKey(String.valueOf(id))); - - // 3. 更新合同工作流编号 - contractMapper.updateById(new CrmContractDO().setId(id).setProcessInstanceId(processInstanceId) - .setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus())); - - // 3. 记录日志 - LogRecordContext.putVariable("contractName", contract.getName()); - } - - @Override - public void updateContractAuditStatus(Long id, Integer bpmResult) { - // 1.1 校验合同是否存在 - CrmContractDO contract = validateContractExists(id); - // 1.2 只有审批中,可以更新审批结果 - if (ObjUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.PROCESS.getStatus())) { - log.error("[updateContractAuditStatus][contract({}) 不处于审批中,无法更新审批结果({})]", - contract.getId(), bpmResult); - throw exception(CONTRACT_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS); - } - - // 2. 更新合同审批结果 - Integer auditStatus = convertBpmResultToAuditStatus(bpmResult); - contractMapper.updateById(new CrmContractDO().setId(id).setAuditStatus(auditStatus)); - } - - // ======================= 查询相关 ======================= - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.READ) - public CrmContractDO getContract(Long id) { - return contractMapper.selectById(id); - } - - @Override - public CrmContractDO validateContract(Long id) { - return validateContractExists(id); - } - - @Override - public List getContractList(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return ListUtil.empty(); - } - return contractMapper.selectBatchIds(ids); - } - - @Override - public PageResult getContractPage(CrmContractPageReqVO pageReqVO, Long userId) { - // 1. 即将到期,需要查询合同配置 - CrmContractConfigDO config = null; - if (CrmContractPageReqVO.EXPIRY_TYPE_ABOUT_TO_EXPIRE.equals(pageReqVO.getExpiryType())) { - config = contractConfigService.getContractConfig(); - if (config != null && Boolean.FALSE.equals(config.getNotifyEnabled())) { - config = null; - } - } - // 2. 查询分页 - return contractMapper.selectPage(pageReqVO, userId, config); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#pageReqVO.customerId", level = CrmPermissionLevelEnum.READ) - public PageResult getContractPageByCustomerId(CrmContractPageReqVO pageReqVO) { - return contractMapper.selectPageByCustomerId(pageReqVO); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#pageReqVO.businessId", level = CrmPermissionLevelEnum.READ) - public PageResult getContractPageByBusinessId(CrmContractPageReqVO pageReqVO) { - return contractMapper.selectPageByBusinessId(pageReqVO); - } - - @Override - public Long getContractCountByContactId(Long contactId) { - return contractMapper.selectCountByContactId(contactId); - } - - @Override - public Long getContractCountByCustomerId(Long customerId) { - return contractMapper.selectCount(CrmContractDO::getCustomerId, customerId); - } - - @Override - public Long getContractCountByBusinessId(Long businessId) { - return contractMapper.selectCountByBusinessId(businessId); - } - - @Override - public List getContractProductListByContractId(Long contactId) { - return contractProductMapper.selectListByContractId(contactId); - } - - @Override - public Long getAuditContractCount(Long userId) { - return contractMapper.selectCountByAudit(userId); - } - - @Override - public Long getRemindContractCount(Long userId) { - CrmContractConfigDO config = contractConfigService.getContractConfig(); - if (config == null || Boolean.FALSE.equals(config.getNotifyEnabled())) { - return 0L; - } - return contractMapper.selectCountByRemind(userId, config); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractResultListener.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractResultListener.java deleted file mode 100644 index cc2d150249..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/listener/CrmContractResultListener.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.contract.listener; - -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEventListener; -import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; -import cn.iocoder.yudao.module.crm.service.contract.CrmContractServiceImpl; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * 合同审批的结果的监听器实现类 - * - * @author HUIHUI - */ -@Component -public class CrmContractResultListener extends BpmProcessInstanceResultEventListener { - - @Resource - private CrmContractService contractService; - - @Override - public String getProcessDefinitionKey() { - return CrmContractServiceImpl.BPM_PROCESS_DEFINITION_KEY; - } - - @Override - protected void onEvent(BpmProcessInstanceResultEvent event) { - contractService.updateContractAuditStatus(Long.parseLong(event.getBusinessKey()), event.getResult()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java deleted file mode 100644 index b00315c673..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java +++ /dev/null @@ -1,56 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.customer; - -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.poolconfig.CrmCustomerPoolConfigSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; -import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerPoolConfigMapper; -import com.mzt.logapi.context.LogRecordContext; -import com.mzt.logapi.starter.annotation.LogRecord; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.util.Objects; - -import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; - -/** - * 客户公海配置 Service 实现类 - * - * @author Wanwan - */ -@Service -@Validated -public class CrmCustomerPoolConfigServiceImpl implements CrmCustomerPoolConfigService { - - @Resource - private CrmCustomerPoolConfigMapper customerPoolConfigMapper; - - @Override - public CrmCustomerPoolConfigDO getCustomerPoolConfig() { - return customerPoolConfigMapper.selectOne(); - } - - @Override - @LogRecord(type = CRM_CUSTOMER_POOL_CONFIG_TYPE, subType = CRM_CUSTOMER_POOL_CONFIG_SUB_TYPE, bizNo = "{{#poolConfigId}}", - success = CRM_CUSTOMER_POOL_CONFIG_SUCCESS) - public void saveCustomerPoolConfig(CrmCustomerPoolConfigSaveReqVO saveReqVO) { - // 1. 存在,则进行更新 - CrmCustomerPoolConfigDO dbConfig = getCustomerPoolConfig(); - CrmCustomerPoolConfigDO poolConfig = BeanUtils.toBean(saveReqVO, CrmCustomerPoolConfigDO.class); - if (Objects.nonNull(dbConfig)) { - customerPoolConfigMapper.updateById(poolConfig.setId(dbConfig.getId())); - // 记录操作日志上下文 - LogRecordContext.putVariable("isPoolConfigUpdate", Boolean.TRUE); - LogRecordContext.putVariable("poolConfigId", poolConfig.getId()); - return; - } - - // 2. 不存在,则进行插入 - customerPoolConfigMapper.insert(poolConfig); - // 记录操作日志上下文 - LogRecordContext.putVariable("isPoolConfigUpdate", Boolean.FALSE); - LogRecordContext.putVariable("poolConfigId", poolConfig.getId()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java deleted file mode 100644 index edaa65088b..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java +++ /dev/null @@ -1,198 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.customer; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.*; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; -import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO; - -import javax.validation.Valid; -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; - -/** - * 客户 Service 接口 - * - * @author Wanwan - */ -public interface CrmCustomerService { - - /** - * 创建客户 - * - * @param createReqVO 创建信息 - * @param userId 用户编号 - * @return 编号 - */ - Long createCustomer(@Valid CrmCustomerSaveReqVO createReqVO, Long userId); - - /** - * 更新客户 - * - * @param updateReqVO 更新信息 - */ - void updateCustomer(@Valid CrmCustomerSaveReqVO updateReqVO); - - /** - * 更新客户的跟进状态 - * - * @param id 编号 - * @param dealStatus 跟进状态 - */ - void updateCustomerDealStatus(Long id, Boolean dealStatus); - - /** - * 更新客户相关的跟进信息 - * - * @param id 编号 - * @param contactNextTime 下次联系时间 - * @param contactLastContent 最后联系内容 - */ - void updateCustomerFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent); - - /** - * 删除客户 - * - * @param id 编号 - */ - void deleteCustomer(Long id); - - /** - * 获得客户 - * - * @param id 编号 - * @return 客户 - */ - CrmCustomerDO getCustomer(Long id); - - /** - * 获得客户列表 - * - * @param ids 客户编号数组 - * @return 客户列表 - * @author ljlleo - */ - List getCustomerList(Collection ids); - - /** - * 获得客户 Map - * - * @param ids 客户编号数组 - * @return 客户 Map - */ - default Map getCustomerMap(Collection ids) { - return convertMap(getCustomerList(ids), CrmCustomerDO::getId); - } - - /** - * 获得客户分页 - * - * @param pageReqVO 分页查询 - * @param userId 用户编号 - * @return 客户分页 - */ - PageResult getCustomerPage(CrmCustomerPageReqVO pageReqVO, Long userId); - - /** - * 获得放入公海提醒的客户分页 - * - * @param pageVO 分页查询 - * @param userId 用户编号 - * @return 客户分页 - */ - PageResult getPutPoolRemindCustomerPage(CrmCustomerPageReqVO pageVO, Long userId); - - /** - * 获得待进入公海的客户数量 - * - * @param userId 用户编号 - * @return 提醒数量 - */ - Long getPutPoolRemindCustomerCount(Long userId); - - /** - * 获得今日需联系客户数量 - * - * @param userId 用户编号 - * @return 提醒数量 - */ - Long getTodayContactCustomerCount(Long userId); - - /** - * 获得分配给我的客户数量 - * - * @param userId 用户编号 - * @return 提醒数量 - */ - Long getFollowCustomerCount(Long userId); - - /** - * 校验客户是否存在 - * - * @param id 编号 - */ - void validateCustomer(Long id); - - /** - * 客户转移 - * - * @param reqVO 请求 - * @param userId 用户编号 - */ - void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId); - - /** - * 锁定/解锁客户 - * - * @param lockReqVO 更新信息 - * @param userId 用户编号 - */ - void lockCustomer(@Valid CrmCustomerLockReqVO lockReqVO, Long userId); - - /** - * 创建客户 - * - * @param customerCreateReq 请求信息 - * @param userId 用户编号 - * @return 客户列表 - */ - Long createCustomer(CrmCustomerCreateReqBO customerCreateReq, Long userId); - - /** - * 批量导入客户 - * - * @param importCustomers 导入客户列表 - * @param importReqVO 请求 - * @return 导入结果 - */ - CrmCustomerImportRespVO importCustomerList(List importCustomers, CrmCustomerImportReqVO importReqVO); - - // ==================== 公海相关操作 ==================== - - /** - * 客户放入公海 - * - * @param id 客户编号 - */ - void putCustomerPool(Long id); - - /** - * 领取公海客户 - * - * @param ids 要领取的客户编号数组 - * @param ownerUserId 负责人 - * @param isReceive 是/否领取;true - 领取;false - 分配 - */ - void receiveCustomer(List ids, Long ownerUserId, Boolean isReceive); - - /** - * 【系统】客户自动掉入公海 - * - * @return 掉入公海数量 - */ - int autoPutCustomerPool(); - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java deleted file mode 100644 index 3fb37f9155..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java +++ /dev/null @@ -1,622 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.customer; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.ObjUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.extra.spring.SpringUtil; -import cn.iocoder.yudao.framework.common.exception.ServiceException; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -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.customer.vo.customer.*; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; -import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper; -import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; -import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; -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.CrmBusinessService; -import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; -import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; -import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO; -import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import com.mzt.logapi.context.LogRecordContext; -import com.mzt.logapi.service.impl.DiffParseFunction; -import com.mzt.logapi.starter.annotation.LogRecord; -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; - -import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.util.*; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; -import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_LOCK_LIMIT; -import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_OWNER_LIMIT; -import static java.util.Collections.singletonList; - -/** - * 客户 Service 实现类 - * - * @author Wanwan - */ -@Service -@Slf4j -@Validated -public class CrmCustomerServiceImpl implements CrmCustomerService { - - @Resource - private CrmCustomerMapper customerMapper; - - @Resource - private CrmPermissionService permissionService; - @Resource - private CrmCustomerLimitConfigService customerLimitConfigService; - @Resource - @Lazy - private CrmCustomerPoolConfigService customerPoolConfigService; - @Resource - @Lazy - private CrmContactService contactService; - @Resource - @Lazy - private CrmBusinessService businessService; - @Resource - @Lazy - private CrmContractService contractService; - - @Resource - private AdminUserApi adminUserApi; - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_CREATE_SUB_TYPE, bizNo = "{{#customer.id}}", - success = CRM_CUSTOMER_CREATE_SUCCESS) - public Long createCustomer(CrmCustomerSaveReqVO createReqVO, Long userId) { - createReqVO.setId(null); - // 1. 校验拥有客户是否到达上限 - validateCustomerExceedOwnerLimit(createReqVO.getOwnerUserId(), 1); - - // 2. 插入客户 - CrmCustomerDO customer = initCustomer(createReqVO, userId); - customerMapper.insert(customer); - - // 3. 创建数据权限 - permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) - .setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 - - // 4. 记录操作日志上下文 - LogRecordContext.putVariable("customer", customer); - return customer.getId(); - } - - /** - * 初始化客户的通用字段 - * - * @param customer 客户信息 - * @param ownerUserId 负责人编号 - * @return 客户信息 DO - */ - private static CrmCustomerDO initCustomer(Object customer, Long ownerUserId) { - return BeanUtils.toBean(customer, CrmCustomerDO.class).setOwnerUserId(ownerUserId) - .setOwnerTime(LocalDateTime.now()); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", - success = CRM_CUSTOMER_UPDATE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) - public void updateCustomer(CrmCustomerSaveReqVO updateReqVO) { - Assert.notNull(updateReqVO.getId(), "客户编号不能为空"); - updateReqVO.setOwnerUserId(null); // 更新的时候,要把 updateReqVO 负责人设置为空,避免修改 - // 1. 校验存在 - CrmCustomerDO oldCustomer = validateCustomerExists(updateReqVO.getId()); - - // 2. 更新客户 - CrmCustomerDO updateObj = BeanUtils.toBean(updateReqVO, CrmCustomerDO.class); - customerMapper.updateById(updateObj); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomer, CrmCustomerSaveReqVO.class)); - LogRecordContext.putVariable("customerName", oldCustomer.getName()); - } - - @Override - @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUB_TYPE, bizNo = "{{#id}}", - success = CRM_CUSTOMER_UPDATE_DEAL_STATUS_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) - public void updateCustomerDealStatus(Long id, Boolean dealStatus) { - // 1.1 校验存在 - CrmCustomerDO customer = validateCustomerExists(id); - // 1.2 校验是否重复操作 - if (Objects.equals(customer.getDealStatus(), dealStatus)) { - throw exception(CUSTOMER_UPDATE_DEAL_STATUS_FAIL); - } - - // 2. 更新客户的成交状态 - customerMapper.updateById(new CrmCustomerDO().setId(id).setDealStatus(dealStatus)); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable("customerName", customer.getName()); - LogRecordContext.putVariable("dealStatus", dealStatus); - } - - @Override - @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}", - success = CRM_CUSTOMER_FOLLOW_UP_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) - public void updateCustomerFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) { - // 1.1 校验存在 - CrmCustomerDO customer = validateCustomerExists(id); - - // 2. 更新客户的跟进信息 - customerMapper.updateById(new CrmCustomerDO().setId(id).setFollowUpStatus(true).setContactNextTime(contactNextTime) - .setContactLastTime(LocalDateTime.now()).setContactLastContent(contactLastContent)); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable("customerName", customer.getName()); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_DELETE_SUB_TYPE, bizNo = "{{#id}}", - success = CRM_CUSTOMER_DELETE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) - public void deleteCustomer(Long id) { - // 1.1 校验存在 - CrmCustomerDO customer = validateCustomerExists(id); - // 1.2 检查引用 - validateCustomerReference(id); - - // 2. 删除客户 - customerMapper.deleteById(id); - // 3. 删除数据权限 - permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id); - - // 4. 记录操作日志上下文 - LogRecordContext.putVariable("customerName", customer.getName()); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", - success = CRM_CUSTOMER_TRANSFER_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) - public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) { - // 1.1 校验客户是否存在 - CrmCustomerDO customer = validateCustomerExists(reqVO.getId()); - // 1.2 校验拥有客户是否到达上限 - validateCustomerExceedOwnerLimit(reqVO.getNewOwnerUserId(), 1); - - // 2.1 数据权限转移 - permissionService.transferPermission(new CrmPermissionTransferReqBO(userId, CrmBizTypeEnum.CRM_CUSTOMER.getType(), - reqVO.getId(), reqVO.getNewOwnerUserId(), reqVO.getOldOwnerPermissionLevel())); - // 2.2 转移后重新设置负责人 - customerMapper.updateById(new CrmCustomerDO().setId(reqVO.getId()) - .setOwnerUserId(reqVO.getNewOwnerUserId()).setOwnerTime(LocalDateTime.now())); - - // 3. 记录转移日志 - LogRecordContext.putVariable("customer", customer); - } - - @Override - @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_LOCK_SUB_TYPE, bizNo = "{{#lockReqVO.id}}", - success = CRM_CUSTOMER_LOCK_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#lockReqVO.id", level = CrmPermissionLevelEnum.OWNER) - public void lockCustomer(CrmCustomerLockReqVO lockReqVO, Long userId) { - // 1.1 校验当前客户是否存在 - CrmCustomerDO customer = validateCustomerExists(lockReqVO.getId()); - // 1.2 校验当前是否重复操作锁定/解锁状态 - if (customer.getLockStatus().equals(lockReqVO.getLockStatus())) { - throw exception(customer.getLockStatus() ? CUSTOMER_LOCK_FAIL_IS_LOCK : CUSTOMER_UNLOCK_FAIL_IS_UNLOCK); - } - // 1.3 校验锁定上限 - if (lockReqVO.getLockStatus()) { - validateCustomerExceedLockLimit(userId); - } - - // 2. 更新锁定状态 - customerMapper.updateById(BeanUtils.toBean(lockReqVO, CrmCustomerDO.class)); - - // 3. 记录操作日志上下文 - // tips: 因为这里使用的是老的状态所以记录时反着记录,也就是 lockStatus 为 true 那么就是解锁反之为锁定 - LogRecordContext.putVariable("customer", customer); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_CREATE_SUB_TYPE, bizNo = "{{#customer.id}}", - success = CRM_CUSTOMER_CREATE_SUCCESS) - public Long createCustomer(CrmCustomerCreateReqBO createReqBO, Long userId) { - // 1. 插入客户 - CrmCustomerDO customer = initCustomer(createReqBO, userId); - customerMapper.insert(customer); - - // 2. 创建数据权限 - permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) - .setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable("customer", customer); - return customer.getId(); - } - - @Override - public CrmCustomerImportRespVO importCustomerList(List importCustomers, - CrmCustomerImportReqVO importReqVO) { - // 校验非空 - importCustomers = filterList(importCustomers, item -> Objects.nonNull(item.getName())); - if (CollUtil.isEmpty(importCustomers)) { - throw exception(CUSTOMER_IMPORT_LIST_IS_EMPTY); - } - - // 逐条处理 - CrmCustomerImportRespVO respVO = CrmCustomerImportRespVO.builder().createCustomerNames(new ArrayList<>()) - .updateCustomerNames(new ArrayList<>()).failureCustomerNames(new LinkedHashMap<>()).build(); - importCustomers.forEach(importCustomer -> { - // 校验,判断是否有不符合的原因 - try { - validateCustomerForCreate(importCustomer); - } catch (ServiceException ex) { - respVO.getFailureCustomerNames().put(importCustomer.getName(), ex.getMessage()); - return; - } - // 情况一:判断如果不存在,在进行插入 - CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName()); - if (existCustomer == null) { - // 1.1 插入客户信息 - CrmCustomerDO customer = initCustomer(importCustomer, importReqVO.getOwnerUserId()); - customerMapper.insert(customer); - respVO.getCreateCustomerNames().add(importCustomer.getName()); - // 1.2 创建数据权限 - if (importReqVO.getOwnerUserId() != null) { - 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 (!importReqVO.getUpdateSupport()) { - respVO.getFailureCustomerNames().put(importCustomer.getName(), - StrUtil.format(CUSTOMER_NAME_EXISTS.getMsg(), importCustomer.getName())); - return; - } - // 2.1 更新客户信息 - CrmCustomerDO updateCustomer = BeanUtils.toBean(importCustomer, CrmCustomerDO.class) - .setId(existCustomer.getId()); - customerMapper.updateById(updateCustomer); - respVO.getUpdateCustomerNames().add(importCustomer.getName()); - // 2.2 记录操作日志 - getSelf().importCustomerLog(updateCustomer, true); - }); - return respVO; - } - - /** - * 记录导入客户时的操作日志 - * - * @param customer 客户信息 - * @param isUpdate 是否更新;true - 更新,false - 新增 - */ - @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_IMPORT_SUB_TYPE, bizNo = "{{#customer.id}}", - success = CRM_CUSTOMER_IMPORT_SUCCESS) - public void importCustomerLog(CrmCustomerDO customer, boolean isUpdate) { - LogRecordContext.putVariable("customer", customer); - LogRecordContext.putVariable("isUpdate", isUpdate); - } - - // ==================== 公海相关操作 ==================== - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_POOL_SUB_TYPE, bizNo = "{{#id}}", - success = CRM_CUSTOMER_POOL_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) - public void putCustomerPool(Long id) { - // 1. 校验存在 - CrmCustomerDO customer = customerMapper.selectById(id); - if (customer == null) { - throw exception(CUSTOMER_NOT_EXISTS); - } - // 1.2. 校验是否为公海数据 - validateCustomerOwnerExists(customer, true); - // 1.3. 校验客户是否锁定 - validateCustomerIsLocked(customer, true); - - // 2. 客户放入公海 - putCustomerPool(customer); - - // 记录操作日志上下文 - LogRecordContext.putVariable("customerName", customer.getName()); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void receiveCustomer(List ids, Long ownerUserId, Boolean isReceive) { - // 1.1 校验存在 - List customers = customerMapper.selectBatchIds(ids); - if (customers.size() != ids.size()) { - throw exception(CUSTOMER_NOT_EXISTS); - } - // 1.2 校验负责人是否存在 - adminUserApi.validateUserList(singletonList(ownerUserId)); - // 1.3 校验状态 - customers.forEach(customer -> { - // 校验是否已有负责人 - validateCustomerOwnerExists(customer, false); - // 校验是否锁定 - validateCustomerIsLocked(customer, false); - // 校验成交状态 - validateCustomerDeal(customer); - }); - // 1.4 校验负责人是否到达上限 - validateCustomerExceedOwnerLimit(ownerUserId, customers.size()); - - // 2. 领取公海数据 - List updateCustomers = new ArrayList<>(); - List createPermissions = new ArrayList<>(); - customers.forEach(customer -> { - // 2.1. 设置负责人 - updateCustomers.add(new CrmCustomerDO().setId(customer.getId()) - .setOwnerUserId(ownerUserId).setOwnerTime(LocalDateTime.now())); - // 2.2. 创建负责人数据权限 - createPermissions.add(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) - .setBizId(customer.getId()).setUserId(ownerUserId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); - }); - // 2.2 更新客户负责人 - customerMapper.updateBatch(updateCustomers); - // 2.3 创建负责人数据权限 - permissionService.createPermissionBatch(createPermissions); - // TODO @芋艿:要不要处理关联的联系人??? - - // 3. 记录操作日志 - AdminUserRespDTO user = null; - if (!isReceive) { - user = adminUserApi.getUser(ownerUserId); - } - for (CrmCustomerDO customer : customers) { - getSelf().receiveCustomerLog(customer, user == null ? null : user.getNickname()); - } - } - - @Override - public int autoPutCustomerPool() { - CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig(); - if (poolConfig == null || !poolConfig.getEnabled()) { - return 0; - } - // 1. 获得需要放到的客户列表 - List customerList = customerMapper.selectListByAutoPool(poolConfig); - // 2. 逐个放入公海 - int count = 0; - for (CrmCustomerDO customer : customerList) { - try { - getSelf().putCustomerPool(customer); - count++; - } catch (Throwable e) { - log.error("[autoPutCustomerPool][客户({}) 放入公海异常]", customer.getId(), e); - } - } - return count; - } - - @Transactional(rollbackFor = Exception.class) // 需要 protected 修饰,因为需要在事务中调用 - protected void putCustomerPool(CrmCustomerDO customer) { - // 1. 设置负责人为 NULL - int updateOwnerUserIncr = customerMapper.updateOwnerUserIdById(customer.getId(), null); - if (updateOwnerUserIncr == 0) { - throw exception(CUSTOMER_UPDATE_OWNER_USER_FAIL); - } - - // 2. 联系人的负责人,也要设置为 null。因为:因为领取后,负责人也要关联过来,这块和 receiveCustomer 是对应的 - contactService.updateOwnerUserIdByCustomerId(customer.getId(), null); - - // 3. 删除负责人数据权限 - // 注意:需要放在 contactService 后面,不然【客户】数据权限已经被删除,无法操作! - permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), customer.getId(), - CrmPermissionLevelEnum.OWNER.getLevel()); - } - - @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_RECEIVE_SUB_TYPE, bizNo = "{{#customer.id}}", - success = CRM_CUSTOMER_RECEIVE_SUCCESS) - public void receiveCustomerLog(CrmCustomerDO customer, String ownerUserName) { - // 记录操作日志上下文 - LogRecordContext.putVariable("customer", customer); - LogRecordContext.putVariable("ownerUserName", ownerUserName); - } - - //======================= 查询相关 ======================= - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.READ) - public CrmCustomerDO getCustomer(Long id) { - return customerMapper.selectById(id); - } - - @Override - public List getCustomerList(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return Collections.emptyList(); - } - return customerMapper.selectBatchIds(ids); - } - - @Override - public PageResult getCustomerPage(CrmCustomerPageReqVO pageReqVO, Long userId) { - return customerMapper.selectPage(pageReqVO, userId); - } - - @Override - public PageResult getPutPoolRemindCustomerPage(CrmCustomerPageReqVO pageVO, Long userId) { - CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig(); - if (ObjUtil.isNull(poolConfig) - || Boolean.FALSE.equals(poolConfig.getEnabled()) - || Boolean.FALSE.equals(poolConfig.getNotifyEnabled())) { - return PageResult.empty(); - } - return customerMapper.selectPutPoolRemindCustomerPage(pageVO, poolConfig, userId); - } - - @Override - public Long getPutPoolRemindCustomerCount(Long userId) { - CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig(); - if (ObjUtil.isNull(poolConfig) - || Boolean.FALSE.equals(poolConfig.getEnabled()) - || Boolean.FALSE.equals(poolConfig.getNotifyEnabled())) { - return 0L; - } - CrmCustomerPageReqVO pageVO = new CrmCustomerPageReqVO() - .setPool(null) - .setContactStatus(CrmCustomerPageReqVO.CONTACT_TODAY) - .setSceneType(CrmSceneTypeEnum.OWNER.getType()); - return customerMapper.selectPutPoolRemindCustomerCount(pageVO, poolConfig, userId); - } - - @Override - public Long getTodayContactCustomerCount(Long userId) { - return customerMapper.selectCountByTodayContact(userId); - } - - @Override - public Long getFollowCustomerCount(Long userId) { - return customerMapper.selectCountByFollow(userId); - } - - // ======================= 校验相关 ======================= - - private void validateCustomerForCreate(CrmCustomerImportExcelVO importCustomer) { - // 校验客户名称不能为空 - if (StrUtil.isEmptyIfStr(importCustomer.getName())) { - throw exception(CUSTOMER_CREATE_NAME_NOT_NULL); - } - } - - /** - * 校验客户是否被引用 - * - * @param id 客户编号 - */ - private void validateCustomerReference(Long id) { - if (contactService.getContactCountByCustomerId(id) > 0) { - throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_CONTACT.getName()); - } - if (businessService.getBusinessCountByCustomerId(id) > 0) { - throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_BUSINESS.getName()); - } - if (contractService.getContractCountByCustomerId(id) > 0) { - throw exception(CUSTOMER_DELETE_FAIL_HAVE_REFERENCE, CrmBizTypeEnum.CRM_CONTRACT.getName()); - } - } - - /** - * 校验客户是否存在 - * - * @param id 客户 id - */ - @Override - public void validateCustomer(Long id) { - validateCustomerExists(id); - } - - private void validateCustomerOwnerExists(CrmCustomerDO customer, Boolean pool) { - if (customer == null) { // 防御一下 - throw exception(CUSTOMER_NOT_EXISTS); - } - // 校验是否为公海数据 - if (pool && customer.getOwnerUserId() == null) { - throw exception(CUSTOMER_IN_POOL, customer.getName()); - } - // 负责人已存在 - if (!pool && customer.getOwnerUserId() != null) { - throw exception(CUSTOMER_OWNER_EXISTS, customer.getName()); - } - } - - private CrmCustomerDO validateCustomerExists(Long id) { - CrmCustomerDO customerDO = customerMapper.selectById(id); - if (customerDO == null) { - throw exception(CUSTOMER_NOT_EXISTS); - } - return customerDO; - } - - private void validateCustomerIsLocked(CrmCustomerDO customer, Boolean pool) { - if (customer.getLockStatus()) { - throw exception(pool ? CUSTOMER_LOCKED_PUT_POOL_FAIL : CUSTOMER_LOCKED, customer.getName()); - } - } - - private void validateCustomerDeal(CrmCustomerDO customer) { - if (customer.getDealStatus()) { - throw exception(CUSTOMER_ALREADY_DEAL); - } - } - - /** - * 校验用户拥有的客户数量,是否到达上限 - * - * @param userId 用户编号 - * @param newCount 附加数量 - */ - private void validateCustomerExceedOwnerLimit(Long userId, int newCount) { - List limitConfigs = customerLimitConfigService.getCustomerLimitConfigListByUserId( - CUSTOMER_OWNER_LIMIT.getType(), userId); - if (CollUtil.isEmpty(limitConfigs)) { - return; - } - Long ownerCount = customerMapper.selectCountByDealStatusAndOwnerUserId(null, userId); - Long dealOwnerCount = customerMapper.selectCountByDealStatusAndOwnerUserId(true, userId); - limitConfigs.forEach(limitConfig -> { - long nowCount = limitConfig.getDealCountEnabled() ? ownerCount : ownerCount - dealOwnerCount; - if (nowCount + newCount > limitConfig.getMaxCount()) { - throw exception(CUSTOMER_OWNER_EXCEED_LIMIT); - } - }); - } - - /** - * 校验用户锁定的客户数量,是否到达上限 - * - * @param userId 用户编号 - */ - private void validateCustomerExceedLockLimit(Long userId) { - List limitConfigs = customerLimitConfigService.getCustomerLimitConfigListByUserId( - CUSTOMER_LOCK_LIMIT.getType(), userId); - if (CollUtil.isEmpty(limitConfigs)) { - return; - } - Long lockCount = customerMapper.selectCountByLockStatusAndOwnerUserId(true, userId); - Integer maxCount = CollectionUtils.getMaxValue(limitConfigs, CrmCustomerLimitConfigDO::getMaxCount); - assert maxCount != null; - if (lockCount >= maxCount) { - throw exception(CUSTOMER_LOCK_EXCEED_LIMIT); - } - } - - /** - * 获得自身的代理对象,解决 AOP 生效问题 - * - * @return 自己 - */ - private CrmCustomerServiceImpl getSelf() { - return SpringUtil.getBean(getClass()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/bo/CrmCustomerCreateReqBO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/bo/CrmCustomerCreateReqBO.java deleted file mode 100644 index 87a6b3387a..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/bo/CrmCustomerCreateReqBO.java +++ /dev/null @@ -1,121 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.customer.bo; - -import cn.iocoder.yudao.framework.common.validation.Mobile; -import cn.iocoder.yudao.framework.common.validation.Telephone; -import cn.iocoder.yudao.module.crm.enums.DictTypeConstants; -import javax.validation.constraints.Email; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.Size; -import lombok.Data; - -import java.time.LocalDateTime; - -/** - * 客户创建 Create Req BO - * - * @author HUIHUI - */ -@Data -public class CrmCustomerCreateReqBO { - - /** - * 客户名称 - */ - @NotEmpty(message = "客户名称不能为空") - private String name; - /** - * 跟进状态 - */ - private Boolean followUpStatus; - /** - * 锁定状态 - */ - private Boolean lockStatus; - /** - * 成交状态 - */ - private Boolean dealStatus; - /** - * 所属行业 - * - * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_INDUSTRY} - */ - private Integer industryId; - /** - * 客户等级 - * - * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_LEVEL} - */ - private Integer level; - /** - * 客户来源 - * - * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_SOURCE} - */ - private Integer source; - - /** - * 手机 - */ - @Mobile - private String mobile; - /** - * 电话 - */ - @Telephone - private String telephone; - /** - * QQ - */ - private String qq; - /** - * wechat - */ - private String wechat; - - /** - * 邮箱 - */ - @Email(message = "邮箱格式不正确") - private String email; - - /** - * 客户描述 - */ - @Size(max = 4096, message = "客户描述长度不能超过 4096 个字符") - private String description; - /** - * 备注 - */ - private String remark; - /** - * 负责人的用户编号 - * - * 关联 AdminUserDO 的 id 字段 - */ - private Long ownerUserId; - /** - * 所在地 - * - * 关联 {@link cn.iocoder.yudao.framework.ip.core.Area#getId()} 字段 - */ - private Integer areaId; - /** - * 详细地址 - */ - private String detailAddress; - - /** - * 最后跟进时间 - */ - private LocalDateTime contactLastTime; - /** - * 最后跟进内容 - */ - private String contactLastContent; - /** - * 下次联系时间 - */ - private LocalDateTime contactNextTime; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java deleted file mode 100644 index 0bc4480e33..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/followup/CrmFollowUpRecordServiceImpl.java +++ /dev/null @@ -1,149 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.followup; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.followup.vo.CrmFollowUpRecordSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO; -import cn.iocoder.yudao.module.crm.dal.mysql.followup.CrmFollowUpRecordMapper; -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.CrmBusinessService; -import cn.iocoder.yudao.module.crm.service.clue.CrmClueService; -import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; -import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; -import cn.iocoder.yudao.module.crm.service.followup.bo.CrmFollowUpCreateReqBO; -import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; -import javax.annotation.Resource; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import java.util.Collection; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_DELETE_DENIED; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_NOT_EXISTS; - -/** - * 跟进记录 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService { - - @Resource - private CrmFollowUpRecordMapper crmFollowUpRecordMapper; - - @Resource - @Lazy - private CrmPermissionService permissionService; - @Resource - @Lazy - private CrmBusinessService businessService; - @Resource - @Lazy - private CrmClueService clueService; - @Resource - @Lazy - private CrmContactService contactService; - @Resource - @Lazy - private CrmContractService contractService; - @Resource - @Lazy - private CrmCustomerService customerService; - - @Override - @CrmPermission(bizTypeValue = "#createReqVO.bizType", bizId = "#createReqVO.bizId", level = CrmPermissionLevelEnum.WRITE) - public Long createFollowUpRecord(CrmFollowUpRecordSaveReqVO createReqVO) { - // 1. 创建更进记录 - CrmFollowUpRecordDO record = BeanUtils.toBean(createReqVO, CrmFollowUpRecordDO.class); - crmFollowUpRecordMapper.insert(record); - - // 2. 更新 bizId 对应的记录 - if (ObjUtil.equal(CrmBizTypeEnum.CRM_CUSTOMER.getType(), record.getBizType())) { // 更新客户跟进信息 - customerService.updateCustomerFollowUp(record.getBizId(), record.getNextTime(), record.getContent()); - } - if (ObjUtil.equal(CrmBizTypeEnum.CRM_BUSINESS.getType(), record.getBizType())) { // 更新商机跟进信息 - businessService.updateBusinessFollowUp(record.getBizId(), record.getNextTime(), record.getContent()); - } - if (ObjUtil.equal(CrmBizTypeEnum.CRM_CLUE.getType(), record.getBizType())) { // 更新线索跟进信息 - clueService.updateClueFollowUp(record.getBizId(), record.getNextTime(), record.getContent()); - } - if (ObjUtil.equal(CrmBizTypeEnum.CRM_CONTACT.getType(), record.getBizType())) { // 更新联系人跟进信息 - contactService.updateContactFollowUp(record.getBizId(), record.getNextTime(), record.getContent()); - } - if (ObjUtil.equal(CrmBizTypeEnum.CRM_CONTRACT.getType(), record.getBizType())) { // 更新合同跟进信息 - contractService.updateContractFollowUp(record.getBizId(), record.getNextTime(), record.getContent()); - } - - // 3.1 更新 contactIds 对应的记录,只更新 nextTime - if (CollUtil.isNotEmpty(createReqVO.getContactIds())) { - contactService.updateContactContactNextTime(createReqVO.getContactIds(), createReqVO.getNextTime()); - } - // 3.2 需要更新 businessIds 对应的记录,只更新 nextTime - if (CollUtil.isNotEmpty(createReqVO.getBusinessIds())) { - businessService.updateBusinessContactNextTime(createReqVO.getBusinessIds(), createReqVO.getNextTime()); - } - return record.getId(); - } - - @Override - public void createFollowUpRecordBatch(List list) { - if (CollUtil.isEmpty(list)) { - return; - } - crmFollowUpRecordMapper.insertBatch(BeanUtils.toBean(list, CrmFollowUpRecordDO.class)); - } - - @Override - public void deleteFollowUpRecord(Long id, Long userId) { - // 校验存在 - CrmFollowUpRecordDO followUpRecord = validateFollowUpRecordExists(id); - // 校验权限 - if (!permissionService.hasPermission(followUpRecord.getBizType(), followUpRecord.getBizId(), userId, CrmPermissionLevelEnum.OWNER)) { - throw exception(FOLLOW_UP_RECORD_DELETE_DENIED); - } - - // 删除 - crmFollowUpRecordMapper.deleteById(id); - } - - @Override - public void deleteFollowUpRecordByBiz(Integer bizType, Long bizId) { - crmFollowUpRecordMapper.deleteByBiz(bizType, bizId); - } - - private CrmFollowUpRecordDO validateFollowUpRecordExists(Long id) { - CrmFollowUpRecordDO followUpRecord = crmFollowUpRecordMapper.selectById(id); - if (followUpRecord == null) { - throw exception(FOLLOW_UP_RECORD_NOT_EXISTS); - } - return followUpRecord; - } - - @Override - public CrmFollowUpRecordDO getFollowUpRecord(Long id) { - return crmFollowUpRecordMapper.selectById(id); - } - - @Override - @CrmPermission(bizTypeValue = "#pageReqVO.bizType", bizId = "#pageReqVO.bizId", level = CrmPermissionLevelEnum.READ) - public PageResult getFollowUpRecordPage(CrmFollowUpRecordPageReqVO pageReqVO) { - return crmFollowUpRecordMapper.selectPage(pageReqVO); - } - - @Override - public List getFollowUpRecordByBiz(Integer bizType, Collection bizIds) { - return crmFollowUpRecordMapper.selectListByBiz(bizType, bizIds); - } - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java deleted file mode 100644 index d67e76fa4a..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java +++ /dev/null @@ -1,223 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.permission; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjUtil; -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.permission.vo.CrmPermissionUpdateReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; -import cn.iocoder.yudao.module.crm.dal.mysql.permission.CrmPermissionMapper; -import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; -import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; -import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -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.anyMatch; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum.isOwner; - -/** - * CRM 数据权限 Service 接口实现类 - * - * @author HUIHUI - */ -@Service -@Validated -public class CrmPermissionServiceImpl implements CrmPermissionService { - - @Resource - private CrmPermissionMapper permissionMapper; - - @Resource - private AdminUserApi adminUserApi; - - @Override - @Transactional(rollbackFor = Exception.class) - public Long createPermission(CrmPermissionCreateReqBO createReqBO) { - validatePermissionNotExists(Collections.singletonList(createReqBO)); - // 1. 校验用户是否存在 - adminUserApi.validateUserList(Collections.singletonList(createReqBO.getUserId())); - - // 2. 创建 - CrmPermissionDO permission = BeanUtils.toBean(createReqBO, CrmPermissionDO.class); - permissionMapper.insert(permission); - return permission.getId(); - } - - @Override - public void createPermissionBatch(List createReqBOs) { - validatePermissionNotExists(createReqBOs); - // 1. 校验用户是否存在 - adminUserApi.validateUserList(convertSet(createReqBOs, CrmPermissionCreateReqBO::getUserId)); - - // 2. 创建 - List permissions = BeanUtils.toBean(createReqBOs, CrmPermissionDO.class); - permissionMapper.insertBatch(permissions); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updatePermission(CrmPermissionUpdateReqVO updateReqVO) { - // 1. 校验存在 - validatePermissionExists(updateReqVO.getIds()); - // 2. 更新 - List updateList = CollectionUtils.convertList(updateReqVO.getIds(), - id -> new CrmPermissionDO().setId(id).setLevel(updateReqVO.getLevel())); - permissionMapper.updateBatch(updateList); - } - - private void validatePermissionExists(Collection ids) { - List permissionList = permissionMapper.selectBatchIds(ids); - if (ObjUtil.notEqual(permissionList.size(), ids.size())) { - throw exception(CRM_PERMISSION_NOT_EXISTS); - } - } - - private void validatePermissionNotExists(Collection createReqBOs) { - Set bizTypes = convertSet(createReqBOs, CrmPermissionCreateReqBO::getBizType); - Set bizIds = convertSet(createReqBOs, CrmPermissionCreateReqBO::getBizId); - Set userIds = convertSet(createReqBOs, CrmPermissionCreateReqBO::getUserId); - Long count = permissionMapper.selectListByBiz(bizTypes, bizIds, userIds); - if (count > 0) { - throw exception(CRM_PERMISSION_CREATE_FAIL); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void transferPermission(CrmPermissionTransferReqBO transferReqBO) { - // 1. 校验数据权限:是否是负责人,只有负责人才可以转移 - CrmPermissionDO oldPermission = permissionMapper.selectByBizTypeAndBizIdByUserId( - transferReqBO.getBizType(), transferReqBO.getBizId(), transferReqBO.getUserId()); - String bizTypeName = CrmBizTypeEnum.getNameByType(transferReqBO.getBizType()); - if (oldPermission == null // 不是拥有者,并且不是超管 - || (!isOwner(oldPermission.getLevel()) && !CrmPermissionUtils.isCrmAdmin())) { - throw exception(CRM_PERMISSION_DENIED, bizTypeName); - } - // 1.1 校验转移对象是否已经是该负责人 - if (ObjUtil.equal(transferReqBO.getNewOwnerUserId(), oldPermission.getUserId())) { - throw exception(CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS, bizTypeName); - } - // 1.2 校验新负责人是否存在 - adminUserApi.validateUserList(Collections.singletonList(transferReqBO.getNewOwnerUserId())); - - // 2. 修改新负责人的权限 - List permissions = permissionMapper.selectByBizTypeAndBizId( - transferReqBO.getBizType(), transferReqBO.getBizId()); // 获得所有数据权限 - CrmPermissionDO permission = CollUtil.findOne(permissions, - item -> ObjUtil.equal(item.getUserId(), transferReqBO.getNewOwnerUserId())); - if (permission == null) { - permissionMapper.insert(new CrmPermissionDO().setBizType(transferReqBO.getBizType()) - .setBizId(transferReqBO.getBizId()).setUserId(transferReqBO.getNewOwnerUserId()) - .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); - } else { - permissionMapper.updateById(new CrmPermissionDO().setId(permission.getId()) - .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); - } - - // 3. 修改老负责人的权限 - if (transferReqBO.getOldOwnerPermissionLevel() != null) { - permissionMapper.updateById(new CrmPermissionDO().setId(oldPermission.getId()) - .setLevel(transferReqBO.getOldOwnerPermissionLevel())); - } else { - permissionMapper.deleteById(oldPermission.getId()); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void deletePermission(Integer bizType, Long bizId, Integer level) { - // 校验存在 - List permissions = permissionMapper.selectListByBizTypeAndBizIdAndLevel( - bizType, bizId, level); - if (CollUtil.isEmpty(permissions)) { - throw exception(CRM_PERMISSION_NOT_EXISTS); - } - - // 删除数据权限 - permissionMapper.deleteBatchIds(convertSet(permissions, CrmPermissionDO::getId)); - } - - @Override - public void deletePermission(Integer bizType, Long bizId) { - int deletedCount = permissionMapper.deletePermission(bizType, bizId); - if (deletedCount == 0) { - throw exception(CRM_PERMISSION_NOT_EXISTS); - } - } - - @Override - public void deletePermissionBatch(Collection ids, Long userId) { - List permissions = permissionMapper.selectBatchIds(ids); - if (CollUtil.isEmpty(permissions)) { - throw exception(CRM_PERMISSION_NOT_EXISTS); - } - // 校验:数据权限的模块数据编号是一致的不可能存在两个 - if (convertSet(permissions, CrmPermissionDO::getBizId).size() > 1) { - throw exception(CRM_PERMISSION_DELETE_FAIL); - } - // 校验操作人是否为负责人 - CrmPermissionDO permission = permissionMapper.selectByBizIdAndUserId(permissions.get(0).getBizId(), userId); - if (permission == null) { - throw exception(CRM_PERMISSION_DELETE_DENIED); - } - if (!CrmPermissionLevelEnum.isOwner(permission.getLevel())) { - throw exception(CRM_PERMISSION_DELETE_DENIED); - } - - // 删除数据权限 - permissionMapper.deleteBatchIds(ids); - } - - @Override - public void deleteSelfPermission(Long id, Long userId) { - // 校验数据存在且是自己 - CrmPermissionDO permission = permissionMapper.selectByIdAndUserId(id, userId); - if (permission == null) { - throw exception(CRM_PERMISSION_NOT_EXISTS); - } - // 校验是否是负责人 - if (CrmPermissionLevelEnum.isOwner(permission.getLevel())) { - throw exception(CRM_PERMISSION_DELETE_SELF_PERMISSION_FAIL_EXIST_OWNER); - } - - // 删除 - permissionMapper.deleteById(id); - } - - @Override - public List getPermissionListByBiz(Integer bizType, Long bizId) { - return permissionMapper.selectByBizTypeAndBizId(bizType, bizId); - } - - @Override - public List getPermissionListByBiz(Integer bizType, Collection bizIds) { - return permissionMapper.selectByBizTypeAndBizIds(bizType, bizIds); - } - - @Override - public List getPermissionListByBizTypeAndUserId(Integer bizType, Long userId) { - return permissionMapper.selectListByBizTypeAndUserId(bizType, userId); - } - - @Override - public boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum level) { - List permissionList = permissionMapper.selectByBizTypeAndBizId(bizType, bizId); - return anyMatch(permissionList, permission -> - ObjUtil.equal(permission.getUserId(), userId) && ObjUtil.equal(permission.getLevel(), level.getLevel())); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionTransferReqBO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionTransferReqBO.java deleted file mode 100644 index fb7813a0f0..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionTransferReqBO.java +++ /dev/null @@ -1,53 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.permission.bo; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; -import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import javax.validation.constraints.NotNull; - -/** - * 数据权限转移 Request BO - * - * @author HUIHUI - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -public class CrmPermissionTransferReqBO { - - /** - * 当前登录用户编号 - */ - @NotNull(message = "用户编号不能为空") - private Long userId; - - /** - * CRM 类型 - */ - @NotNull(message = "Crm 类型不能为空") - @InEnum(CrmBizTypeEnum.class) - private Integer bizType; - /** - * 数据编号 - */ - @NotNull(message = "CRM 数据编号不能为空") - private Long bizId; - - /** - * 新负责人的用户编号 - */ - @NotNull(message = "新负责人的用户编号不能为空") - private Long newOwnerUserId; - - /** - * 老负责人加入团队后的权限级别。如果 null 说明移除 - * - * 关联 {@link CrmPermissionLevelEnum} - */ - private Integer oldOwnerPermissionLevel; - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryService.java deleted file mode 100644 index c82f97c4a7..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryService.java +++ /dev/null @@ -1,77 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.product; - -import cn.iocoder.yudao.module.crm.controller.admin.product.vo.category.CrmProductCategoryCreateReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.product.vo.category.CrmProductCategoryListReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; - -import javax.validation.Valid; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; - -/** - * CRM 产品分类 Service 接口 - * - * @author ZanGe丶 - */ -public interface CrmProductCategoryService { - - /** - * 创建产品分类 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createProductCategory(@Valid CrmProductCategoryCreateReqVO createReqVO); - - /** - * 更新产品分类 - * - * @param updateReqVO 更新信息 - */ - void updateProductCategory(@Valid CrmProductCategoryCreateReqVO updateReqVO); - - /** - * 删除产品分类 - * - * @param id 编号 - */ - void deleteProductCategory(Long id); - - /** - * 获得产品分类 - * - * @param id 编号 - * @return 产品分类 - */ - CrmProductCategoryDO getProductCategory(Long id); - - /** - * 获得产品分类列表 - * - * @param listReqVO 列表请求 - * @return 产品分类列表 - */ - List getProductCategoryList(CrmProductCategoryListReqVO listReqVO); - - /** - * 获得产品分类列表 - * - * @param ids 编号数组 - * @return 产品分类列表 - */ - List getProductCategoryList(Collection ids); - - /** - * 获得产品分类 Map - * - * @param ids 编号数组 - * @return 产品分类 Map - */ - default Map getProductCategoryMap(Collection ids) { - return convertMap(getProductCategoryList(ids), CrmProductCategoryDO::getId); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductService.java deleted file mode 100644 index d2f6aa580a..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductService.java +++ /dev/null @@ -1,102 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.product; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; - -import javax.validation.Valid; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; - -/** - * CRM 产品 Service 接口 - * - * @author ZanGe丶 - */ -public interface CrmProductService { - - /** - * 创建产品 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createProduct(@Valid CrmProductSaveReqVO createReqVO); - - /** - * 更新产品 - * - * @param updateReqVO 更新信息 - */ - void updateProduct(@Valid CrmProductSaveReqVO updateReqVO); - - /** - * 删除产品 - * - * @param id 编号 - */ - void deleteProduct(Long id); - - /** - * 获得产品 - * - * @param id 编号 - * @return 产品 - */ - CrmProductDO getProduct(Long id); - - /** - * 获得产品列表 - * - * @param ids 编号 - * @return 产品列表 - */ - List getProductList(Collection ids); - - /** - * 获得产品 Map - * - * @param ids 编号 - * @return 产品 Map - */ - default Map getProductMap(Collection ids) { - return convertMap(getProductList(ids), CrmProductDO::getId); - } - - /** - * 获得产品分页 - * - * @param pageReqVO 分页查询 - * @return 产品分页 - */ - PageResult getProductPage(CrmProductPageReqVO pageReqVO); - - /** - * 获得产品数量 - * - * @param categoryId 分类编号 - * @return 产品 - */ - Long getProductByCategoryId(Long categoryId); - - /** - * 获得指定状态的产品列表 - * - * @param status 状态 - * @return 产品列表 - */ - List getProductListByStatus(Integer status); - - /** - * 校验产品们的有效性 - * - * @param ids 编号数组 - * @return 产品列表 - */ - List validProductList(Collection ids); - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java deleted file mode 100644 index 5291b3e1d3..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java +++ /dev/null @@ -1,183 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.product; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; -import cn.iocoder.yudao.module.crm.dal.mysql.product.CrmProductMapper; -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.permission.CrmPermissionService; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import com.mzt.logapi.context.LogRecordContext; -import com.mzt.logapi.service.impl.DiffParseFunction; -import com.mzt.logapi.starter.annotation.LogRecord; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; - - -/** - * CRM 产品 Service 实现类 - * - * @author ZanGe丶 - */ -@Service -@Validated -public class CrmProductServiceImpl implements CrmProductService { - - @Resource(name = "crmProductMapper") - private CrmProductMapper productMapper; - - @Resource - private CrmProductCategoryService productCategoryService; - @Resource - private CrmPermissionService permissionService; - - @Resource - private AdminUserApi adminUserApi; - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_PRODUCT_TYPE, subType = CRM_PRODUCT_CREATE_SUB_TYPE, bizNo = "{{#productId}}", - success = CRM_PRODUCT_CREATE_SUCCESS) - public Long createProduct(CrmProductSaveReqVO createReqVO) { - // 1. 校验产品 - adminUserApi.validateUserList(Collections.singleton(createReqVO.getOwnerUserId())); - validateProductNoDuplicate(null, createReqVO.getNo()); - validateProductCategoryExists(createReqVO.getCategoryId()); - - // 2. 插入产品 - CrmProductDO product = BeanUtils.toBean(createReqVO, CrmProductDO.class); - productMapper.insert(product); - - // 3. 插入数据权限 - permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(product.getOwnerUserId()) - .setBizType(CrmBizTypeEnum.CRM_PRODUCT.getType()).setBizId(product.getId()) - .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); - - // 4. 记录操作日志上下文 - LogRecordContext.putVariable("productId", product.getId()); - return product.getId(); - } - - @Override - @LogRecord(type = CRM_PRODUCT_TYPE, subType = CRM_PRODUCT_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", - success = CRM_PRODUCT_UPDATE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_PRODUCT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) - public void updateProduct(CrmProductSaveReqVO updateReqVO) { - // 1. 校验产品 - updateReqVO.setOwnerUserId(null); // 不修改负责人 - CrmProductDO crmProductDO = validateProductExists(updateReqVO.getId()); - validateProductNoDuplicate(updateReqVO.getId(), updateReqVO.getNo()); - validateProductCategoryExists(updateReqVO.getCategoryId()); - - // 2. 更新产品 - CrmProductDO updateObj = BeanUtils.toBean(updateReqVO, CrmProductDO.class); - productMapper.updateById(updateObj); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(crmProductDO, CrmProductSaveReqVO.class)); - } - - private CrmProductDO validateProductExists(Long id) { - CrmProductDO product = productMapper.selectById(id); - if (product == null) { - throw exception(PRODUCT_NOT_EXISTS); - } - return product; - } - - private void validateProductNoDuplicate(Long id, String no) { - CrmProductDO product = productMapper.selectByNo(no); - if (product == null - || product.getId().equals(id)) { - return; - } - throw exception(PRODUCT_NO_EXISTS); - } - - private void validateProductCategoryExists(Long categoryId) { - CrmProductCategoryDO category = productCategoryService.getProductCategory(categoryId); - if (category == null) { - throw exception(PRODUCT_CATEGORY_NOT_EXISTS); - } - } - - @Override - @LogRecord(type = CRM_PRODUCT_TYPE, subType = CRM_PRODUCT_DELETE_SUB_TYPE, bizNo = "{{#id}}", - success = CRM_PRODUCT_DELETE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_PRODUCT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) - public void deleteProduct(Long id) { - // 校验存在 - validateProductExists(id); - // 删除 - productMapper.deleteById(id); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_PRODUCT, bizId = "#id", level = CrmPermissionLevelEnum.READ) - public CrmProductDO getProduct(Long id) { - return productMapper.selectById(id); - } - - @Override - public PageResult getProductPage(CrmProductPageReqVO pageReqVO) { - return productMapper.selectPage(pageReqVO); - } - - @Override - public Long getProductByCategoryId(Long categoryId) { - return productMapper.selectCountByCategoryId(categoryId); - } - - @Override - public List getProductListByStatus(Integer status) { - return productMapper.selectListByStatus(status); - } - - @Override - public List validProductList(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return Collections.emptyList(); - } - List list = productMapper.selectBatchIds(ids); - Map productMap = convertMap(list, CrmProductDO::getId); - for (Long id : ids) { - CrmProductDO product = productMap.get(id); - if (productMap.get(id) == null) { - throw exception(PRODUCT_NOT_EXISTS); - } - if (CommonStatusEnum.isDisable(product.getStatus())) { - throw exception(PRODUCT_NOT_ENABLE, product.getName()); - } - } - return list; - } - - @Override - public List getProductList(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return Collections.emptyList(); - } - return productMapper.selectBatchIds(ids); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanService.java deleted file mode 100644 index e81f1e5e98..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanService.java +++ /dev/null @@ -1,95 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.receivable; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; - -import javax.validation.Valid; -import java.util.Collection; -import java.util.List; - -/** - * CRM 回款计划 Service 接口 - * - * @author 芋道源码 - */ -public interface CrmReceivablePlanService { - - /** - * 创建回款计划 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createReceivablePlan(@Valid CrmReceivablePlanSaveReqVO createReqVO); - - /** - * 更新回款计划 - * - * @param updateReqVO 更新信息 - */ - void updateReceivablePlan(@Valid CrmReceivablePlanSaveReqVO updateReqVO); - - /** - * 更新回款计划关联的回款编号 - * - * @param id 编号 - * @param receivableId 回款编号 - */ - void updateReceivablePlanReceivableId(Long id, Long receivableId); - - /** - * 删除回款计划 - * - * @param id 编号 - */ - void deleteReceivablePlan(Long id); - - /** - * 获得回款计划 - * - * @param id 编号 - * @return 回款计划 - */ - CrmReceivablePlanDO getReceivablePlan(Long id); - - /** - * 获得回款计划列表 - * - * @param ids 编号 - * @return 回款计划列表 - */ - List getReceivablePlanList(Collection ids); - - /** - * 获得回款计划分页 - * - * 数据权限:基于 {@link CrmReceivablePlanDO} 读取 - * - * @param pageReqVO 分页查询 - * @param userId 用户编号 - * @return 回款计划分页 - */ - PageResult getReceivablePlanPage(CrmReceivablePlanPageReqVO pageReqVO, Long userId); - - /** - * 获得回款计划分页,基于指定客户 - * - * 数据权限:基于 {@link CrmCustomerDO} 读取 - * - * @param pageReqVO 分页查询 - * @return 回款计划分页 - */ - PageResult getReceivablePlanPageByCustomerId(CrmReceivablePlanPageReqVO pageReqVO); - - /** - * 获得待回款提醒数量 - * - * @param userId 用户编号 - * @return 提醒数量 - */ - Long getReceivablePlanRemindCount(Long userId); - -} 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 deleted file mode 100644 index 985003433e..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java +++ /dev/null @@ -1,191 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.receivable; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanPageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; -import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivablePlanMapper; -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.contract.CrmContractService; -import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import com.mzt.logapi.context.LogRecordContext; -import com.mzt.logapi.service.impl.DiffParseFunction; -import com.mzt.logapi.starter.annotation.LogRecord; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.util.Collection; -import java.util.List; -import java.util.Objects; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.RECEIVABLE_PLAN_NOT_EXISTS; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.RECEIVABLE_PLAN_UPDATE_FAIL; -import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; - -/** - * 回款计划 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { - - @Resource - private CrmReceivablePlanMapper receivablePlanMapper; - - @Resource - @Lazy // 延迟加载,避免循环依赖 - private CrmReceivableService receivableService; - @Resource - private CrmContractService contractService; - @Resource - private CrmPermissionService permissionService; - - @Resource - private AdminUserApi adminUserApi; - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_RECEIVABLE_PLAN_TYPE, subType = CRM_RECEIVABLE_PLAN_CREATE_SUB_TYPE, bizNo = "{{#receivablePlan.id}}", - success = CRM_RECEIVABLE_PLAN_CREATE_SUCCESS) - public Long createReceivablePlan(CrmReceivablePlanSaveReqVO createReqVO) { - // 1. 校验关联数据是否存在 - validateRelationDataExists(createReqVO); - - // 2. 插入回款计划 - CrmReceivablePlanDO maxPeriodReceivablePlan = receivablePlanMapper.selectMaxPeriodByContractId(createReqVO.getContractId()); - int period = maxPeriodReceivablePlan == null ? 1 : maxPeriodReceivablePlan.getPeriod() + 1; - CrmReceivablePlanDO receivablePlan = BeanUtils.toBean(createReqVO, CrmReceivablePlanDO.class).setPeriod(period); - if (createReqVO.getReturnTime() != null && createReqVO.getRemindDays() != null) { - receivablePlan.setRemindTime(createReqVO.getReturnTime().minusDays(createReqVO.getRemindDays())); - } - receivablePlanMapper.insert(receivablePlan); - - // 3. 创建数据权限 - permissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(createReqVO.getOwnerUserId()) - .setBizType(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType()).setBizId(receivablePlan.getId()) - .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); - - // 4. 记录操作日志上下文 - LogRecordContext.putVariable("receivablePlan", receivablePlan); - return receivablePlan.getId(); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_RECEIVABLE_PLAN_TYPE, subType = CRM_RECEIVABLE_PLAN_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", - success = CRM_RECEIVABLE_PLAN_UPDATE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE_PLAN, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) - public void updateReceivablePlan(CrmReceivablePlanSaveReqVO updateReqVO) { - updateReqVO.setOwnerUserId(null).setCustomerId(null).setContractId(null); // 防止修改这些字段 - // 1.1 校验存在 - validateRelationDataExists(updateReqVO); - // 1.2 校验关联数据是否存在 - CrmReceivablePlanDO oldReceivablePlan = validateReceivablePlanExists(updateReqVO.getId()); - // 1.3 如果已经有对应的回款,则不允许编辑 - if (Objects.nonNull(oldReceivablePlan.getReceivableId())) { - throw exception(RECEIVABLE_PLAN_UPDATE_FAIL); - } - - // 2. 更新回款计划 - CrmReceivablePlanDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivablePlanDO.class); - if (updateReqVO.getReturnTime() != null && updateReqVO.getRemindDays() != null) { - updateObj.setRemindTime(updateReqVO.getReturnTime().minusDays(updateReqVO.getRemindDays())); - } - receivablePlanMapper.updateById(updateObj); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldReceivablePlan, CrmReceivablePlanSaveReqVO.class)); - LogRecordContext.putVariable("receivablePlan", oldReceivablePlan); - } - - private void validateRelationDataExists(CrmReceivablePlanSaveReqVO reqVO) { - // 校验负责人存在 - if (reqVO.getOwnerUserId() != null) { - adminUserApi.validateUser(reqVO.getOwnerUserId()); - } - // 校验合同存在 - if (reqVO.getContractId() != null) { - CrmContractDO contract = contractService.getContract(reqVO.getContractId()); - reqVO.setCustomerId(contract.getCustomerId()); - } - } - - @Override - public void updateReceivablePlanReceivableId(Long id, Long receivableId) { - // 校验存在 - validateReceivablePlanExists(id); - // 更新回款计划 - receivablePlanMapper.updateById(new CrmReceivablePlanDO().setId(id).setReceivableId(receivableId)); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_RECEIVABLE_PLAN_TYPE, subType = CRM_RECEIVABLE_PLAN_DELETE_SUB_TYPE, bizNo = "{{#id}}", - success = CRM_RECEIVABLE_PLAN_DELETE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE_PLAN, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) - public void deleteReceivablePlan(Long id) { - // 1. 校验存在 - CrmReceivablePlanDO receivablePlan = validateReceivablePlanExists(id); - - // 2. 删除 - receivablePlanMapper.deleteById(id); - // 3. 删除数据权限 - permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id); - - // 4. 记录操作日志上下文 - LogRecordContext.putVariable("receivablePlan", receivablePlan); - } - - private CrmReceivablePlanDO validateReceivablePlanExists(Long id) { - CrmReceivablePlanDO receivablePlan = receivablePlanMapper.selectById(id); - if (receivablePlan == null) { - throw exception(RECEIVABLE_PLAN_NOT_EXISTS); - } - return receivablePlan; - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE_PLAN, bizId = "#id", level = CrmPermissionLevelEnum.READ) - public CrmReceivablePlanDO getReceivablePlan(Long id) { - return receivablePlanMapper.selectById(id); - } - - @Override - public List getReceivablePlanList(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return ListUtil.empty(); - } - return receivablePlanMapper.selectBatchIds(ids); - } - - @Override - public PageResult getReceivablePlanPage(CrmReceivablePlanPageReqVO pageReqVO, Long userId) { - return receivablePlanMapper.selectPage(pageReqVO, userId); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#pageReqVO.customerId", level = CrmPermissionLevelEnum.READ) - public PageResult getReceivablePlanPageByCustomerId(CrmReceivablePlanPageReqVO pageReqVO) { - return receivablePlanMapper.selectPageByCustomerId(pageReqVO); - } - - @Override - public Long getReceivablePlanRemindCount(Long userId) { - return receivablePlanMapper.selectReceivablePlanCountByRemind(userId); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java deleted file mode 100644 index ec5f7008e3..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java +++ /dev/null @@ -1,125 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.receivable; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; - -import javax.validation.Valid; -import java.math.BigDecimal; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; - -/** - * CRM 回款 Service 接口 - * - * @author 赤焰 - */ -public interface CrmReceivableService { - - /** - * 创建回款 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createReceivable(@Valid CrmReceivableSaveReqVO createReqVO); - - /** - * 更新回款 - * - * @param updateReqVO 更新信息 - */ - void updateReceivable(@Valid CrmReceivableSaveReqVO updateReqVO); - - /** - * 更新回款流程审批结果 - * - * @param id 回款编号 - * @param bpmResult BPM 审批结果 - */ - void updateReceivableAuditStatus(Long id, Integer bpmResult); - - /** - * 删除回款 - * - * @param id 编号 - */ - void deleteReceivable(Long id); - - /** - * 发起回款审批流程 - * - * @param id 回款编号 - * @param userId 用户编号 - */ - void submitReceivable(Long id, Long userId); - - /** - * 获得回款 - * - * @param id 编号 - * @return 回款 - */ - CrmReceivableDO getReceivable(Long id); - - /** - * 获得回款列表 - * - * @param ids 编号 - * @return 回款列表 - */ - List getReceivableList(Collection ids); - - /** - * 获得回款 Map - * - * @param ids 编号 - * @return 回款 Map - */ - default Map getReceivableMap(Collection ids) { - return convertMap(getReceivableList(ids), CrmReceivableDO::getId); - } - - /** - * 获得回款分页 - * - * 数据权限:基于 {@link CrmReceivableDO} 读取 - * - * @param pageReqVO 分页查询 - * @param userId 用户编号 - * @return 回款分页 - */ - PageResult getReceivablePage(CrmReceivablePageReqVO pageReqVO, Long userId); - - /** - * 获得回款分页,基于指定客户 - * - * 数据权限:基于 {@link CrmCustomerDO} 读取 - * - * @param pageReqVO 分页查询 - * @return 回款分页 - */ - PageResult getReceivablePageByCustomerId(CrmReceivablePageReqVO pageReqVO); - - /** - * 获得待审核回款数量 - * - * @param userId 用户编号 - * @return 待审批数量 - */ - Long getAuditReceivableCount(Long userId); - - /** - * 获得合同已回款金额 Map - * - * @param contractIds 合同编号 - * @return 回款金额 Map - */ - Map getReceivablePriceMapByContractId(Collection contractIds); - -} 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 deleted file mode 100644 index 3674bed1e5..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java +++ /dev/null @@ -1,292 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.receivable; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; -import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.ObjUtil; -import cn.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.object.BeanUtils; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; -import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivablePageReqVO; -import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableSaveReqVO; -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO; -import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO; -import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivableMapper; -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; -import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; -import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; -import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; -import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import com.mzt.logapi.context.LogRecordContext; -import com.mzt.logapi.service.impl.DiffParseFunction; -import com.mzt.logapi.starter.annotation.LogRecord; -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; - -import javax.annotation.Resource; -import java.math.BigDecimal; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*; -import static cn.iocoder.yudao.module.crm.util.CrmAuditStatusUtils.convertBpmResultToAuditStatus; - -/** - * CRM 回款 Service 实现类 - * - * @author 赤焰 - */ -@Service -@Validated -@Slf4j -public class CrmReceivableServiceImpl implements CrmReceivableService { - - /** - * BPM 合同审批流程标识 - */ - public static final String BPM_PROCESS_DEFINITION_KEY = "crm-receivable-audit"; - - @Resource - private CrmReceivableMapper receivableMapper; - - @Resource - private CrmNoRedisDAO noRedisDAO; - - @Resource - private CrmContractService contractService; - @Resource - @Lazy // 延迟加载,避免循环依赖 - private CrmReceivablePlanService receivablePlanService; - @Resource - private CrmPermissionService permissionService; - - @Resource - private AdminUserApi adminUserApi; - @Resource - private BpmProcessInstanceApi bpmProcessInstanceApi; - - // TODO @puhui999:操作日志没记录上 - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_CREATE_SUB_TYPE, bizNo = "{{#receivable.id}}", - success = CRM_RECEIVABLE_CREATE_SUCCESS) - public Long createReceivable(CrmReceivableSaveReqVO createReqVO) { - // 1.1 校验可回款金额超过上限 - validateReceivablePriceExceedsLimit(createReqVO); - // 1.2 校验关联数据存在 - validateRelationDataExists(createReqVO); - // 1.3 生成回款编号 - String no = noRedisDAO.generate(CrmNoRedisDAO.RECEIVABLE_PREFIX); - if (receivableMapper.selectByNo(no) != null) { - throw exception(RECEIVABLE_NO_EXISTS); - } - - // 2.1 插入回款 - CrmReceivableDO receivable = BeanUtils.toBean(createReqVO, CrmReceivableDO.class) - .setNo(no).setAuditStatus(CrmAuditStatusEnum.DRAFT.getStatus()); - receivableMapper.insert(receivable); - // 2.2 - - // 3. 创建数据权限 - permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_RECEIVABLE.getType()) - .setBizId(receivable.getId()).setUserId(createReqVO.getOwnerUserId()) - .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 - - // 4. 更新关联的回款计划 - if (createReqVO.getPlanId() != null) { - receivablePlanService.updateReceivablePlanReceivableId(receivable.getPlanId(), receivable.getId()); - } - - // 5. 记录操作日志上下文 - LogRecordContext.putVariable("receivable", receivable); - return receivable.getId(); - } - - private void validateReceivablePriceExceedsLimit(CrmReceivableSaveReqVO reqVO) { - // 1. 计算剩余可退款金额,不包括 reqVO 自身 - CrmContractDO contract = contractService.validateContract(reqVO.getContractId()); - List receivables = receivableMapper.selectListByContractIdAndStatus(reqVO.getContractId(), - Arrays.asList(CrmAuditStatusEnum.APPROVE.getStatus(), CrmAuditStatusEnum.PROCESS.getStatus())); - if (reqVO.getId() != null) { - receivables.removeIf(receivable -> ObjectUtil.equal(receivable.getId(), reqVO.getId())); - } - BigDecimal notReceivablePrice = contract.getTotalPrice().subtract( - CollectionUtils.getSumValue(receivables, CrmReceivableDO::getPrice, BigDecimal::add, BigDecimal.ZERO)); - // 2. 校验金额是否超过 - if (reqVO.getPrice().compareTo(notReceivablePrice) > 0) { - throw exception(RECEIVABLE_CREATE_FAIL_PRICE_EXCEEDS_LIMIT, notReceivablePrice); - } - } - - private void validateRelationDataExists(CrmReceivableSaveReqVO reqVO) { - if (reqVO.getOwnerUserId() != null) { - adminUserApi.validateUser(reqVO.getOwnerUserId()); // 校验负责人存在 - } - if (reqVO.getContractId() != null) { - CrmContractDO contract = contractService.validateContract(reqVO.getContractId()); - if (ObjectUtil.notEqual(contract.getAuditStatus(), CrmAuditStatusEnum.APPROVE.getStatus())) { - throw exception(RECEIVABLE_CREATE_FAIL_CONTRACT_NOT_APPROVE); - } - reqVO.setCustomerId(contract.getCustomerId()); // 设置客户编号 - } - if (reqVO.getPlanId() != null) { - CrmReceivablePlanDO receivablePlan = receivablePlanService.getReceivablePlan(reqVO.getPlanId()); - if (receivablePlan == null) { - throw exception(RECEIVABLE_PLAN_NOT_EXISTS); - } - if (receivablePlan.getReceivableId() != null) { - throw exception(RECEIVABLE_PLAN_EXISTS_RECEIVABLE); - } - } - } - - // TODO @puhui999:操作日志没记录上 - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", - success = CRM_RECEIVABLE_UPDATE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) - public void updateReceivable(CrmReceivableSaveReqVO updateReqVO) { - Assert.notNull(updateReqVO.getId(), "回款编号不能为空"); - updateReqVO.setOwnerUserId(null).setCustomerId(null).setContractId(null).setPlanId(null); // 不允许修改的字段 - // 1.1 校验可回款金额超过上限 - validateReceivablePriceExceedsLimit(updateReqVO); - // 1.2 校验存在 - CrmReceivableDO receivable = validateReceivableExists(updateReqVO.getId()); - // 1.3 只有草稿、审批中,可以编辑; - if (!ObjectUtils.equalsAny(receivable.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(), - CrmAuditStatusEnum.PROCESS.getStatus())) { - throw exception(RECEIVABLE_UPDATE_FAIL_EDITING_PROHIBITED); - } - - // 2. 更新回款 - CrmReceivableDO updateObj = BeanUtils.toBean(updateReqVO, CrmReceivableDO.class); - receivableMapper.updateById(updateObj); - - // 3. 记录操作日志上下文 - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(receivable, CrmReceivableSaveReqVO.class)); - LogRecordContext.putVariable("receivable", receivable); - } - - @Override - public void updateReceivableAuditStatus(Long id, Integer bpmResult) { - // 1.1 校验存在 - CrmReceivableDO receivable = validateReceivableExists(id); - // 1.2 只有审批中,可以更新审批结果 - if (ObjUtil.notEqual(receivable.getAuditStatus(), CrmAuditStatusEnum.PROCESS.getStatus())) { - log.error("[updateReceivableAuditStatus][receivable({}) 不处于审批中,无法更新审批结果({})]", - receivable.getId(), bpmResult); - throw exception(RECEIVABLE_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS); - } - - // 2. 更新回款审批状态 - Integer auditStatus = convertBpmResultToAuditStatus(bpmResult); - receivableMapper.updateById(new CrmReceivableDO().setId(id).setAuditStatus(auditStatus)); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_DELETE_SUB_TYPE, bizNo = "{{#id}}", - success = CRM_RECEIVABLE_DELETE_SUCCESS) - @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) - public void deleteReceivable(Long id) { - // 1.1 校验存在 - CrmReceivableDO receivable = validateReceivableExists(id); - // 1.2 如果被 CrmReceivablePlanDO 所使用,则不允许删除 - if (receivable.getPlanId() != null && receivablePlanService.getReceivablePlan(receivable.getPlanId()) != null) { - throw exception(RECEIVABLE_DELETE_FAIL); - } - // TODO @puhui999:审批通过时,不允许删除; - - // 2. 删除 - receivableMapper.deleteById(id); - // 3. 删除数据权限 - permissionService.deletePermission(CrmBizTypeEnum.CRM_RECEIVABLE.getType(), id); - - // 4. 记录操作日志上下文 - LogRecordContext.putVariable("receivable", receivable); - } - - @Override - @Transactional(rollbackFor = Exception.class) - @LogRecord(type = CRM_RECEIVABLE_TYPE, subType = CRM_RECEIVABLE_SUBMIT_SUB_TYPE, bizNo = "{{#id}}", - success = CRM_RECEIVABLE_SUBMIT_SUCCESS) - public void submitReceivable(Long id, Long userId) { - // 1. 校验回款是否在审批 - CrmReceivableDO receivable = validateReceivableExists(id); - if (ObjUtil.notEqual(receivable.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus())) { - throw exception(RECEIVABLE_SUBMIT_FAIL_NOT_DRAFT); - } - - // 2. 创建回款审批流程实例 - String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO() - .setProcessDefinitionKey(BPM_PROCESS_DEFINITION_KEY).setBusinessKey(String.valueOf(id))); - - // 3. 更新回款工作流编号 - receivableMapper.updateById(new CrmReceivableDO().setId(id).setProcessInstanceId(processInstanceId) - .setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus())); - - // 4. 记录日志 - LogRecordContext.putVariable("receivableNo", receivable.getNo()); - } - - private CrmReceivableDO validateReceivableExists(Long id) { - CrmReceivableDO receivable = receivableMapper.selectById(id); - if (receivable == null) { - throw exception(RECEIVABLE_NOT_EXISTS); - } - return receivable; - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE, bizId = "#id", level = CrmPermissionLevelEnum.READ) - public CrmReceivableDO getReceivable(Long id) { - return receivableMapper.selectById(id); - } - - @Override - public List getReceivableList(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return ListUtil.empty(); - } - return receivableMapper.selectBatchIds(ids); - } - - @Override - public PageResult getReceivablePage(CrmReceivablePageReqVO pageReqVO, Long userId) { - return receivableMapper.selectPage(pageReqVO, userId); - } - - @Override - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#pageReqVO.customerId", level = CrmPermissionLevelEnum.READ) - public PageResult getReceivablePageByCustomerId(CrmReceivablePageReqVO pageReqVO) { - return receivableMapper.selectPageByCustomerId(pageReqVO); - } - - @Override - public Long getAuditReceivableCount(Long userId) { - return receivableMapper.selectCountByAudit(userId); - } - - @Override - public Map getReceivablePriceMapByContractId(Collection contractIds) { - return receivableMapper.selectReceivablePriceMapByContractId(contractIds); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableResultListener.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableResultListener.java deleted file mode 100644 index 41a82d0080..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/listener/CrmReceivableResultListener.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.receivable.listener; - -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEvent; -import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceResultEventListener; -import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; -import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableServiceImpl; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * 回款审批的结果的监听器实现类 - * - * @author HUIHUI - */ -@Component -public class CrmReceivableResultListener extends BpmProcessInstanceResultEventListener { - - @Resource - private CrmReceivableService receivableService; - - @Override - public String getProcessDefinitionKey() { - return CrmReceivableServiceImpl.BPM_PROCESS_DEFINITION_KEY; - } - - @Override - public void onEvent(BpmProcessInstanceResultEvent event) { - receivableService.updateReceivableAuditStatus(Long.parseLong(event.getBusinessKey()), event.getResult()); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingService.java deleted file mode 100644 index c9455708c1..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingService.java +++ /dev/null @@ -1,80 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.statistics; - - -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRanKRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRankReqVO; - -import java.util.List; - -/** - * CRM 排行榜统计 Service 接口 - * - * @author anhaohao - */ -public interface CrmStatisticsRankingService { - - /** - * 获得合同金额排行榜 - * - * @param rankReqVO 排行参数 - * @return 合同金额排行榜 - */ - List getContractPriceRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 获得回款金额排行榜 - * - * @param rankReqVO 排行参数 - * @return 回款金额排行榜 - */ - List getReceivablePriceRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 获得签约合同数量排行榜 - * - * @param rankReqVO 排行参数 - * @return 签约合同数量排行榜 - */ - List getContractCountRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 获得产品销量排行榜 - * - * @param rankReqVO 排行参数 - * @return 产品销量排行榜 - */ - List getProductSalesRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 获得新增客户数排行榜 - * - * @param rankReqVO 排行参数 - * @return 新增客户数排行榜 - */ - List getCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 获得联系人数量排行榜 - * - * @param rankReqVO 排行参数 - * @return 联系人数量排行榜 - */ - List getContactsCountRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 获得跟进次数排行榜 - * - * @param rankReqVO 排行参数 - * @return 跟进次数排行榜 - */ - List getFollowCountRank(CrmStatisticsRankReqVO rankReqVO); - - /** - * 获得跟进客户数排行榜 - * - * @param rankReqVO 排行参数 - * @return 跟进客户数排行榜 - */ - List getFollowCustomerCountRank(CrmStatisticsRankReqVO rankReqVO); - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingServiceImpl.java deleted file mode 100644 index d54324ab11..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsRankingServiceImpl.java +++ /dev/null @@ -1,134 +0,0 @@ -package cn.iocoder.yudao.module.crm.service.statistics; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRanKRespVO; -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.CrmStatisticsRankReqVO; -import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsRankingMapper; -import cn.iocoder.yudao.module.system.api.dept.DeptApi; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; - -/** - * CRM 排行榜统计 Service 实现类 - * - * @author anhaohao - */ -@Service -@Validated -public class CrmStatisticsRankingServiceImpl implements CrmStatisticsRankingService { - - @Resource - private CrmStatisticsRankingMapper rankMapper; - - @Resource - private AdminUserApi adminUserApi; - @Resource - private DeptApi deptApi; - - @Override - public List getContractPriceRank(CrmStatisticsRankReqVO rankReqVO) { - return getRank(rankReqVO, rankMapper::selectContractPriceRank); - } - - @Override - public List getReceivablePriceRank(CrmStatisticsRankReqVO rankReqVO) { - return getRank(rankReqVO, rankMapper::selectReceivablePriceRank); - } - - @Override - public List getContractCountRank(CrmStatisticsRankReqVO rankReqVO) { - return getRank(rankReqVO, rankMapper::selectContractCountRank); - } - - @Override - public List getProductSalesRank(CrmStatisticsRankReqVO rankReqVO) { - return getRank(rankReqVO, rankMapper::selectProductSalesRank); - } - - @Override - public List getCustomerCountRank(CrmStatisticsRankReqVO rankReqVO) { - return getRank(rankReqVO, rankMapper::selectCustomerCountRank); - } - - @Override - public List getContactsCountRank(CrmStatisticsRankReqVO rankReqVO) { - return getRank(rankReqVO, rankMapper::selectContactsCountRank); - } - - @Override - public List getFollowCountRank(CrmStatisticsRankReqVO rankReqVO) { - return getRank(rankReqVO, rankMapper::selectFollowCountRank); - } - - @Override - public List getFollowCustomerCountRank(CrmStatisticsRankReqVO rankReqVO) { - return getRank(rankReqVO, rankMapper::selectFollowCustomerCountRank); - } - - /** - * 获得排行版数据 - * - * @param rankReqVO 参数 - * @param rankFunction 排行榜方法 - * @return 排行版数据 - */ - private List getRank(CrmStatisticsRankReqVO rankReqVO, Function> rankFunction) { - // 1. 获得用户编号数组 - rankReqVO.setUserIds(getUserIds(rankReqVO.getDeptId())); - if (CollUtil.isEmpty(rankReqVO.getUserIds())) { - return Collections.emptyList(); - } - // 2. 获得排行数据 - List ranks = rankFunction.apply(rankReqVO); - if (CollUtil.isEmpty(ranks)) { - return Collections.emptyList(); - } - ranks.sort(Comparator.comparing(CrmStatisticsRanKRespVO::getCount).reversed()); - // 3. 拼接用户信息 - appendUserInfo(ranks); - return ranks; - } - - /** - * 拼接用户信息(昵称、部门) - * - * @param ranks 排行榜数据 - */ - private void appendUserInfo(List ranks) { - Map userMap = adminUserApi.getUserMap(convertSet(ranks, CrmStatisticsRanKRespVO::getOwnerUserId)); - Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); - ranks.forEach(rank -> MapUtils.findAndThen(userMap, rank.getOwnerUserId(), user -> { - rank.setNickname(user.getNickname()); - MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> rank.setDeptName(dept.getName())); - })); - } - - /** - * 获得部门下的用户编号数组,包括子部门的 - * - * @param deptId 部门编号 - * @return 用户编号数组 - */ - public List getUserIds(Long deptId) { - // 1. 获得部门列表 - List deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId); - deptIds.add(deptId); - // 2. 获得用户编号 - return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); - } - -} \ No newline at end of file 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 deleted file mode 100644 index 665e98fbed..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmAuditStatusUtils.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.iocoder.yudao.module.crm.util; - -import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; -import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; - -/** - * CRM 流程工具类 - * - * @author HUIHUI - */ -public class CrmAuditStatusUtils { - - /** - * BPM 审批结果转换 - * - * @param bpmResult BPM 审批结果 - */ - public static Integer convertBpmResultToAuditStatus(Integer bpmResult) { - Integer auditStatus = BpmProcessInstanceResultEnum.APPROVE.getResult().equals(bpmResult) ? CrmAuditStatusEnum.APPROVE.getStatus() - : BpmProcessInstanceResultEnum.REJECT.getResult().equals(bpmResult) ? CrmAuditStatusEnum.REJECT.getStatus() - : BpmProcessInstanceResultEnum.CANCEL.getResult().equals(bpmResult) ? BpmProcessInstanceResultEnum.CANCEL.getResult() : null; - Assert.notNull(auditStatus, "BPM 审批结果({}) 转换失败", bpmResult); - return auditStatus; - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java deleted file mode 100644 index 587e9ab560..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java +++ /dev/null @@ -1,106 +0,0 @@ -package cn.iocoder.yudao.module.crm.util; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjUtil; -import cn.hutool.extra.spring.SpringUtil; -import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; -import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; -import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; -import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; -import cn.iocoder.yudao.module.system.api.permission.PermissionApi; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; -import com.baomidou.mybatisplus.core.toolkit.support.SFunction; -import com.github.yulichang.autoconfigure.MybatisPlusJoinProperties; -import com.github.yulichang.wrapper.MPJLambdaWrapper; - -import java.util.Collection; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; - -/** - * 数据权限工具类 - * - * @author HUIHUI - */ -public class CrmPermissionUtils { - - /** - * 校验用户是否是 CRM 管理员 - * - * @return 是/否 - */ - public static boolean isCrmAdmin() { - PermissionApi permissionApi = SpringUtil.getBean(PermissionApi.class); - return permissionApi.hasAnyRoles(getLoginUserId(), RoleCodeEnum.CRM_ADMIN.getCode()); - } - - /** - * 构造 CRM 数据类型数据分页查询条件 - * - * @param query 连表查询对象 - * @param bizType 数据类型 {@link CrmBizTypeEnum} - * @param bizId 数据编号 - * @param userId 用户编号 - * @param sceneType 场景类型 - * @param pool 公海 - */ - public static , S> void appendPermissionCondition(T query, Integer bizType, SFunction bizId, - Long userId, Integer sceneType, Boolean pool) { - MybatisPlusJoinProperties mybatisPlusJoinProperties = SpringUtil.getBean(MybatisPlusJoinProperties.class); - final String ownerUserIdField = mybatisPlusJoinProperties.getTableAlias() + ".owner_user_id"; - // 1. 构建数据权限连表条件 - if (!CrmPermissionUtils.isCrmAdmin() && ObjUtil.notEqual(pool, Boolean.TRUE)) { // 管理员,公海不需要数据权限 - query.innerJoin(CrmPermissionDO.class, on -> on.eq(CrmPermissionDO::getBizType, bizType) - .eq(CrmPermissionDO::getBizId, bizId) // 只能使用 SFunction 如果传 id 解析出来的 sql 不对 - .eq(CrmPermissionDO::getUserId, userId)); - } - // 2.1 场景一:我负责的数据 - if (CrmSceneTypeEnum.isOwner(sceneType)) { - query.eq(ownerUserIdField, userId); - } - // 2.2 场景二:我参与的数据 - if (CrmSceneTypeEnum.isInvolved(sceneType)) { - query.ne(ownerUserIdField, userId) - .in(CrmPermissionDO::getLevel, CrmPermissionLevelEnum.READ.getLevel(), CrmPermissionLevelEnum.WRITE.getLevel()); - } - // 2.3 场景三:下属负责的数据 - if (CrmSceneTypeEnum.isSubordinate(sceneType)) { - AdminUserApi adminUserApi = SpringUtil.getBean(AdminUserApi.class); - List subordinateUsers = adminUserApi.getUserListBySubordinate(userId); - if (CollUtil.isEmpty(subordinateUsers)) { - query.eq(ownerUserIdField, -1); // 不返回任何结果 - } else { - query.in(ownerUserIdField, convertSet(subordinateUsers, AdminUserRespDTO::getId)); - } - } - - // 3. 拼接公海的查询条件 - if (ObjUtil.equal(pool, Boolean.TRUE)) { // 情况一:公海 - query.isNull(ownerUserIdField); - } else { // 情况二:不是公海 - query.isNotNull(ownerUserIdField); - } - } - - /** - * 构造 CRM 数据类型批量数据查询条件 - * - * @param query 连表查询对象 - * @param bizType 数据类型 {@link CrmBizTypeEnum} - * @param bizIds 数据编号 - * @param userId 用户编号 - */ - public static > void appendPermissionCondition(T query, Integer bizType, Collection bizIds, Long userId) { - if (isCrmAdmin()) {// 管理员不需要数据权限 - return; - } - query.innerJoin(CrmPermissionDO.class, on -> - on.eq(CrmPermissionDO::getBizType, bizType).in(CrmPermissionDO::getBizId, bizIds) - .eq(CollUtil.isNotEmpty(bizIds), CrmPermissionDO::getUserId, userId)); - } - -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/bi/CrmBiRankingMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/bi/CrmBiRankingMapper.xml deleted file mode 100644 index c193873ce0..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/bi/CrmBiRankingMapper.xml +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/yudao-module-erp/yudao-module-erp-biz/pom.xml b/yudao-module-erp/yudao-module-erp-biz/pom.xml deleted file mode 100644 index 53c9349506..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/pom.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - cn.iocoder.boot - yudao-module-erp - ${revision} - - 4.0.0 - yudao-module-erp-biz - - ${project.artifactId} - - erp 包下,企业资源管理(Enterprise Resource Planning)。 - 例如说:采购、销售、库存、财务、产品等等 - - - - - cn.iocoder.boot - yudao-module-system-api - ${revision} - - - cn.iocoder.boot - yudao-module-erp-api - ${revision} - - - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-operatelog - - - - - cn.iocoder.boot - yudao-spring-boot-starter-web - - - - cn.iocoder.boot - yudao-spring-boot-starter-security - - - - - cn.iocoder.boot - yudao-spring-boot-starter-mybatis - - - - cn.iocoder.boot - yudao-spring-boot-starter-redis - - - - - cn.iocoder.boot - yudao-spring-boot-starter-excel - - - - - cn.iocoder.boot - yudao-spring-boot-starter-test - - - - - \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpPurchaseStatisticsController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpPurchaseStatisticsController.java deleted file mode 100644 index be0258dabe..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpPurchaseStatisticsController.java +++ /dev/null @@ -1,69 +0,0 @@ -package cn.iocoder.yudao.module.erp.controller.admin.statistics; - -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; -import cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.purchase.ErpPurchaseSummaryRespVO; -import cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.purchase.ErpPurchaseTimeSummaryRespVO; -import cn.iocoder.yudao.module.erp.service.statistics.ErpPurchaseStatisticsService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; - -import static cn.hutool.core.date.DatePattern.NORM_MONTH_PATTERN; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - ERP 采购统计") -@RestController -@RequestMapping("/erp/purchase-statistics") -@Validated -public class ErpPurchaseStatisticsController { - - @Resource - private ErpPurchaseStatisticsService purchaseStatisticsService; - - @GetMapping("/summary") - @Operation(summary = "获得采购统计") - @PreAuthorize("@ss.hasPermission('erp:statistics:query')") - public CommonResult getPurchaseSummary() { - LocalDateTime today = LocalDateTimeUtils.getToday(); - LocalDateTime yesterday = LocalDateTimeUtils.getYesterday(); - LocalDateTime month = LocalDateTimeUtils.getMonth(); - LocalDateTime year = LocalDateTimeUtils.getYear(); - ErpPurchaseSummaryRespVO summary = new ErpPurchaseSummaryRespVO() - .setTodayPrice(purchaseStatisticsService.getPurchasePrice(today, null)) - .setYesterdayPrice(purchaseStatisticsService.getPurchasePrice(yesterday, today)) - .setMonthPrice(purchaseStatisticsService.getPurchasePrice(month, null)) - .setYearPrice(purchaseStatisticsService.getPurchasePrice(year, null)); - return success(summary); - } - - @GetMapping("/time-summary") - @Operation(summary = "获得采购时间段统计") - @Parameter(name = "count", description = "时间段数量", example = "6") - @PreAuthorize("@ss.hasPermission('erp:statistics:query')") - public CommonResult> getPurchaseTimeSummary( - @RequestParam(value = "count", defaultValue = "6") Integer count) { - List summaryList = new ArrayList<>(); - for (int i = count - 1; i >= 0; i--) { - LocalDateTime startTime = LocalDateTimeUtils.beginOfMonth(LocalDateTime.now().minusMonths(i)); - LocalDateTime endTime = LocalDateTimeUtils.endOfMonth(startTime); - summaryList.add(new ErpPurchaseTimeSummaryRespVO() - .setTime(LocalDateTimeUtil.format(startTime, NORM_MONTH_PATTERN)) - .setPrice(purchaseStatisticsService.getPurchasePrice(startTime, endTime))); - } - return success(summaryList); - } - -} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.http b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.http deleted file mode 100644 index 5f5cab1094..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.http +++ /dev/null @@ -1,11 +0,0 @@ -### 请求 /erp/sale-statistics/summary 接口 => 成功 -GET {{baseUrl}}/erp/sale-statistics/summary -Content-Type: application/json -tenant-id: {{adminTenentId}} -Authorization: Bearer {{token}} - -### 请求 /erp/sale-statistics/time-summary 接口 => 成功 -GET {{baseUrl}}/erp/sale-statistics/time-summary -Content-Type: application/json -tenant-id: {{adminTenentId}} -Authorization: Bearer {{token}} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.java deleted file mode 100644 index c43c971fe8..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/ErpSaleStatisticsController.java +++ /dev/null @@ -1,69 +0,0 @@ -package cn.iocoder.yudao.module.erp.controller.admin.statistics; - -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; -import cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.sale.ErpSaleSummaryRespVO; -import cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.sale.ErpSaleTimeSummaryRespVO; -import cn.iocoder.yudao.module.erp.service.statistics.ErpSaleStatisticsService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; - -import static cn.hutool.core.date.DatePattern.NORM_MONTH_PATTERN; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - ERP 销售统计") -@RestController -@RequestMapping("/erp/sale-statistics") -@Validated -public class ErpSaleStatisticsController { - - @Resource - private ErpSaleStatisticsService saleStatisticsService; - - @GetMapping("/summary") - @Operation(summary = "获得销售统计") - @PreAuthorize("@ss.hasPermission('erp:statistics:query')") - public CommonResult getSaleSummary() { - LocalDateTime today = LocalDateTimeUtils.getToday(); - LocalDateTime yesterday = LocalDateTimeUtils.getYesterday(); - LocalDateTime month = LocalDateTimeUtils.getMonth(); - LocalDateTime year = LocalDateTimeUtils.getYear(); - ErpSaleSummaryRespVO summary = new ErpSaleSummaryRespVO() - .setTodayPrice(saleStatisticsService.getSalePrice(today, null)) - .setYesterdayPrice(saleStatisticsService.getSalePrice(yesterday, today)) - .setMonthPrice(saleStatisticsService.getSalePrice(month, null)) - .setYearPrice(saleStatisticsService.getSalePrice(year, null)); - return success(summary); - } - - @GetMapping("/time-summary") - @Operation(summary = "获得销售时间段统计") - @Parameter(name = "count", description = "时间段数量", example = "6") - @PreAuthorize("@ss.hasPermission('erp:statistics:query')") - public CommonResult> getSaleTimeSummary( - @RequestParam(value = "count", defaultValue = "6") Integer count) { - List summaryList = new ArrayList<>(); - for (int i = count - 1; i >= 0; i--) { - LocalDateTime startTime = LocalDateTimeUtils.beginOfMonth(LocalDateTime.now().minusMonths(i)); - LocalDateTime endTime = LocalDateTimeUtils.endOfMonth(startTime); - summaryList.add(new ErpSaleTimeSummaryRespVO() - .setTime(LocalDateTimeUtil.format(startTime, NORM_MONTH_PATTERN)) - .setPrice(saleStatisticsService.getSalePrice(startTime, endTime))); - } - return success(summaryList); - } - -} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseSummaryRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseSummaryRespVO.java deleted file mode 100644 index 22635e7457..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseSummaryRespVO.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.purchase; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.math.BigDecimal; - -@Schema(description = "管理后台 - ERP 采购全局统计 Response VO") -@Data -public class ErpPurchaseSummaryRespVO { - - @Schema(description = "今日采购金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private BigDecimal todayPrice; - - @Schema(description = "昨日采购金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") - private BigDecimal yesterdayPrice; - - @Schema(description = "本月采购金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private BigDecimal monthPrice; - - @Schema(description = "今年采购金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "88888") - private BigDecimal yearPrice; - -} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseTimeSummaryRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseTimeSummaryRespVO.java deleted file mode 100644 index 15ae817de1..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/purchase/ErpPurchaseTimeSummaryRespVO.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.purchase; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.math.BigDecimal; - -@Schema(description = "管理后台 - ERP 采购某个时间段的统计 Response VO") -@Data -public class ErpPurchaseTimeSummaryRespVO { - - @Schema(description = "时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-03") - private String time; - - @Schema(description = "采购金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private BigDecimal price; - -} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleSummaryRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleSummaryRespVO.java deleted file mode 100644 index 575d7da5e7..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleSummaryRespVO.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.sale; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.math.BigDecimal; - -@Schema(description = "管理后台 - ERP 销售全局统计 Response VO") -@Data -public class ErpSaleSummaryRespVO { - - @Schema(description = "今日销售金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private BigDecimal todayPrice; - - @Schema(description = "昨日销售金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") - private BigDecimal yesterdayPrice; - - @Schema(description = "本月销售金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private BigDecimal monthPrice; - - @Schema(description = "今年销售金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "88888") - private BigDecimal yearPrice; - -} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleTimeSummaryRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleTimeSummaryRespVO.java deleted file mode 100644 index 48b9b6e9ac..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/statistics/vo/sale/ErpSaleTimeSummaryRespVO.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.module.erp.controller.admin.statistics.vo.sale; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.math.BigDecimal; - -@Schema(description = "管理后台 - ERP 销售某个时间段的统计 Response VO") -@Data -public class ErpSaleTimeSummaryRespVO { - - @Schema(description = "时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-03") - private String time; - - @Schema(description = "销售金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private BigDecimal price; - -} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java deleted file mode 100644 index 488959bfa6..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java +++ /dev/null @@ -1,116 +0,0 @@ -package cn.iocoder.yudao.module.erp.controller.admin.stock; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; -import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSaveReqVO; -import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; -import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseRespVO; -import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; -import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; -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 org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletResponse; -import javax.validation.Valid; -import java.io.IOException; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; - -@Tag(name = "管理后台 - ERP 仓库") -@RestController -@RequestMapping("/erp/warehouse") -@Validated -public class ErpWarehouseController { - - @Resource - private ErpWarehouseService warehouseService; - - @PostMapping("/create") - @Operation(summary = "创建仓库") - @PreAuthorize("@ss.hasPermission('erp:warehouse:create')") - public CommonResult createWarehouse(@Valid @RequestBody ErpWarehouseSaveReqVO createReqVO) { - return success(warehouseService.createWarehouse(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新仓库") - @PreAuthorize("@ss.hasPermission('erp:warehouse:update')") - public CommonResult updateWarehouse(@Valid @RequestBody ErpWarehouseSaveReqVO updateReqVO) { - warehouseService.updateWarehouse(updateReqVO); - return success(true); - } - - @PutMapping("/update-default-status") - @Operation(summary = "更新仓库默认状态") - @Parameters({ - @Parameter(name = "id", description = "编号", required = true), - @Parameter(name = "status", description = "状态", required = true) - }) - public CommonResult updateWarehouseDefaultStatus(@RequestParam("id") Long id, - @RequestParam("defaultStatus") Boolean defaultStatus) { - warehouseService.updateWarehouseDefaultStatus(id, defaultStatus); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除仓库") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('erp:warehouse:delete')") - public CommonResult deleteWarehouse(@RequestParam("id") Long id) { - warehouseService.deleteWarehouse(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得仓库") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('erp:warehouse:query')") - public CommonResult getWarehouse(@RequestParam("id") Long id) { - ErpWarehouseDO warehouse = warehouseService.getWarehouse(id); - return success(BeanUtils.toBean(warehouse, ErpWarehouseRespVO.class)); - } - - @GetMapping("/page") - @Operation(summary = "获得仓库分页") - @PreAuthorize("@ss.hasPermission('erp:warehouse:query')") - public CommonResult> getWarehousePage(@Valid ErpWarehousePageReqVO pageReqVO) { - PageResult pageResult = warehouseService.getWarehousePage(pageReqVO); - return success(BeanUtils.toBean(pageResult, ErpWarehouseRespVO.class)); - } - - @GetMapping("/simple-list") - @Operation(summary = "获得仓库精简列表", description = "只包含被开启的仓库,主要用于前端的下拉选项") - public CommonResult> getWarehouseSimpleList() { - List list = warehouseService.getWarehouseListByStatus(CommonStatusEnum.ENABLE.getStatus()); - return success(convertList(list, warehouse -> new ErpWarehouseRespVO().setId(warehouse.getId()) - .setName(warehouse.getName()).setDefaultStatus(warehouse.getDefaultStatus()))); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出仓库 Excel") - @PreAuthorize("@ss.hasPermission('erp:warehouse:export')") - @OperateLog(type = EXPORT) - public void exportWarehouseExcel(@Valid ErpWarehousePageReqVO pageReqVO, - HttpServletResponse response) throws IOException { - pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = warehouseService.getWarehousePage(pageReqVO).getList(); - // 导出 Excel - ExcelUtils.write(response, "仓库.xls", "数据", ErpWarehouseRespVO.class, - BeanUtils.toBean(list, ErpWarehouseRespVO.class)); - } - -} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java deleted file mode 100644 index 06bf5580eb..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java +++ /dev/null @@ -1,47 +0,0 @@ -package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.validation.InEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import lombok.Data; - -import java.math.BigDecimal; - -@Schema(description = "管理后台 - ERP 仓库新增/修改 Request VO") -@Data -public class ErpWarehouseSaveReqVO { - - @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11614") - private Long id; - - @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") - @NotEmpty(message = "仓库名称不能为空") - private String name; - - @Schema(description = "仓库地址", example = "上海陆家嘴") - private String address; - - @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") - @NotNull(message = "排序不能为空") - private Long sort; - - @Schema(description = "备注", example = "随便") - private String remark; - - @Schema(description = "负责人", example = "芋头") - private String principal; - - @Schema(description = "仓储费,单位:元", example = "13973") - private BigDecimal warehousePrice; - - @Schema(description = "搬运费,单位:元", example = "9903") - private BigDecimal truckagePrice; - - @Schema(description = "开启状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @NotNull(message = "开启状态不能为空") - @InEnum(CommonStatusEnum.class) - private Integer status; - -} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpPurchaseStatisticsMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpPurchaseStatisticsMapper.java deleted file mode 100644 index 14b4e517bf..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpPurchaseStatisticsMapper.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.yudao.module.erp.dal.mysql.statistics; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -/** - * ERP 采购统计 Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface ErpPurchaseStatisticsMapper { - - BigDecimal getPurchasePrice(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - -} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpSaleStatisticsMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpSaleStatisticsMapper.java deleted file mode 100644 index b29f1944d4..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/statistics/ErpSaleStatisticsMapper.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.yudao.module.erp.dal.mysql.statistics; - -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -/** - * ERP 销售统计 Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface ErpSaleStatisticsMapper { - - BigDecimal getSalePrice(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - -} 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 deleted file mode 100644 index 06ec31387b..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/RedisKeyConstants.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.module.erp.dal.redis; - -/** - * ERP Redis Key 枚举类 - * - * @author 芋道源码 - */ -public interface RedisKeyConstants { - - /** - * 序号的缓存 - * - * KEY 格式:seq_no:{prefix} - * VALUE 数据格式:编号自增 - */ - 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 deleted file mode 100644 index f7d976d286..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java +++ /dev/null @@ -1,96 +0,0 @@ -package cn.iocoder.yudao.module.erp.dal.redis.no; - -import cn.hutool.core.date.DatePattern; -import cn.hutool.core.date.DateUtil; -import cn.iocoder.yudao.module.erp.dal.redis.RedisKeyConstants; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.stereotype.Repository; - -import javax.annotation.Resource; -import java.time.Duration; -import java.time.LocalDateTime; - - -/** - * Erp 订单序号的 Redis DAO - * - * @author HUIHUI - */ -@Repository -public class ErpNoRedisDAO { - - /** - * 其它入库 {@link cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO} - */ - public static final String STOCK_IN_NO_PREFIX = "QTRK"; - /** - * 其它出库 {@link cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO} - */ - public static final String STOCK_OUT_NO_PREFIX = "QCKD"; - - /** - * 库存调拨 {@link cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO} - */ - public static final String STOCK_MOVE_NO_PREFIX = "QCDB"; - - /** - * 库存盘点 {@link cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO} - */ - public static final String STOCK_CHECK_NO_PREFIX = "QCPD"; - - /** - * 销售订单 {@link cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO} - */ - public static final String SALE_ORDER_NO_PREFIX = "XSDD"; - /** - * 销售出库 {@link cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO} - */ - public static final String SALE_OUT_NO_PREFIX = "XSCK"; - /** - * 销售退货 {@link cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnDO} - */ - public static final String SALE_RETURN_NO_PREFIX = "XSTH"; - - /** - * 采购订单 {@link cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO} - */ - public static final String PURCHASE_ORDER_NO_PREFIX = "CGDD"; - /** - * 采购入库 {@link cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInDO} - */ - public static final String PURCHASE_IN_NO_PREFIX = "CGRK"; - /** - * 采购退货 {@link cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnDO} - */ - public static final String PURCHASE_RETURN_NO_PREFIX = "CGTH"; - - /** - * 付款单 {@link cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentDO} - */ - public static final String FINANCE_PAYMENT_NO_PREFIX = "FKD"; - /** - * 收款单 {@link cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinanceReceiptDO} - */ - public static final String FINANCE_RECEIPT_NO_PREFIX = "SKD"; - - @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-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java deleted file mode 100644 index 58f4952081..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java +++ /dev/null @@ -1,308 +0,0 @@ -package cn.iocoder.yudao.module.erp.service.purchase; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in.ErpPurchaseInPageReqVO; -import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in.ErpPurchaseInSaveReqVO; -import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInItemDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; -import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseInItemMapper; -import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseInMapper; -import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; -import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; -import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; -import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; -import cn.iocoder.yudao.module.erp.service.product.ErpProductService; -import cn.iocoder.yudao.module.erp.service.stock.ErpStockRecordService; -import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.math.BigDecimal; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; - -// TODO 芋艿:记录操作日志 - -/** - * ERP 采购入库 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class ErpPurchaseInServiceImpl implements ErpPurchaseInService { - - @Resource - private ErpPurchaseInMapper purchaseInMapper; - @Resource - private ErpPurchaseInItemMapper purchaseInItemMapper; - - @Resource - private ErpNoRedisDAO noRedisDAO; - - @Resource - private ErpProductService productService; - @Resource - @Lazy // 延迟加载,避免循环依赖 - private ErpPurchaseOrderService purchaseOrderService; - @Resource - private ErpAccountService accountService; - @Resource - private ErpStockRecordService stockRecordService; - - @Resource - private AdminUserApi adminUserApi; - - @Override - @Transactional(rollbackFor = Exception.class) - public Long createPurchaseIn(ErpPurchaseInSaveReqVO createReqVO) { - // 1.1 校验采购订单已审核 - ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.validatePurchaseOrder(createReqVO.getOrderId()); - // 1.2 校验入库项的有效性 - List purchaseInItems = validatePurchaseInItems(createReqVO.getItems()); - // 1.3 校验结算账户 - accountService.validateAccount(createReqVO.getAccountId()); - // 1.4 生成入库单号,并校验唯一性 - String no = noRedisDAO.generate(ErpNoRedisDAO.PURCHASE_IN_NO_PREFIX); - if (purchaseInMapper.selectByNo(no) != null) { - throw exception(PURCHASE_IN_NO_EXISTS); - } - - // 2.1 插入入库 - ErpPurchaseInDO purchaseIn = BeanUtils.toBean(createReqVO, ErpPurchaseInDO.class, in -> in - .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())) - .setOrderNo(purchaseOrder.getNo()).setSupplierId(purchaseOrder.getSupplierId()); - calculateTotalPrice(purchaseIn, purchaseInItems); - purchaseInMapper.insert(purchaseIn); - // 2.2 插入入库项 - purchaseInItems.forEach(o -> o.setInId(purchaseIn.getId())); - purchaseInItemMapper.insertBatch(purchaseInItems); - - // 3. 更新采购订单的入库数量 - updatePurchaseOrderInCount(createReqVO.getOrderId()); - return purchaseIn.getId(); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updatePurchaseIn(ErpPurchaseInSaveReqVO updateReqVO) { - // 1.1 校验存在 - ErpPurchaseInDO purchaseIn = validatePurchaseInExists(updateReqVO.getId()); - if (ErpAuditStatus.APPROVE.getStatus().equals(purchaseIn.getStatus())) { - throw exception(PURCHASE_IN_UPDATE_FAIL_APPROVE, purchaseIn.getNo()); - } - // 1.2 校验采购订单已审核 - ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.validatePurchaseOrder(updateReqVO.getOrderId()); - // 1.3 校验结算账户 - accountService.validateAccount(updateReqVO.getAccountId()); - // 1.4 校验订单项的有效性 - List purchaseInItems = validatePurchaseInItems(updateReqVO.getItems()); - - // 2.1 更新入库 - ErpPurchaseInDO updateObj = BeanUtils.toBean(updateReqVO, ErpPurchaseInDO.class) - .setOrderNo(purchaseOrder.getNo()).setSupplierId(purchaseOrder.getSupplierId()); - calculateTotalPrice(updateObj, purchaseInItems); - purchaseInMapper.updateById(updateObj); - // 2.2 更新入库项 - updatePurchaseInItemList(updateReqVO.getId(), purchaseInItems); - - // 3.1 更新采购订单的入库数量 - updatePurchaseOrderInCount(updateObj.getOrderId()); - // 3.2 注意:如果采购订单编号变更了,需要更新“老”采购订单的入库数量 - if (ObjectUtil.notEqual(purchaseIn.getOrderId(), updateObj.getOrderId())) { - updatePurchaseOrderInCount(purchaseIn.getOrderId()); - } - } - - private void calculateTotalPrice(ErpPurchaseInDO purchaseIn, List purchaseInItems) { - purchaseIn.setTotalCount(getSumValue(purchaseInItems, ErpPurchaseInItemDO::getCount, BigDecimal::add)); - purchaseIn.setTotalProductPrice(getSumValue(purchaseInItems, ErpPurchaseInItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); - purchaseIn.setTotalTaxPrice(getSumValue(purchaseInItems, ErpPurchaseInItemDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO)); - purchaseIn.setTotalPrice(purchaseIn.getTotalProductPrice().add(purchaseIn.getTotalTaxPrice())); - // 计算优惠价格 - if (purchaseIn.getDiscountPercent() == null) { - purchaseIn.setDiscountPercent(BigDecimal.ZERO); - } - purchaseIn.setDiscountPrice(MoneyUtils.priceMultiplyPercent(purchaseIn.getTotalPrice(), purchaseIn.getDiscountPercent())); - purchaseIn.setTotalPrice(purchaseIn.getTotalPrice().subtract(purchaseIn.getDiscountPrice().add(purchaseIn.getOtherPrice()))); - } - - private void updatePurchaseOrderInCount(Long orderId) { - // 1.1 查询采购订单对应的采购入库单列表 - List purchaseIns = purchaseInMapper.selectListByOrderId(orderId); - // 1.2 查询对应的采购订单项的入库数量 - Map returnCountMap = purchaseInItemMapper.selectOrderItemCountSumMapByInIds( - convertList(purchaseIns, ErpPurchaseInDO::getId)); - // 2. 更新采购订单的入库数量 - purchaseOrderService.updatePurchaseOrderInCount(orderId, returnCountMap); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updatePurchaseInStatus(Long id, Integer status) { - boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); - // 1.1 校验存在 - ErpPurchaseInDO purchaseIn = validatePurchaseInExists(id); - // 1.2 校验状态 - if (purchaseIn.getStatus().equals(status)) { - throw exception(approve ? PURCHASE_IN_APPROVE_FAIL : PURCHASE_IN_PROCESS_FAIL); - } - // 1.3 校验已付款 - if (!approve && purchaseIn.getPaymentPrice().compareTo(BigDecimal.ZERO) > 0) { - throw exception(PURCHASE_IN_PROCESS_FAIL_EXISTS_PAYMENT); - } - - // 2. 更新状态 - int updateCount = purchaseInMapper.updateByIdAndStatus(id, purchaseIn.getStatus(), - new ErpPurchaseInDO().setStatus(status)); - if (updateCount == 0) { - throw exception(approve ? PURCHASE_IN_APPROVE_FAIL : PURCHASE_IN_PROCESS_FAIL); - } - - // 3. 变更库存 - List purchaseInItems = purchaseInItemMapper.selectListByInId(id); - Integer bizType = approve ? ErpStockRecordBizTypeEnum.PURCHASE_IN.getType() - : ErpStockRecordBizTypeEnum.PURCHASE_IN_CANCEL.getType(); - purchaseInItems.forEach(purchaseInItem -> { - BigDecimal count = approve ? purchaseInItem.getCount() : purchaseInItem.getCount().negate(); - stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( - purchaseInItem.getProductId(), purchaseInItem.getWarehouseId(), count, - bizType, purchaseInItem.getInId(), purchaseInItem.getId(), purchaseIn.getNo())); - }); - } - - @Override - public void updatePurchaseInPaymentPrice(Long id, BigDecimal paymentPrice) { - ErpPurchaseInDO purchaseIn = purchaseInMapper.selectById(id); - if (purchaseIn.getPaymentPrice().equals(paymentPrice)) { - return; - } - if (paymentPrice.compareTo(purchaseIn.getTotalPrice()) > 0) { - throw exception(PURCHASE_IN_FAIL_PAYMENT_PRICE_EXCEED, paymentPrice, purchaseIn.getTotalPrice()); - } - purchaseInMapper.updateById(new ErpPurchaseInDO().setId(id).setPaymentPrice(paymentPrice)); - } - - private List validatePurchaseInItems(List list) { - // 1. 校验产品存在 - List productList = productService.validProductList( - convertSet(list, ErpPurchaseInSaveReqVO.Item::getProductId)); - Map productMap = convertMap(productList, ErpProductDO::getId); - // 2. 转化为 ErpPurchaseInItemDO 列表 - return convertList(list, o -> BeanUtils.toBean(o, ErpPurchaseInItemDO.class, item -> { - item.setProductUnitId(productMap.get(item.getProductId()).getUnitId()); - item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())); - if (item.getTotalPrice() == null) { - return; - } - if (item.getTaxPercent() != null) { - item.setTaxPrice(MoneyUtils.priceMultiplyPercent(item.getTotalPrice(), item.getTaxPercent())); - } - })); - } - - private void updatePurchaseInItemList(Long id, List newList) { - // 第一步,对比新老数据,获得添加、修改、删除的列表 - List oldList = purchaseInItemMapper.selectListByInId(id); - List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 - (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); - - // 第二步,批量添加、修改、删除 - if (CollUtil.isNotEmpty(diffList.get(0))) { - diffList.get(0).forEach(o -> o.setInId(id)); - purchaseInItemMapper.insertBatch(diffList.get(0)); - } - if (CollUtil.isNotEmpty(diffList.get(1))) { - purchaseInItemMapper.updateBatch(diffList.get(1)); - } - if (CollUtil.isNotEmpty(diffList.get(2))) { - purchaseInItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpPurchaseInItemDO::getId)); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void deletePurchaseIn(List ids) { - // 1. 校验不处于已审批 - List purchaseIns = purchaseInMapper.selectBatchIds(ids); - if (CollUtil.isEmpty(purchaseIns)) { - return; - } - purchaseIns.forEach(purchaseIn -> { - if (ErpAuditStatus.APPROVE.getStatus().equals(purchaseIn.getStatus())) { - throw exception(PURCHASE_IN_DELETE_FAIL_APPROVE, purchaseIn.getNo()); - } - }); - - // 2. 遍历删除,并记录操作日志 - purchaseIns.forEach(purchaseIn -> { - // 2.1 删除订单 - purchaseInMapper.deleteById(purchaseIn.getId()); - // 2.2 删除订单项 - purchaseInItemMapper.deleteByInId(purchaseIn.getId()); - - // 2.3 更新采购订单的入库数量 - updatePurchaseOrderInCount(purchaseIn.getOrderId()); - }); - - } - - private ErpPurchaseInDO validatePurchaseInExists(Long id) { - ErpPurchaseInDO purchaseIn = purchaseInMapper.selectById(id); - if (purchaseIn == null) { - throw exception(PURCHASE_IN_NOT_EXISTS); - } - return purchaseIn; - } - - @Override - public ErpPurchaseInDO getPurchaseIn(Long id) { - return purchaseInMapper.selectById(id); - } - - @Override - public ErpPurchaseInDO validatePurchaseIn(Long id) { - ErpPurchaseInDO purchaseIn = validatePurchaseInExists(id); - if (ObjectUtil.notEqual(purchaseIn.getStatus(), ErpAuditStatus.APPROVE.getStatus())) { - throw exception(PURCHASE_IN_NOT_APPROVE); - } - return purchaseIn; - } - - @Override - public PageResult getPurchaseInPage(ErpPurchaseInPageReqVO pageReqVO) { - return purchaseInMapper.selectPage(pageReqVO); - } - - // ==================== 采购入库项 ==================== - - @Override - public List getPurchaseInItemListByInId(Long inId) { - return purchaseInItemMapper.selectListByInId(inId); - } - - @Override - public List getPurchaseInItemListByInIds(Collection inIds) { - if (CollUtil.isEmpty(inIds)) { - return Collections.emptyList(); - } - return purchaseInItemMapper.selectListByInIds(inIds); - } - -} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java deleted file mode 100644 index 6648825b32..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java +++ /dev/null @@ -1,304 +0,0 @@ -package cn.iocoder.yudao.module.erp.service.purchase; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns.ErpPurchaseReturnPageReqVO; -import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.returns.ErpPurchaseReturnSaveReqVO; -import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnItemDO; -import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseReturnItemMapper; -import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseReturnMapper; -import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; -import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; -import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; -import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; -import cn.iocoder.yudao.module.erp.service.product.ErpProductService; -import cn.iocoder.yudao.module.erp.service.stock.ErpStockRecordService; -import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.math.BigDecimal; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; - -// TODO 芋艿:记录操作日志 - -/** - * ERP 采购退货 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class ErpPurchaseReturnServiceImpl implements ErpPurchaseReturnService { - - @Resource - private ErpPurchaseReturnMapper purchaseReturnMapper; - @Resource - private ErpPurchaseReturnItemMapper purchaseReturnItemMapper; - - @Resource - private ErpNoRedisDAO noRedisDAO; - - @Resource - private ErpProductService productService; - @Resource - @Lazy // 延迟加载,避免循环依赖 - private ErpPurchaseOrderService purchaseOrderService; - @Resource - private ErpAccountService accountService; - @Resource - private ErpStockRecordService stockRecordService; - - @Override - @Transactional(rollbackFor = Exception.class) - public Long createPurchaseReturn(ErpPurchaseReturnSaveReqVO createReqVO) { - // 1.1 校验采购订单已审核 - ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.validatePurchaseOrder(createReqVO.getOrderId()); - // 1.2 校验退货项的有效性 - List purchaseReturnItems = validatePurchaseReturnItems(createReqVO.getItems()); - // 1.3 校验结算账户 - accountService.validateAccount(createReqVO.getAccountId()); - // 1.4 生成退货单号,并校验唯一性 - String no = noRedisDAO.generate(ErpNoRedisDAO.PURCHASE_RETURN_NO_PREFIX); - if (purchaseReturnMapper.selectByNo(no) != null) { - throw exception(PURCHASE_RETURN_NO_EXISTS); - } - - // 2.1 插入退货 - ErpPurchaseReturnDO purchaseReturn = BeanUtils.toBean(createReqVO, ErpPurchaseReturnDO.class, in -> in - .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())) - .setOrderNo(purchaseOrder.getNo()).setSupplierId(purchaseOrder.getSupplierId()); - calculateTotalPrice(purchaseReturn, purchaseReturnItems); - purchaseReturnMapper.insert(purchaseReturn); - // 2.2 插入退货项 - purchaseReturnItems.forEach(o -> o.setReturnId(purchaseReturn.getId())); - purchaseReturnItemMapper.insertBatch(purchaseReturnItems); - - // 3. 更新采购订单的退货数量 - updatePurchaseOrderReturnCount(createReqVO.getOrderId()); - return purchaseReturn.getId(); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updatePurchaseReturn(ErpPurchaseReturnSaveReqVO updateReqVO) { - // 1.1 校验存在 - ErpPurchaseReturnDO purchaseReturn = validatePurchaseReturnExists(updateReqVO.getId()); - if (ErpAuditStatus.APPROVE.getStatus().equals(purchaseReturn.getStatus())) { - throw exception(PURCHASE_RETURN_UPDATE_FAIL_APPROVE, purchaseReturn.getNo()); - } - // 1.2 校验采购订单已审核 - ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.validatePurchaseOrder(updateReqVO.getOrderId()); - // 1.3 校验结算账户 - accountService.validateAccount(updateReqVO.getAccountId()); - // 1.4 校验订单项的有效性 - List purchaseReturnItems = validatePurchaseReturnItems(updateReqVO.getItems()); - - // 2.1 更新退货 - ErpPurchaseReturnDO updateObj = BeanUtils.toBean(updateReqVO, ErpPurchaseReturnDO.class) - .setOrderNo(purchaseOrder.getNo()).setSupplierId(purchaseOrder.getSupplierId()); - calculateTotalPrice(updateObj, purchaseReturnItems); - purchaseReturnMapper.updateById(updateObj); - // 2.2 更新退货项 - updatePurchaseReturnItemList(updateReqVO.getId(), purchaseReturnItems); - - // 3.1 更新采购订单的出库数量 - updatePurchaseOrderReturnCount(updateObj.getOrderId()); - // 3.2 注意:如果采购订单编号变更了,需要更新“老”采购订单的出库数量 - if (ObjectUtil.notEqual(purchaseReturn.getOrderId(), updateObj.getOrderId())) { - updatePurchaseOrderReturnCount(purchaseReturn.getOrderId()); - } - } - - private void calculateTotalPrice(ErpPurchaseReturnDO purchaseReturn, List purchaseReturnItems) { - purchaseReturn.setTotalCount(getSumValue(purchaseReturnItems, ErpPurchaseReturnItemDO::getCount, BigDecimal::add)); - purchaseReturn.setTotalProductPrice(getSumValue(purchaseReturnItems, ErpPurchaseReturnItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); - purchaseReturn.setTotalTaxPrice(getSumValue(purchaseReturnItems, ErpPurchaseReturnItemDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO)); - purchaseReturn.setTotalPrice(purchaseReturn.getTotalProductPrice().add(purchaseReturn.getTotalTaxPrice())); - // 计算优惠价格 - if (purchaseReturn.getDiscountPercent() == null) { - purchaseReturn.setDiscountPercent(BigDecimal.ZERO); - } - purchaseReturn.setDiscountPrice(MoneyUtils.priceMultiplyPercent(purchaseReturn.getTotalPrice(), purchaseReturn.getDiscountPercent())); - purchaseReturn.setTotalPrice(purchaseReturn.getTotalPrice().subtract(purchaseReturn.getDiscountPrice().add(purchaseReturn.getOtherPrice()))); - } - - private void updatePurchaseOrderReturnCount(Long orderId) { - // 1.1 查询采购订单对应的采购出库单列表 - List purchaseReturns = purchaseReturnMapper.selectListByOrderId(orderId); - // 1.2 查询对应的采购订单项的退货数量 - Map returnCountMap = purchaseReturnItemMapper.selectOrderItemCountSumMapByReturnIds( - convertList(purchaseReturns, ErpPurchaseReturnDO::getId)); - // 2. 更新采购订单的出库数量 - purchaseOrderService.updatePurchaseOrderReturnCount(orderId, returnCountMap); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updatePurchaseReturnStatus(Long id, Integer status) { - boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); - // 1.1 校验存在 - ErpPurchaseReturnDO purchaseReturn = validatePurchaseReturnExists(id); - // 1.2 校验状态 - if (purchaseReturn.getStatus().equals(status)) { - throw exception(approve ? PURCHASE_RETURN_APPROVE_FAIL : PURCHASE_RETURN_PROCESS_FAIL); - } - // 1.3 校验已退款 - if (!approve && purchaseReturn.getRefundPrice().compareTo(BigDecimal.ZERO) > 0) { - throw exception(PURCHASE_RETURN_PROCESS_FAIL_EXISTS_REFUND); - } - - // 2. 更新状态 - int updateCount = purchaseReturnMapper.updateByIdAndStatus(id, purchaseReturn.getStatus(), - new ErpPurchaseReturnDO().setStatus(status)); - if (updateCount == 0) { - throw exception(approve ? PURCHASE_RETURN_APPROVE_FAIL : PURCHASE_RETURN_PROCESS_FAIL); - } - - // 3. 变更库存 - List purchaseReturnItems = purchaseReturnItemMapper.selectListByReturnId(id); - Integer bizType = approve ? ErpStockRecordBizTypeEnum.PURCHASE_RETURN.getType() - : ErpStockRecordBizTypeEnum.PURCHASE_RETURN_CANCEL.getType(); - purchaseReturnItems.forEach(purchaseReturnItem -> { - BigDecimal count = approve ? purchaseReturnItem.getCount().negate() : purchaseReturnItem.getCount(); - stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( - purchaseReturnItem.getProductId(), purchaseReturnItem.getWarehouseId(), count, - bizType, purchaseReturnItem.getReturnId(), purchaseReturnItem.getId(), purchaseReturn.getNo())); - }); - } - - @Override - public void updatePurchaseReturnRefundPrice(Long id, BigDecimal refundPrice) { - ErpPurchaseReturnDO purchaseReturn = purchaseReturnMapper.selectById(id); - if (purchaseReturn.getRefundPrice().equals(refundPrice)) { - return; - } - if (refundPrice.compareTo(purchaseReturn.getTotalPrice()) > 0) { - throw exception(PURCHASE_RETURN_FAIL_REFUND_PRICE_EXCEED, refundPrice, purchaseReturn.getTotalPrice()); - } - purchaseReturnMapper.updateById(new ErpPurchaseReturnDO().setId(id).setRefundPrice(refundPrice)); - } - - private List validatePurchaseReturnItems(List list) { - // 1. 校验产品存在 - List productList = productService.validProductList( - convertSet(list, ErpPurchaseReturnSaveReqVO.Item::getProductId)); - Map productMap = convertMap(productList, ErpProductDO::getId); - // 2. 转化为 ErpPurchaseReturnItemDO 列表 - return convertList(list, o -> BeanUtils.toBean(o, ErpPurchaseReturnItemDO.class, item -> { - item.setProductUnitId(productMap.get(item.getProductId()).getUnitId()); - item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())); - if (item.getTotalPrice() == null) { - return; - } - if (item.getTaxPercent() != null) { - item.setTaxPrice(MoneyUtils.priceMultiplyPercent(item.getTotalPrice(), item.getTaxPercent())); - } - })); - } - - private void updatePurchaseReturnItemList(Long id, List newList) { - // 第一步,对比新老数据,获得添加、修改、删除的列表 - List oldList = purchaseReturnItemMapper.selectListByReturnId(id); - List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 - (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); - - // 第二步,批量添加、修改、删除 - if (CollUtil.isNotEmpty(diffList.get(0))) { - diffList.get(0).forEach(o -> o.setReturnId(id)); - purchaseReturnItemMapper.insertBatch(diffList.get(0)); - } - if (CollUtil.isNotEmpty(diffList.get(1))) { - purchaseReturnItemMapper.updateBatch(diffList.get(1)); - } - if (CollUtil.isNotEmpty(diffList.get(2))) { - purchaseReturnItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpPurchaseReturnItemDO::getId)); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void deletePurchaseReturn(List ids) { - // 1. 校验不处于已审批 - List purchaseReturns = purchaseReturnMapper.selectBatchIds(ids); - if (CollUtil.isEmpty(purchaseReturns)) { - return; - } - purchaseReturns.forEach(purchaseReturn -> { - if (ErpAuditStatus.APPROVE.getStatus().equals(purchaseReturn.getStatus())) { - throw exception(PURCHASE_RETURN_DELETE_FAIL_APPROVE, purchaseReturn.getNo()); - } - }); - - // 2. 遍历删除,并记录操作日志 - purchaseReturns.forEach(purchaseReturn -> { - // 2.1 删除订单 - purchaseReturnMapper.deleteById(purchaseReturn.getId()); - // 2.2 删除订单项 - purchaseReturnItemMapper.deleteByReturnId(purchaseReturn.getId()); - - // 2.3 更新采购订单的出库数量 - updatePurchaseOrderReturnCount(purchaseReturn.getOrderId()); - }); - - } - - private ErpPurchaseReturnDO validatePurchaseReturnExists(Long id) { - ErpPurchaseReturnDO purchaseReturn = purchaseReturnMapper.selectById(id); - if (purchaseReturn == null) { - throw exception(PURCHASE_RETURN_NOT_EXISTS); - } - return purchaseReturn; - } - - @Override - public ErpPurchaseReturnDO getPurchaseReturn(Long id) { - return purchaseReturnMapper.selectById(id); - } - - @Override - public ErpPurchaseReturnDO validatePurchaseReturn(Long id) { - ErpPurchaseReturnDO purchaseReturn = getPurchaseReturn(id); - if (ObjectUtil.notEqual(purchaseReturn.getStatus(), ErpAuditStatus.APPROVE.getStatus())) { - throw exception(PURCHASE_RETURN_NOT_APPROVE); - } - return purchaseReturn; - } - - @Override - public PageResult getPurchaseReturnPage(ErpPurchaseReturnPageReqVO pageReqVO) { - return purchaseReturnMapper.selectPage(pageReqVO); - } - - // ==================== 采购退货项 ==================== - - @Override - public List getPurchaseReturnItemListByReturnId(Long returnId) { - return purchaseReturnItemMapper.selectListByReturnId(returnId); - } - - @Override - public List getPurchaseReturnItemListByReturnIds(Collection returnIds) { - if (CollUtil.isEmpty(returnIds)) { - return Collections.emptyList(); - } - return purchaseReturnItemMapper.selectListByReturnIds(returnIds); - } - -} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java deleted file mode 100644 index 16d20dd376..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java +++ /dev/null @@ -1,316 +0,0 @@ -package cn.iocoder.yudao.module.erp.service.sale; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutPageReqVO; -import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutSaveReqVO; -import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutItemDO; -import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOutItemMapper; -import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOutMapper; -import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; -import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; -import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; -import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; -import cn.iocoder.yudao.module.erp.service.product.ErpProductService; -import cn.iocoder.yudao.module.erp.service.stock.ErpStockRecordService; -import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.math.BigDecimal; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; - -// TODO 芋艿:记录操作日志 - -/** - * ERP 销售出库 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class ErpSaleOutServiceImpl implements ErpSaleOutService { - - @Resource - private ErpSaleOutMapper saleOutMapper; - @Resource - private ErpSaleOutItemMapper saleOutItemMapper; - - @Resource - private ErpNoRedisDAO noRedisDAO; - - @Resource - private ErpProductService productService; - @Resource - @Lazy // 延迟加载,避免循环依赖 - private ErpSaleOrderService saleOrderService; - @Resource - private ErpAccountService accountService; - @Resource - private ErpStockRecordService stockRecordService; - - @Resource - private AdminUserApi adminUserApi; - - @Override - @Transactional(rollbackFor = Exception.class) - public Long createSaleOut(ErpSaleOutSaveReqVO createReqVO) { - // 1.1 校验销售订单已审核 - ErpSaleOrderDO saleOrder = saleOrderService.validateSaleOrder(createReqVO.getOrderId()); - // 1.2 校验出库项的有效性 - List saleOutItems = validateSaleOutItems(createReqVO.getItems()); - // 1.3 校验结算账户 - accountService.validateAccount(createReqVO.getAccountId()); - // 1.4 校验销售人员 - if (createReqVO.getSaleUserId() != null) { - adminUserApi.validateUser(createReqVO.getSaleUserId()); - } - // 1.5 生成出库单号,并校验唯一性 - String no = noRedisDAO.generate(ErpNoRedisDAO.SALE_OUT_NO_PREFIX); - if (saleOutMapper.selectByNo(no) != null) { - throw exception(SALE_OUT_NO_EXISTS); - } - - // 2.1 插入出库 - ErpSaleOutDO saleOut = BeanUtils.toBean(createReqVO, ErpSaleOutDO.class, in -> in - .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())) - .setOrderNo(saleOrder.getNo()).setCustomerId(saleOrder.getCustomerId()); - calculateTotalPrice(saleOut, saleOutItems); - saleOutMapper.insert(saleOut); - // 2.2 插入出库项 - saleOutItems.forEach(o -> o.setOutId(saleOut.getId())); - saleOutItemMapper.insertBatch(saleOutItems); - - // 3. 更新销售订单的出库数量 - updateSaleOrderOutCount(createReqVO.getOrderId()); - return saleOut.getId(); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updateSaleOut(ErpSaleOutSaveReqVO updateReqVO) { - // 1.1 校验存在 - ErpSaleOutDO saleOut = validateSaleOutExists(updateReqVO.getId()); - if (ErpAuditStatus.APPROVE.getStatus().equals(saleOut.getStatus())) { - throw exception(SALE_OUT_UPDATE_FAIL_APPROVE, saleOut.getNo()); - } - // 1.2 校验销售订单已审核 - ErpSaleOrderDO saleOrder = saleOrderService.validateSaleOrder(updateReqVO.getOrderId()); - // 1.3 校验结算账户 - accountService.validateAccount(updateReqVO.getAccountId()); - // 1.4 校验销售人员 - if (updateReqVO.getSaleUserId() != null) { - adminUserApi.validateUser(updateReqVO.getSaleUserId()); - } - // 1.5 校验订单项的有效性 - List saleOutItems = validateSaleOutItems(updateReqVO.getItems()); - - // 2.1 更新出库 - ErpSaleOutDO updateObj = BeanUtils.toBean(updateReqVO, ErpSaleOutDO.class) - .setOrderNo(saleOrder.getNo()).setCustomerId(saleOrder.getCustomerId()); - calculateTotalPrice(updateObj, saleOutItems); - saleOutMapper.updateById(updateObj); - // 2.2 更新出库项 - updateSaleOutItemList(updateReqVO.getId(), saleOutItems); - - // 3.1 更新销售订单的出库数量 - updateSaleOrderOutCount(updateObj.getOrderId()); - // 3.2 注意:如果销售订单编号变更了,需要更新“老”销售订单的出库数量 - if (ObjectUtil.notEqual(saleOut.getOrderId(), updateObj.getOrderId())) { - updateSaleOrderOutCount(saleOut.getOrderId()); - } - } - - private void calculateTotalPrice(ErpSaleOutDO saleOut, List saleOutItems) { - saleOut.setTotalCount(getSumValue(saleOutItems, ErpSaleOutItemDO::getCount, BigDecimal::add)); - saleOut.setTotalProductPrice(getSumValue(saleOutItems, ErpSaleOutItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); - saleOut.setTotalTaxPrice(getSumValue(saleOutItems, ErpSaleOutItemDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO)); - saleOut.setTotalPrice(saleOut.getTotalProductPrice().add(saleOut.getTotalTaxPrice())); - // 计算优惠价格 - if (saleOut.getDiscountPercent() == null) { - saleOut.setDiscountPercent(BigDecimal.ZERO); - } - saleOut.setDiscountPrice(MoneyUtils.priceMultiplyPercent(saleOut.getTotalPrice(), saleOut.getDiscountPercent())); - saleOut.setTotalPrice(saleOut.getTotalPrice().subtract(saleOut.getDiscountPrice().add(saleOut.getOtherPrice()))); - } - - private void updateSaleOrderOutCount(Long orderId) { - // 1.1 查询销售订单对应的销售出库单列表 - List saleOuts = saleOutMapper.selectListByOrderId(orderId); - // 1.2 查询对应的销售订单项的出库数量 - Map returnCountMap = saleOutItemMapper.selectOrderItemCountSumMapByOutIds( - convertList(saleOuts, ErpSaleOutDO::getId)); - // 2. 更新销售订单的出库数量 - saleOrderService.updateSaleOrderOutCount(orderId, returnCountMap); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updateSaleOutStatus(Long id, Integer status) { - boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); - // 1.1 校验存在 - ErpSaleOutDO saleOut = validateSaleOutExists(id); - // 1.2 校验状态 - if (saleOut.getStatus().equals(status)) { - throw exception(approve ? SALE_OUT_APPROVE_FAIL : SALE_OUT_PROCESS_FAIL); - } - // 1.3 校验已退款 - if (!approve && saleOut.getReceiptPrice().compareTo(BigDecimal.ZERO) > 0) { - throw exception(SALE_OUT_PROCESS_FAIL_EXISTS_RECEIPT); - } - - // 2. 更新状态 - int updateCount = saleOutMapper.updateByIdAndStatus(id, saleOut.getStatus(), - new ErpSaleOutDO().setStatus(status)); - if (updateCount == 0) { - throw exception(approve ? SALE_OUT_APPROVE_FAIL : SALE_OUT_PROCESS_FAIL); - } - - // 3. 变更库存 - List saleOutItems = saleOutItemMapper.selectListByOutId(id); - Integer bizType = approve ? ErpStockRecordBizTypeEnum.SALE_OUT.getType() - : ErpStockRecordBizTypeEnum.SALE_OUT_CANCEL.getType(); - saleOutItems.forEach(saleOutItem -> { - BigDecimal count = approve ? saleOutItem.getCount().negate() : saleOutItem.getCount(); - stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( - saleOutItem.getProductId(), saleOutItem.getWarehouseId(), count, - bizType, saleOutItem.getOutId(), saleOutItem.getId(), saleOut.getNo())); - }); - } - - @Override - public void updateSaleInReceiptPrice(Long id, BigDecimal receiptPrice) { - ErpSaleOutDO saleOut = saleOutMapper.selectById(id); - if (saleOut.getReceiptPrice().equals(receiptPrice)) { - return; - } - if (receiptPrice.compareTo(saleOut.getTotalPrice()) > 0) { - throw exception(SALE_OUT_FAIL_RECEIPT_PRICE_EXCEED, receiptPrice, saleOut.getTotalPrice()); - } - saleOutMapper.updateById(new ErpSaleOutDO().setId(id).setReceiptPrice(receiptPrice)); - } - - private List validateSaleOutItems(List list) { - // 1. 校验产品存在 - List productList = productService.validProductList( - convertSet(list, ErpSaleOutSaveReqVO.Item::getProductId)); - Map productMap = convertMap(productList, ErpProductDO::getId); - // 2. 转化为 ErpSaleOutItemDO 列表 - return convertList(list, o -> BeanUtils.toBean(o, ErpSaleOutItemDO.class, item -> { - item.setProductUnitId(productMap.get(item.getProductId()).getUnitId()); - item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())); - if (item.getTotalPrice() == null) { - return; - } - if (item.getTaxPercent() != null) { - item.setTaxPrice(MoneyUtils.priceMultiplyPercent(item.getTotalPrice(), item.getTaxPercent())); - } - })); - } - - private void updateSaleOutItemList(Long id, List newList) { - // 第一步,对比新老数据,获得添加、修改、删除的列表 - List oldList = saleOutItemMapper.selectListByOutId(id); - List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 - (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); - - // 第二步,批量添加、修改、删除 - if (CollUtil.isNotEmpty(diffList.get(0))) { - diffList.get(0).forEach(o -> o.setOutId(id)); - saleOutItemMapper.insertBatch(diffList.get(0)); - } - if (CollUtil.isNotEmpty(diffList.get(1))) { - saleOutItemMapper.updateBatch(diffList.get(1)); - } - if (CollUtil.isNotEmpty(diffList.get(2))) { - saleOutItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpSaleOutItemDO::getId)); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void deleteSaleOut(List ids) { - // 1. 校验不处于已审批 - List saleOuts = saleOutMapper.selectBatchIds(ids); - if (CollUtil.isEmpty(saleOuts)) { - return; - } - saleOuts.forEach(saleOut -> { - if (ErpAuditStatus.APPROVE.getStatus().equals(saleOut.getStatus())) { - throw exception(SALE_OUT_DELETE_FAIL_APPROVE, saleOut.getNo()); - } - }); - - // 2. 遍历删除,并记录操作日志 - saleOuts.forEach(saleOut -> { - // 2.1 删除订单 - saleOutMapper.deleteById(saleOut.getId()); - // 2.2 删除订单项 - saleOutItemMapper.deleteByOutId(saleOut.getId()); - - // 2.3 更新销售订单的出库数量 - updateSaleOrderOutCount(saleOut.getOrderId()); - }); - - } - - private ErpSaleOutDO validateSaleOutExists(Long id) { - ErpSaleOutDO saleOut = saleOutMapper.selectById(id); - if (saleOut == null) { - throw exception(SALE_OUT_NOT_EXISTS); - } - return saleOut; - } - - @Override - public ErpSaleOutDO getSaleOut(Long id) { - return saleOutMapper.selectById(id); - } - - @Override - public ErpSaleOutDO validateSaleOut(Long id) { - ErpSaleOutDO saleOut = validateSaleOutExists(id); - if (ObjectUtil.notEqual(saleOut.getStatus(), ErpAuditStatus.APPROVE.getStatus())) { - throw exception(SALE_OUT_NOT_APPROVE); - } - return saleOut; - } - - @Override - public PageResult getSaleOutPage(ErpSaleOutPageReqVO pageReqVO) { - return saleOutMapper.selectPage(pageReqVO); - } - - // ==================== 销售出库项 ==================== - - @Override - public List getSaleOutItemListByOutId(Long outId) { - return saleOutItemMapper.selectListByOutId(outId); - } - - @Override - public List getSaleOutItemListByOutIds(Collection outIds) { - if (CollUtil.isEmpty(outIds)) { - return Collections.emptyList(); - } - return saleOutItemMapper.selectListByOutIds(outIds); - } - -} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java deleted file mode 100644 index 209df114c0..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java +++ /dev/null @@ -1,316 +0,0 @@ -package cn.iocoder.yudao.module.erp.service.sale; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns.ErpSaleReturnPageReqVO; -import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.returns.ErpSaleReturnSaveReqVO; -import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnItemDO; -import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleReturnItemMapper; -import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleReturnMapper; -import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; -import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; -import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; -import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; -import cn.iocoder.yudao.module.erp.service.product.ErpProductService; -import cn.iocoder.yudao.module.erp.service.stock.ErpStockRecordService; -import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.math.BigDecimal; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; - -// TODO 芋艿:记录操作日志 - -/** - * ERP 销售退货 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class ErpSaleReturnServiceImpl implements ErpSaleReturnService { - - @Resource - private ErpSaleReturnMapper saleReturnMapper; - @Resource - private ErpSaleReturnItemMapper saleReturnItemMapper; - - @Resource - private ErpNoRedisDAO noRedisDAO; - - @Resource - private ErpProductService productService; - @Resource - @Lazy // 延迟加载,避免循环依赖 - private ErpSaleOrderService saleOrderService; - @Resource - private ErpAccountService accountService; - @Resource - private ErpStockRecordService stockRecordService; - - @Resource - private AdminUserApi adminUserApi; - - @Override - @Transactional(rollbackFor = Exception.class) - public Long createSaleReturn(ErpSaleReturnSaveReqVO createReqVO) { - // 1.1 校验销售订单已审核 - ErpSaleOrderDO saleOrder = saleOrderService.validateSaleOrder(createReqVO.getOrderId()); - // 1.2 校验退货项的有效性 - List saleReturnItems = validateSaleReturnItems(createReqVO.getItems()); - // 1.3 校验结算账户 - accountService.validateAccount(createReqVO.getAccountId()); - // 1.4 校验销售人员 - if (createReqVO.getSaleUserId() != null) { - adminUserApi.validateUser(createReqVO.getSaleUserId()); - } - // 1.5 生成退货单号,并校验唯一性 - String no = noRedisDAO.generate(ErpNoRedisDAO.SALE_RETURN_NO_PREFIX); - if (saleReturnMapper.selectByNo(no) != null) { - throw exception(SALE_RETURN_NO_EXISTS); - } - - // 2.1 插入退货 - ErpSaleReturnDO saleReturn = BeanUtils.toBean(createReqVO, ErpSaleReturnDO.class, in -> in - .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus())) - .setOrderNo(saleOrder.getNo()).setCustomerId(saleOrder.getCustomerId()); - calculateTotalPrice(saleReturn, saleReturnItems); - saleReturnMapper.insert(saleReturn); - // 2.2 插入退货项 - saleReturnItems.forEach(o -> o.setReturnId(saleReturn.getId())); - saleReturnItemMapper.insertBatch(saleReturnItems); - - // 3. 更新销售订单的退货数量 - updateSaleOrderReturnCount(createReqVO.getOrderId()); - return saleReturn.getId(); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updateSaleReturn(ErpSaleReturnSaveReqVO updateReqVO) { - // 1.1 校验存在 - ErpSaleReturnDO saleReturn = validateSaleReturnExists(updateReqVO.getId()); - if (ErpAuditStatus.APPROVE.getStatus().equals(saleReturn.getStatus())) { - throw exception(SALE_RETURN_UPDATE_FAIL_APPROVE, saleReturn.getNo()); - } - // 1.2 校验销售订单已审核 - ErpSaleOrderDO saleOrder = saleOrderService.validateSaleOrder(updateReqVO.getOrderId()); - // 1.3 校验结算账户 - accountService.validateAccount(updateReqVO.getAccountId()); - // 1.4 校验销售人员 - if (updateReqVO.getSaleUserId() != null) { - adminUserApi.validateUser(updateReqVO.getSaleUserId()); - } - // 1.5 校验订单项的有效性 - List saleReturnItems = validateSaleReturnItems(updateReqVO.getItems()); - - // 2.1 更新退货 - ErpSaleReturnDO updateObj = BeanUtils.toBean(updateReqVO, ErpSaleReturnDO.class) - .setOrderNo(saleOrder.getNo()).setCustomerId(saleOrder.getCustomerId()); - calculateTotalPrice(updateObj, saleReturnItems); - saleReturnMapper.updateById(updateObj); - // 2.2 更新退货项 - updateSaleReturnItemList(updateReqVO.getId(), saleReturnItems); - - // 3.1 更新销售订单的出库数量 - updateSaleOrderReturnCount(updateObj.getOrderId()); - // 3.2 注意:如果销售订单编号变更了,需要更新“老”销售订单的出库数量 - if (ObjectUtil.notEqual(saleReturn.getOrderId(), updateObj.getOrderId())) { - updateSaleOrderReturnCount(saleReturn.getOrderId()); - } - } - - private void calculateTotalPrice(ErpSaleReturnDO saleReturn, List saleReturnItems) { - saleReturn.setTotalCount(getSumValue(saleReturnItems, ErpSaleReturnItemDO::getCount, BigDecimal::add)); - saleReturn.setTotalProductPrice(getSumValue(saleReturnItems, ErpSaleReturnItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); - saleReturn.setTotalTaxPrice(getSumValue(saleReturnItems, ErpSaleReturnItemDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO)); - saleReturn.setTotalPrice(saleReturn.getTotalProductPrice().add(saleReturn.getTotalTaxPrice())); - // 计算优惠价格 - if (saleReturn.getDiscountPercent() == null) { - saleReturn.setDiscountPercent(BigDecimal.ZERO); - } - saleReturn.setDiscountPrice(MoneyUtils.priceMultiplyPercent(saleReturn.getTotalPrice(), saleReturn.getDiscountPercent())); - saleReturn.setTotalPrice(saleReturn.getTotalPrice().subtract(saleReturn.getDiscountPrice().add(saleReturn.getOtherPrice()))); - } - - private void updateSaleOrderReturnCount(Long orderId) { - // 1.1 查询销售订单对应的销售出库单列表 - List saleReturns = saleReturnMapper.selectListByOrderId(orderId); - // 1.2 查询对应的销售订单项的退货数量 - Map returnCountMap = saleReturnItemMapper.selectOrderItemCountSumMapByReturnIds( - convertList(saleReturns, ErpSaleReturnDO::getId)); - // 2. 更新销售订单的出库数量 - saleOrderService.updateSaleOrderReturnCount(orderId, returnCountMap); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updateSaleReturnStatus(Long id, Integer status) { - boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); - // 1.1 校验存在 - ErpSaleReturnDO saleReturn = validateSaleReturnExists(id); - // 1.2 校验状态 - if (saleReturn.getStatus().equals(status)) { - throw exception(approve ? SALE_RETURN_APPROVE_FAIL : SALE_RETURN_PROCESS_FAIL); - } - // 1.3 校验已退款 - if (!approve && saleReturn.getRefundPrice().compareTo(BigDecimal.ZERO) > 0) { - throw exception(SALE_RETURN_PROCESS_FAIL_EXISTS_REFUND); - } - - // 2. 更新状态 - int updateCount = saleReturnMapper.updateByIdAndStatus(id, saleReturn.getStatus(), - new ErpSaleReturnDO().setStatus(status)); - if (updateCount == 0) { - throw exception(approve ? SALE_RETURN_APPROVE_FAIL : SALE_RETURN_PROCESS_FAIL); - } - - // 3. 变更库存 - List saleReturnItems = saleReturnItemMapper.selectListByReturnId(id); - Integer bizType = approve ? ErpStockRecordBizTypeEnum.SALE_RETURN.getType() - : ErpStockRecordBizTypeEnum.SALE_RETURN_CANCEL.getType(); - saleReturnItems.forEach(saleReturnItem -> { - BigDecimal count = approve ? saleReturnItem.getCount() : saleReturnItem.getCount().negate(); - stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( - saleReturnItem.getProductId(), saleReturnItem.getWarehouseId(), count, - bizType, saleReturnItem.getReturnId(), saleReturnItem.getId(), saleReturn.getNo())); - }); - } - - @Override - public void updateSaleReturnRefundPrice(Long id, BigDecimal refundPrice) { - ErpSaleReturnDO saleReturn = saleReturnMapper.selectById(id); - if (saleReturn.getRefundPrice().equals(refundPrice)) { - return; - } - if (refundPrice.compareTo(saleReturn.getTotalPrice()) > 0) { - throw exception(SALE_RETURN_FAIL_REFUND_PRICE_EXCEED, refundPrice, saleReturn.getTotalPrice()); - } - saleReturnMapper.updateById(new ErpSaleReturnDO().setId(id).setRefundPrice(refundPrice)); - } - - private List validateSaleReturnItems(List list) { - // 1. 校验产品存在 - List productList = productService.validProductList( - convertSet(list, ErpSaleReturnSaveReqVO.Item::getProductId)); - Map productMap = convertMap(productList, ErpProductDO::getId); - // 2. 转化为 ErpSaleReturnItemDO 列表 - return convertList(list, o -> BeanUtils.toBean(o, ErpSaleReturnItemDO.class, item -> { - item.setProductUnitId(productMap.get(item.getProductId()).getUnitId()); - item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())); - if (item.getTotalPrice() == null) { - return; - } - if (item.getTaxPercent() != null) { - item.setTaxPrice(MoneyUtils.priceMultiplyPercent(item.getTotalPrice(), item.getTaxPercent())); - } - })); - } - - private void updateSaleReturnItemList(Long id, List newList) { - // 第一步,对比新老数据,获得添加、修改、删除的列表 - List oldList = saleReturnItemMapper.selectListByReturnId(id); - List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 - (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); - - // 第二步,批量添加、修改、删除 - if (CollUtil.isNotEmpty(diffList.get(0))) { - diffList.get(0).forEach(o -> o.setReturnId(id)); - saleReturnItemMapper.insertBatch(diffList.get(0)); - } - if (CollUtil.isNotEmpty(diffList.get(1))) { - saleReturnItemMapper.updateBatch(diffList.get(1)); - } - if (CollUtil.isNotEmpty(diffList.get(2))) { - saleReturnItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpSaleReturnItemDO::getId)); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void deleteSaleReturn(List ids) { - // 1. 校验不处于已审批 - List saleReturns = saleReturnMapper.selectBatchIds(ids); - if (CollUtil.isEmpty(saleReturns)) { - return; - } - saleReturns.forEach(saleReturn -> { - if (ErpAuditStatus.APPROVE.getStatus().equals(saleReturn.getStatus())) { - throw exception(SALE_RETURN_DELETE_FAIL_APPROVE, saleReturn.getNo()); - } - }); - - // 2. 遍历删除,并记录操作日志 - saleReturns.forEach(saleReturn -> { - // 2.1 删除订单 - saleReturnMapper.deleteById(saleReturn.getId()); - // 2.2 删除订单项 - saleReturnItemMapper.deleteByReturnId(saleReturn.getId()); - - // 2.3 更新销售订单的出库数量 - updateSaleOrderReturnCount(saleReturn.getOrderId()); - }); - - } - - private ErpSaleReturnDO validateSaleReturnExists(Long id) { - ErpSaleReturnDO saleReturn = saleReturnMapper.selectById(id); - if (saleReturn == null) { - throw exception(SALE_RETURN_NOT_EXISTS); - } - return saleReturn; - } - - @Override - public ErpSaleReturnDO getSaleReturn(Long id) { - return saleReturnMapper.selectById(id); - } - - @Override - public ErpSaleReturnDO validateSaleReturn(Long id) { - ErpSaleReturnDO saleReturn = validateSaleReturnExists(id); - if (ObjectUtil.notEqual(saleReturn.getStatus(), ErpAuditStatus.APPROVE.getStatus())) { - throw exception(SALE_RETURN_NOT_APPROVE); - } - return saleReturn; - } - - @Override - public PageResult getSaleReturnPage(ErpSaleReturnPageReqVO pageReqVO) { - return saleReturnMapper.selectPage(pageReqVO); - } - - // ==================== 销售退货项 ==================== - - @Override - public List getSaleReturnItemListByReturnId(Long returnId) { - return saleReturnItemMapper.selectListByReturnId(returnId); - } - - @Override - public List getSaleReturnItemListByReturnIds(Collection returnIds) { - if (CollUtil.isEmpty(returnIds)) { - return Collections.emptyList(); - } - return saleReturnItemMapper.selectListByReturnIds(returnIds); - } - -} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsService.java deleted file mode 100644 index 9134094879..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsService.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.erp.service.statistics; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -/** - * ERP 采购统计 Service 接口 - * - * @author 芋道源码 - */ -public interface ErpPurchaseStatisticsService { - - /** - * 获得采购金额 - * - * 计算逻辑:采购出库的金额 - 采购退货的金额 - * - * @param beginTime >= 开始时间 - * @param endTime < 结束时间 - * @return 采购金额 - */ - BigDecimal getPurchasePrice(LocalDateTime beginTime, LocalDateTime endTime); - -} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsServiceImpl.java deleted file mode 100644 index 588ff74ba5..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpPurchaseStatisticsServiceImpl.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.erp.service.statistics; - -import cn.iocoder.yudao.module.erp.dal.mysql.statistics.ErpPurchaseStatisticsMapper; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; -import java.math.BigDecimal; -import java.time.LocalDateTime; - -/** - * ERP 采购统计 Service 实现类 - * - * @author 芋道源码 - */ -@Service -public class ErpPurchaseStatisticsServiceImpl implements ErpPurchaseStatisticsService { - - @Resource - private ErpPurchaseStatisticsMapper purchaseStatisticsMapper; - - @Override - public BigDecimal getPurchasePrice(LocalDateTime beginTime, LocalDateTime endTime) { - return purchaseStatisticsMapper.getPurchasePrice(beginTime, endTime); - } - -} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsService.java deleted file mode 100644 index 3c28bc327e..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsService.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.erp.service.statistics; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -/** - * ERP 销售统计 Service 接口 - * - * @author 芋道源码 - */ -public interface ErpSaleStatisticsService { - - /** - * 获得销售金额 - * - * 计算逻辑:销售出库的金额 - 销售退货的金额 - * - * @param beginTime >= 开始时间 - * @param endTime < 结束时间 - * @return 销售金额 - */ - BigDecimal getSalePrice(LocalDateTime beginTime, LocalDateTime endTime); - -} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsServiceImpl.java deleted file mode 100644 index a6664332a2..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/statistics/ErpSaleStatisticsServiceImpl.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.erp.service.statistics; - -import cn.iocoder.yudao.module.erp.dal.mysql.statistics.ErpSaleStatisticsMapper; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; -import java.math.BigDecimal; -import java.time.LocalDateTime; - -/** - * ERP 销售统计 Service 实现类 - * - * @author 芋道源码 - */ -@Service -public class ErpSaleStatisticsServiceImpl implements ErpSaleStatisticsService { - - @Resource - private ErpSaleStatisticsMapper saleStatisticsMapper; - - @Override - public BigDecimal getSalePrice(LocalDateTime beginTime, LocalDateTime endTime) { - return saleStatisticsMapper.getSalePrice(beginTime, endTime); - } - -} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java deleted file mode 100644 index 2d6f96fb3a..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java +++ /dev/null @@ -1,102 +0,0 @@ -package cn.iocoder.yudao.module.erp.service.stock; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSaveReqVO; -import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; -import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; - -import javax.validation.Valid; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; - -/** - * ERP 仓库 Service 接口 - * - * @author 芋道源码 - */ -public interface ErpWarehouseService { - - /** - * 创建仓库 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createWarehouse(@Valid ErpWarehouseSaveReqVO createReqVO); - - /** - * 更新ERP 仓库 - * - * @param updateReqVO 更新信息 - */ - void updateWarehouse(@Valid ErpWarehouseSaveReqVO updateReqVO); - - /** - * 更新仓库默认状态 - * - * @param id 编号 - * @param defaultStatus 默认状态 - */ - void updateWarehouseDefaultStatus(Long id, Boolean defaultStatus); - - /** - * 删除仓库 - * - * @param id 编号 - */ - void deleteWarehouse(Long id); - - /** - * 获得仓库 - * - * @param id 编号 - * @return 仓库 - */ - ErpWarehouseDO getWarehouse(Long id); - - /** - * 校验仓库列表的有效性 - * - * @param ids 编号数组 - * @return 仓库列表 - */ - List validWarehouseList(Collection ids); - - /** - * 获得指定状态的仓库列表 - * - * @param status 状态 - * @return 仓库列表 - */ - List getWarehouseListByStatus(Integer status); - - /** - * 获得仓库列表 - * - * @param ids 编号数组 - * @return 仓库列表 - */ - List getWarehouseList(Collection ids); - - /** - * 获得仓库 Map - * - * @param ids 编号数组 - * @return 仓库 Map - */ - default Map getWarehouseMap(Collection ids) { - return convertMap(getWarehouseList(ids), ErpWarehouseDO::getId); - } - - /** - * 获得仓库分页 - * - * @param pageReqVO 分页查询 - * @return 仓库分页 - */ - PageResult getWarehousePage(ErpWarehousePageReqVO pageReqVO); - -} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java deleted file mode 100644 index 9e80128dd0..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java +++ /dev/null @@ -1,126 +0,0 @@ -package cn.iocoder.yudao.module.erp.service.stock; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSaveReqVO; -import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; -import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; -import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpWarehouseMapper; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import javax.annotation.Resource; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_NOT_ENABLE; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_NOT_EXISTS; - -/** - * ERP 仓库 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class ErpWarehouseServiceImpl implements ErpWarehouseService { - - @Resource - private ErpWarehouseMapper warehouseMapper; - - @Override - public Long createWarehouse(ErpWarehouseSaveReqVO createReqVO) { - // 插入 - ErpWarehouseDO warehouse = BeanUtils.toBean(createReqVO, ErpWarehouseDO.class); - warehouseMapper.insert(warehouse); - // 返回 - return warehouse.getId(); - } - - @Override - public void updateWarehouse(ErpWarehouseSaveReqVO updateReqVO) { - // 校验存在 - validateWarehouseExists(updateReqVO.getId()); - // 更新 - ErpWarehouseDO updateObj = BeanUtils.toBean(updateReqVO, ErpWarehouseDO.class); - warehouseMapper.updateById(updateObj); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void updateWarehouseDefaultStatus(Long id, Boolean defaultStatus) { - // 1. 校验存在 - validateWarehouseExists(id); - - // 2.1 如果开启,则需要关闭所有其它的默认 - if (defaultStatus) { - ErpWarehouseDO warehouse = warehouseMapper.selectByDefaultStatus(); - if (warehouse != null) { - warehouseMapper.updateById(new ErpWarehouseDO().setId(warehouse.getId()).setDefaultStatus(false)); - } - } - // 2.2 更新对应的默认状态 - warehouseMapper.updateById(new ErpWarehouseDO().setId(id).setDefaultStatus(defaultStatus)); - } - - @Override - public void deleteWarehouse(Long id) { - // 校验存在 - validateWarehouseExists(id); - // 删除 - warehouseMapper.deleteById(id); - } - - private void validateWarehouseExists(Long id) { - if (warehouseMapper.selectById(id) == null) { - throw exception(WAREHOUSE_NOT_EXISTS); - } - } - - @Override - public ErpWarehouseDO getWarehouse(Long id) { - return warehouseMapper.selectById(id); - } - - @Override - public List validWarehouseList(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return Collections.emptyList(); - } - List list = warehouseMapper.selectBatchIds(ids); - Map warehouseMap = convertMap(list, ErpWarehouseDO::getId); - for (Long id : ids) { - ErpWarehouseDO warehouse = warehouseMap.get(id); - if (warehouseMap.get(id) == null) { - throw exception(WAREHOUSE_NOT_EXISTS); - } - if (CommonStatusEnum.isDisable(warehouse.getStatus())) { - throw exception(WAREHOUSE_NOT_ENABLE, warehouse.getName()); - } - } - return list; - } - - @Override - public List getWarehouseListByStatus(Integer status) { - return warehouseMapper.selectListByStatus(status); - } - - @Override - public List getWarehouseList(Collection ids) { - return warehouseMapper.selectBatchIds(ids); - } - - @Override - public PageResult getWarehousePage(ErpWarehousePageReqVO pageReqVO) { - return warehouseMapper.selectPage(pageReqVO); - } - -} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpPurchaseStatisticsMapper.xml b/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpPurchaseStatisticsMapper.xml deleted file mode 100644 index e2b25992a4..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpPurchaseStatisticsMapper.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpSaleStatisticsMapper.xml b/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpSaleStatisticsMapper.xml deleted file mode 100644 index 8e74606c9e..0000000000 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/resources/mapper/statistics/ErpSaleStatisticsMapper.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/ftp/FtpFileClientTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/ftp/FtpFileClientTest.java deleted file mode 100644 index b8876f7fc4..0000000000 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/ftp/FtpFileClientTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.yudao.module.infra.framework.file.core.ftp; - -import cn.hutool.core.io.resource.ResourceUtil; -import cn.hutool.core.util.IdUtil; -import cn.hutool.extra.ftp.FtpMode; -import cn.iocoder.yudao.module.infra.framework.file.core.client.ftp.FtpFileClient; -import cn.iocoder.yudao.module.infra.framework.file.core.client.ftp.FtpFileClientConfig; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -public class FtpFileClientTest { - - @Test - @Disabled - public void test() { - // 创建客户端 - FtpFileClientConfig config = new FtpFileClientConfig(); - config.setDomain("http://127.0.0.1:48080"); - config.setBasePath("/home/ftp"); - config.setHost("kanchai.club"); - config.setPort(221); - config.setUsername(""); - config.setPassword(""); - config.setMode(FtpMode.Passive.name()); - FtpFileClient client = new FtpFileClient(0L, config); - client.init(); - // 上传文件 - String path = IdUtil.fastSimpleUUID() + ".jpg"; - byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); - String fullPath = client.upload(content, path, "image/jpeg"); - System.out.println("访问地址:" + fullPath); - if (false) { - byte[] bytes = client.getContent(path); - System.out.println("文件内容:" + bytes); - } - if (false) { - client.delete(path); - } - } - -} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/local/LocalFileClientTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/local/LocalFileClientTest.java deleted file mode 100644 index 7c622a5306..0000000000 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/local/LocalFileClientTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.infra.framework.file.core.local; - -import cn.hutool.core.io.resource.ResourceUtil; -import cn.hutool.core.util.IdUtil; -import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClient; -import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -public class LocalFileClientTest { - - @Test - @Disabled - public void test() { - // 创建客户端 - LocalFileClientConfig config = new LocalFileClientConfig(); - config.setDomain("http://127.0.0.1:48080"); - config.setBasePath("/Users/yunai/file_test"); - LocalFileClient client = new LocalFileClient(0L, config); - client.init(); - // 上传文件 - String path = IdUtil.fastSimpleUUID() + ".jpg"; - byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); - String fullPath = client.upload(content, path, "image/jpeg"); - System.out.println("访问地址:" + fullPath); - client.delete(path); - } - -} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/s3/S3FileClientTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/s3/S3FileClientTest.java deleted file mode 100644 index 1933e98587..0000000000 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/s3/S3FileClientTest.java +++ /dev/null @@ -1,119 +0,0 @@ -package cn.iocoder.yudao.module.infra.framework.file.core.s3; - -import cn.hutool.core.io.resource.ResourceUtil; -import cn.hutool.core.util.IdUtil; -import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; -import cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClient; -import cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import javax.validation.Validation; - -public class S3FileClientTest { - - @Test - @Disabled // MinIO,如果要集成测试,可以注释本行 - public void testMinIO() throws Exception { - S3FileClientConfig config = new S3FileClientConfig(); - // 配置成你自己的 - config.setAccessKey("admin"); - config.setAccessSecret("password"); - config.setBucket("yudaoyuanma"); - config.setDomain(null); - // 默认 9000 endpoint - config.setEndpoint("http://127.0.0.1:9000"); - - // 执行上传 - testExecuteUpload(config); - } - - @Test - @Disabled // 阿里云 OSS,如果要集成测试,可以注释本行 - public void testAliyun() throws Exception { - S3FileClientConfig config = new S3FileClientConfig(); - // 配置成你自己的 - config.setAccessKey(System.getenv("ALIYUN_ACCESS_KEY")); - config.setAccessSecret(System.getenv("ALIYUN_SECRET_KEY")); - config.setBucket("yunai-aoteman"); - config.setDomain(null); // 如果有自定义域名,则可以设置。http://ali-oss.iocoder.cn - // 默认北京的 endpoint - config.setEndpoint("oss-cn-beijing.aliyuncs.com"); - - // 执行上传 - testExecuteUpload(config); - } - - @Test - @Disabled // 腾讯云 COS,如果要集成测试,可以注释本行 - public void testQCloud() throws Exception { - S3FileClientConfig config = new S3FileClientConfig(); - // 配置成你自己的 - config.setAccessKey(System.getenv("QCLOUD_ACCESS_KEY")); - config.setAccessSecret(System.getenv("QCLOUD_SECRET_KEY")); - config.setBucket("aoteman-1255880240"); - config.setDomain(null); // 如果有自定义域名,则可以设置。http://tengxun-oss.iocoder.cn - // 默认上海的 endpoint - config.setEndpoint("cos.ap-shanghai.myqcloud.com"); - - // 执行上传 - testExecuteUpload(config); - } - - @Test - @Disabled // 七牛云存储,如果要集成测试,可以注释本行 - public void testQiniu() throws Exception { - S3FileClientConfig config = new S3FileClientConfig(); - // 配置成你自己的 -// config.setAccessKey(System.getenv("QINIU_ACCESS_KEY")); -// config.setAccessSecret(System.getenv("QINIU_SECRET_KEY")); - config.setAccessKey("b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8"); - config.setAccessSecret("kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP"); - config.setBucket("ruoyi-vue-pro"); - config.setDomain("http://test.yudao.iocoder.cn"); // 如果有自定义域名,则可以设置。http://static.yudao.iocoder.cn - // 默认上海的 endpoint - config.setEndpoint("s3-cn-south-1.qiniucs.com"); - - // 执行上传 - testExecuteUpload(config); - } - - @Test - @Disabled // 华为云存储,如果要集成测试,可以注释本行 - public void testHuaweiCloud() throws Exception { - S3FileClientConfig config = new S3FileClientConfig(); - // 配置成你自己的 -// config.setAccessKey(System.getenv("HUAWEI_CLOUD_ACCESS_KEY")); -// config.setAccessSecret(System.getenv("HUAWEI_CLOUD_SECRET_KEY")); - config.setBucket("yudao"); - config.setDomain(null); // 如果有自定义域名,则可以设置。 - // 默认上海的 endpoint - config.setEndpoint("obs.cn-east-3.myhuaweicloud.com"); - - // 执行上传 - testExecuteUpload(config); - } - - private void testExecuteUpload(S3FileClientConfig config) throws Exception { - // 校验配置 - ValidationUtils.validate(Validation.buildDefaultValidatorFactory().getValidator(), config); - // 创建 Client - S3FileClient client = new S3FileClient(0L, config); - client.init(); - // 上传文件 - String path = IdUtil.fastSimpleUUID() + ".jpg"; - byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); - String fullPath = client.upload(content, path, "image/jpeg"); - System.out.println("访问地址:" + fullPath); - // 读取文件 - if (true) { - byte[] bytes = client.getContent(path); - System.out.println("文件内容:" + bytes.length); - } - // 删除文件 - if (false) { - client.delete(path); - } - } - -} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/sftp/SftpFileClientTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/sftp/SftpFileClientTest.java deleted file mode 100644 index 1e00cf196f..0000000000 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/sftp/SftpFileClientTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.module.infra.framework.file.core.sftp; - -import cn.hutool.core.io.resource.ResourceUtil; -import cn.hutool.core.util.IdUtil; -import cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClient; -import cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClientConfig; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -public class SftpFileClientTest { - - @Test - @Disabled - public void test() { - // 创建客户端 - SftpFileClientConfig config = new SftpFileClientConfig(); - config.setDomain("http://127.0.0.1:48080"); - config.setBasePath("/home/ftp"); - config.setHost("kanchai.club"); - config.setPort(222); - config.setUsername(""); - config.setPassword(""); - SftpFileClient client = new SftpFileClient(0L, config); - client.init(); - // 上传文件 - String path = IdUtil.fastSimpleUUID() + ".jpg"; - byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); - String fullPath = client.upload(content, path, "image/jpeg"); - System.out.println("访问地址:" + fullPath); - if (false) { - byte[] bytes = client.getContent(path); - System.out.println("文件内容:" + bytes); - } - if (false) { - client.delete(path); - } - } - -} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java deleted file mode 100644 index c3987a829c..0000000000 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java +++ /dev/null @@ -1,558 +0,0 @@ -package cn.iocoder.yudao.module.infra.service.codegen; - -import cn.hutool.core.collection.ListUtil; -import cn.hutool.core.map.MapUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO; -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO; -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO; -import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; -import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; -import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper; -import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper; -import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; -import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum; -import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; -import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties; -import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder; -import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine; -import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import com.baomidou.mybatisplus.generator.config.po.TableField; -import com.baomidou.mybatisplus.generator.config.po.TableInfo; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.Import; - -import javax.annotation.Resource; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * {@link CodegenServiceImpl} 的单元测试类 - * - * @author 芋道源码 - */ -@Import(CodegenServiceImpl.class) -public class CodegenServiceImplTest extends BaseDbUnitTest { - - @Resource - private CodegenServiceImpl codegenService; - - @Resource - private CodegenTableMapper codegenTableMapper; - @Resource - private CodegenColumnMapper codegenColumnMapper; - - @MockBean - private DatabaseTableService databaseTableService; - - @MockBean - private AdminUserApi userApi; - - @MockBean - private CodegenBuilder codegenBuilder; - @MockBean - private CodegenEngine codegenEngine; - - @MockBean - private CodegenProperties codegenProperties; - - @Test - public void testCreateCodegenList() { - // 准备参数 - Long userId = randomLongId(); - CodegenCreateListReqVO reqVO = randomPojo(CodegenCreateListReqVO.class, - o -> o.setDataSourceConfigId(1L).setTableNames(Collections.singletonList("t_yunai"))); - // mock 方法(TableInfo) - TableInfo tableInfo = mock(TableInfo.class); - when(databaseTableService.getTable(eq(1L), eq("t_yunai"))) - .thenReturn(tableInfo); - when(tableInfo.getComment()).thenReturn("芋艿"); - // mock 方法(TableInfo fields) - TableField field01 = mock(TableField.class); - when(field01.getComment()).thenReturn("主键"); - TableField field02 = mock(TableField.class); - when(field02.getComment()).thenReturn("名字"); - List fields = Arrays.asList(field01, field02); - when(tableInfo.getFields()).thenReturn(fields); - // mock 方法(CodegenTableDO) - CodegenTableDO table = randomPojo(CodegenTableDO.class); - when(codegenBuilder.buildTable(same(tableInfo))).thenReturn(table); - // mock 方法(AdminUserRespDTO) - AdminUserRespDTO user = randomPojo(AdminUserRespDTO.class, o -> o.setNickname("芋头")); - when(userApi.getUser(eq(userId))).thenReturn(user); - // mock 方法(CodegenColumnDO) - List columns = randomPojoList(CodegenColumnDO.class); - when(codegenBuilder.buildColumns(eq(table.getId()), same(fields))) - .thenReturn(columns); - // mock 方法(CodegenProperties) - when(codegenProperties.getFrontType()).thenReturn(CodegenFrontTypeEnum.VUE3.getType()); - - // 调用 - List result = codegenService.createCodegenList(userId, reqVO); - // 断言 - assertEquals(1, result.size()); - // 断言(CodegenTableDO) - CodegenTableDO dbTable = codegenTableMapper.selectList().get(0); - assertPojoEquals(table, dbTable); - assertEquals(1L, dbTable.getDataSourceConfigId()); - assertEquals(CodegenSceneEnum.ADMIN.getScene(), dbTable.getScene()); - assertEquals(CodegenFrontTypeEnum.VUE3.getType(), dbTable.getFrontType()); - assertEquals("芋头", dbTable.getAuthor()); - // 断言(CodegenColumnDO) - List dbColumns = codegenColumnMapper.selectList(); - assertEquals(columns.size(), dbColumns.size()); - assertTrue(dbColumns.get(0).getPrimaryKey()); - for (int i = 0; i < dbColumns.size(); i++) { - assertPojoEquals(columns.get(i), dbColumns.get(i)); - } - } - - @Test - public void testValidateTableInfo() { - // 情况一 - assertServiceException(() -> codegenService.validateTableInfo(null), - CODEGEN_IMPORT_TABLE_NULL); - // 情况二 - TableInfo tableInfo = mock(TableInfo.class); - assertServiceException(() -> codegenService.validateTableInfo(tableInfo), - CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL); - // 情况三 - when(tableInfo.getComment()).thenReturn("芋艿"); - assertServiceException(() -> codegenService.validateTableInfo(tableInfo), - CODEGEN_IMPORT_COLUMNS_NULL); - // 情况四 - TableField field = mock(TableField.class); - when(field.getName()).thenReturn("name"); - when(tableInfo.getFields()).thenReturn(Collections.singletonList(field)); - assertServiceException(() -> codegenService.validateTableInfo(tableInfo), - CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL, field.getName()); - } - - @Test - public void testUpdateCodegen_notExists() { - // 准备参数 - CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class); - // mock 方法 - - // 调用,并断言 - assertServiceException(() -> codegenService.updateCodegen(updateReqVO), - CODEGEN_TABLE_NOT_EXISTS); - } - - @Test - public void testUpdateCodegen_sub_masterNotExists() { - // mock 数据 - CodegenTableDO table = randomPojo(CodegenTableDO.class, - o -> o.setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) - .setScene(CodegenSceneEnum.ADMIN.getScene())); - codegenTableMapper.insert(table); - // 准备参数 - CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class, - o -> o.getTable().setId(table.getId()) - .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())); - - // 调用,并断言 - assertServiceException(() -> codegenService.updateCodegen(updateReqVO), - CODEGEN_MASTER_TABLE_NOT_EXISTS, updateReqVO.getTable().getMasterTableId()); - } - - @Test - public void testUpdateCodegen_sub_columnNotExists() { - // mock 数据 - CodegenTableDO subTable = randomPojo(CodegenTableDO.class, - o -> o.setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) - .setScene(CodegenSceneEnum.ADMIN.getScene())); - codegenTableMapper.insert(subTable); - // mock 数据(master) - CodegenTableDO masterTable = randomPojo(CodegenTableDO.class, - o -> o.setTemplateType(CodegenTemplateTypeEnum.MASTER_ERP.getType()) - .setScene(CodegenSceneEnum.ADMIN.getScene())); - codegenTableMapper.insert(masterTable); - // 准备参数 - CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class, - o -> o.getTable().setId(subTable.getId()) - .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) - .setMasterTableId(masterTable.getId())); - - // 调用,并断言 - assertServiceException(() -> codegenService.updateCodegen(updateReqVO), - CODEGEN_SUB_COLUMN_NOT_EXISTS, updateReqVO.getTable().getSubJoinColumnId()); - } - - @Test - public void testUpdateCodegen_success() { - // mock 数据 - CodegenTableDO table = randomPojo(CodegenTableDO.class, - o -> o.setTemplateType(CodegenTemplateTypeEnum.ONE.getType()) - .setScene(CodegenSceneEnum.ADMIN.getScene())); - codegenTableMapper.insert(table); - CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); - codegenColumnMapper.insert(column01); - CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); - codegenColumnMapper.insert(column02); - // 准备参数 - CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class, - o -> o.getTable().setId(table.getId()) - .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()) - .setScene(CodegenSceneEnum.ADMIN.getScene())); - CodegenColumnSaveReqVO columnVO01 = randomPojo(CodegenColumnSaveReqVO.class, - o -> o.setId(column01.getId()).setTableId(table.getId())); - CodegenColumnSaveReqVO columnVO02 = randomPojo(CodegenColumnSaveReqVO.class, - o -> o.setId(column02.getId()).setTableId(table.getId())); - updateReqVO.setColumns(Arrays.asList(columnVO01, columnVO02)); - - // 调用 - codegenService.updateCodegen(updateReqVO); - // 断言 - CodegenTableDO dbTable = codegenTableMapper.selectById(table.getId()); - assertPojoEquals(updateReqVO.getTable(), dbTable); - List dbColumns = codegenColumnMapper.selectList(); - assertEquals(2, dbColumns.size()); - assertPojoEquals(columnVO01, dbColumns.get(0)); - assertPojoEquals(columnVO02, dbColumns.get(1)); - } - - @Test - @Disabled // TODO @芋艿:这个单测会随机性失败,需要定位下; - public void testSyncCodegenFromDB() { - // mock 数据(CodegenTableDO) - CodegenTableDO table = randomPojo(CodegenTableDO.class, o -> o.setTableName("t_yunai") - .setDataSourceConfigId(1L).setScene(CodegenSceneEnum.ADMIN.getScene())); - codegenTableMapper.insert(table); - CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()) - .setColumnName("id")); - codegenColumnMapper.insert(column01); - CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()) - .setColumnName("name")); - codegenColumnMapper.insert(column02); - // 准备参数 - Long tableId = table.getId(); - // mock 方法(TableInfo) - TableInfo tableInfo = mock(TableInfo.class); - when(databaseTableService.getTable(eq(1L), eq("t_yunai"))) - .thenReturn(tableInfo); - when(tableInfo.getComment()).thenReturn("芋艿"); - // mock 方法(TableInfo fields) - TableField field01 = mock(TableField.class); - when(field01.getComment()).thenReturn("主键"); - TableField field03 = mock(TableField.class); - when(field03.getComment()).thenReturn("分类"); - List fields = Arrays.asList(field01, field03); - when(tableInfo.getFields()).thenReturn(fields); - when(databaseTableService.getTable(eq(1L), eq("t_yunai"))) - .thenReturn(tableInfo); - // mock 方法(CodegenTableDO) - List newColumns = randomPojoList(CodegenColumnDO.class); - when(codegenBuilder.buildColumns(eq(table.getId()), argThat(tableFields -> { - assertEquals(2, tableFields.size()); - assertSame(tableInfo.getFields(), tableFields); - return true; - }))).thenReturn(newColumns); - - // 调用 - codegenService.syncCodegenFromDB(tableId); - // 断言 - List dbColumns = codegenColumnMapper.selectList(); - assertEquals(newColumns.size(), dbColumns.size()); - assertPojoEquals(newColumns.get(0), dbColumns.get(0)); - assertPojoEquals(newColumns.get(1), dbColumns.get(1)); - } - - @Test - public void testDeleteCodegen_notExists() { - assertServiceException(() -> codegenService.deleteCodegen(randomLongId()), - CODEGEN_TABLE_NOT_EXISTS); - } - - @Test - public void testDeleteCodegen_success() { - // mock 数据 - CodegenTableDO table = randomPojo(CodegenTableDO.class, - o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())); - codegenTableMapper.insert(table); - CodegenColumnDO column = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); - codegenColumnMapper.insert(column); - // 准备参数 - Long tableId = table.getId(); - - // 调用 - codegenService.deleteCodegen(tableId); - // 断言 - assertNull(codegenTableMapper.selectById(tableId)); - assertEquals(0, codegenColumnMapper.selectList().size()); - } - - @Test - public void testGetCodegenTableList() { - // mock 数据 - CodegenTableDO table01 = randomPojo(CodegenTableDO.class, - o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())); - codegenTableMapper.insert(table01); - CodegenTableDO table02 = randomPojo(CodegenTableDO.class, - o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())); - codegenTableMapper.insert(table02); - // 准备参数 - Long dataSourceConfigId = table01.getDataSourceConfigId(); - - // 调用 - List result = codegenService.getCodegenTableList(dataSourceConfigId); - // 断言 - assertEquals(1, result.size()); - assertPojoEquals(table01, result.get(0)); - } - - @Test - public void testGetCodegenTablePage() { - // mock 数据 - CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, o -> { - o.setTableName("t_yunai"); - o.setTableComment("芋艿"); - o.setClassName("SystemYunai"); - o.setCreateTime(buildTime(2021, 3, 10)); - }).setScene(CodegenSceneEnum.ADMIN.getScene()); - codegenTableMapper.insert(tableDO); - // 测试 tableName 不匹配 - codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setTableName(randomString()))); - // 测试 tableComment 不匹配 - codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setTableComment(randomString()))); - // 测试 className 不匹配 - codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setClassName(randomString()))); - // 测试 createTime 不匹配 - codegenTableMapper.insert(cloneIgnoreId(tableDO, logDO -> logDO.setCreateTime(buildTime(2021, 4, 10)))); - // 准备参数 - CodegenTablePageReqVO reqVO = new CodegenTablePageReqVO(); - reqVO.setTableName("yunai"); - reqVO.setTableComment("芋"); - reqVO.setClassName("Yunai"); - reqVO.setCreateTime(buildBetweenTime(2021, 3, 1, 2021, 3, 31)); - - // 调用 - PageResult pageResult = codegenService.getCodegenTablePage(reqVO); - // 断言,只查到了一条符合条件的 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(tableDO, pageResult.getList().get(0)); - } - - @Test - public void testGetCodegenTable() { - // mock 数据 - CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())); - codegenTableMapper.insert(tableDO); - // 准备参数 - Long id = tableDO.getId(); - - // 调用 - CodegenTableDO result = codegenService.getCodegenTable(id); - // 断言 - assertPojoEquals(tableDO, result); - } - - @Test - public void testGetCodegenColumnListByTableId() { - // mock 数据 - CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class); - codegenColumnMapper.insert(column01); - CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class); - codegenColumnMapper.insert(column02); - // 准备参数 - Long tableId = column01.getTableId(); - - // 调用 - List result = codegenService.getCodegenColumnListByTableId(tableId); - // 断言 - assertEquals(1, result.size()); - assertPojoEquals(column01, result.get(0)); - } - - @Test - public void testGenerationCodes_tableNotExists() { - assertServiceException(() -> codegenService.generationCodes(randomLongId()), - CODEGEN_TABLE_NOT_EXISTS); - } - - @Test - public void testGenerationCodes_columnNotExists() { - // mock 数据(CodegenTableDO) - CodegenTableDO table = randomPojo(CodegenTableDO.class, - o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) - .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType())); - codegenTableMapper.insert(table); - // 准备参数 - Long tableId = table.getId(); - - // 调用,并断言 - assertServiceException(() -> codegenService.generationCodes(tableId), - CODEGEN_COLUMN_NOT_EXISTS); - } - - @Test - public void testGenerationCodes_sub_tableNotExists() { - // mock 数据(CodegenTableDO) - CodegenTableDO table = randomPojo(CodegenTableDO.class, - o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) - .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType())); - codegenTableMapper.insert(table); - // mock 数据(CodegenColumnDO) - CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); - codegenColumnMapper.insert(column01); - // 准备参数 - Long tableId = table.getId(); - - // 调用,并断言 - assertServiceException(() -> codegenService.generationCodes(tableId), - CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE); - } - - @Test - public void testGenerationCodes_sub_columnNotExists() { - // mock 数据(CodegenTableDO) - CodegenTableDO table = randomPojo(CodegenTableDO.class, - o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) - .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType())); - codegenTableMapper.insert(table); - // mock 数据(CodegenColumnDO) - CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); - codegenColumnMapper.insert(column01); - // mock 数据(sub CodegenTableDO) - CodegenTableDO subTable = randomPojo(CodegenTableDO.class, - o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) - .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) - .setMasterTableId(table.getId())); - codegenTableMapper.insert(subTable); - // 准备参数 - Long tableId = table.getId(); - - // 调用,并断言 - assertServiceException(() -> codegenService.generationCodes(tableId), - CODEGEN_SUB_COLUMN_NOT_EXISTS, subTable.getId()); - } - - @Test - public void testGenerationCodes_one_success() { - // mock 数据(CodegenTableDO) - CodegenTableDO table = randomPojo(CodegenTableDO.class, - o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) - .setTemplateType(CodegenTemplateTypeEnum.ONE.getType())); - codegenTableMapper.insert(table); - // mock 数据(CodegenColumnDO) - CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); - codegenColumnMapper.insert(column01); - CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); - codegenColumnMapper.insert(column02); - // mock 执行生成 - Map codes = MapUtil.of(randomString(), randomString()); - when(codegenEngine.execute(eq(table), argThat(columns -> { - assertEquals(2, columns.size()); - assertEquals(column01, columns.get(0)); - assertEquals(column02, columns.get(1)); - return true; - }), isNull(), isNull())).thenReturn(codes); - // 准备参数 - Long tableId = table.getId(); - - // 调用 - Map result = codegenService.generationCodes(tableId); - // 断言 - assertSame(codes, result); - } - - @Test - public void testGenerationCodes_master_success() { - // mock 数据(CodegenTableDO) - CodegenTableDO table = randomPojo(CodegenTableDO.class, - o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) - .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType())); - codegenTableMapper.insert(table); - // mock 数据(CodegenColumnDO) - CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); - codegenColumnMapper.insert(column01); - CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())); - codegenColumnMapper.insert(column02); - // mock 数据(sub CodegenTableDO) - CodegenTableDO subTable = randomPojo(CodegenTableDO.class, - o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) - .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) - .setMasterTableId(table.getId()) - .setSubJoinColumnId(1024L)); - codegenTableMapper.insert(subTable); - // mock 数据(sub CodegenColumnDO) - CodegenColumnDO subColumn01 = randomPojo(CodegenColumnDO.class, o -> o.setId(1024L).setTableId(subTable.getId())); - codegenColumnMapper.insert(subColumn01); - // mock 执行生成 - Map codes = MapUtil.of(randomString(), randomString()); - when(codegenEngine.execute(eq(table), argThat(columns -> { - assertEquals(2, columns.size()); - assertEquals(column01, columns.get(0)); - assertEquals(column02, columns.get(1)); - return true; - }), argThat(tables -> { - assertEquals(1, tables.size()); - assertPojoEquals(subTable, tables.get(0)); - return true; - }), argThat(columns -> { - assertEquals(1, columns.size()); - assertPojoEquals(subColumn01, columns.size()); - return true; - }))).thenReturn(codes); - // 准备参数 - Long tableId = table.getId(); - - // 调用 - Map result = codegenService.generationCodes(tableId); - // 断言 - assertSame(codes, result); - } - - @Test - public void testGetDatabaseTableList() { - // 准备参数 - Long dataSourceConfigId = randomLongId(); - String name = randomString(); - String comment = randomString(); - // mock 方法 - TableInfo tableInfo01 = mock(TableInfo.class); - when(tableInfo01.getName()).thenReturn("t_yunai"); - when(tableInfo01.getComment()).thenReturn("芋艿"); - TableInfo tableInfo02 = mock(TableInfo.class); - when(tableInfo02.getName()).thenReturn("t_yunai_02"); - when(tableInfo02.getComment()).thenReturn("芋艿_02"); - when(databaseTableService.getTableList(eq(dataSourceConfigId), eq(name), eq(comment))) - .thenReturn(ListUtil.toList(tableInfo01, tableInfo02)); - // mock 数据 - CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, - o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()) - .setTableName("t_yunai_02") - .setDataSourceConfigId(dataSourceConfigId)); - codegenTableMapper.insert(tableDO); - - // 调用 - List result = codegenService.getDatabaseTableList(dataSourceConfigId, name, comment); - // 断言 - assertEquals(1, result.size()); - assertEquals("t_yunai", result.get(0).getName()); - assertEquals("芋艿", result.get(0).getComment()); - } - -} \ No newline at end of file diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java deleted file mode 100755 index ba0c8b15fd..0000000000 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java +++ /dev/null @@ -1,281 +0,0 @@ -package cn.iocoder.yudao.module.infra.service.file; - -import cn.hutool.core.date.DatePattern; -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.hutool.core.map.MapUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient; -import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientConfig; -import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientFactory; -import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClient; -import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig; -import cn.iocoder.yudao.module.infra.framework.file.core.enums.FileStorageEnum; -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; -import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigSaveReqVO; -import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; -import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; -import lombok.Data; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.Import; - -import javax.annotation.Resource; -import javax.validation.Validator; -import java.io.Serializable; -import java.time.LocalDateTime; -import java.util.Map; - -import static cn.hutool.core.util.RandomUtil.randomEle; -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; -import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_DELETE_FAIL_MASTER; -import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_NOT_EXISTS; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; - -/** - * {@link FileConfigServiceImpl} 的单元测试类 - * - * @author 芋道源码 - */ -@Import(FileConfigServiceImpl.class) -public class FileConfigServiceImplTest extends BaseDbUnitTest { - - @Resource - private FileConfigServiceImpl fileConfigService; - - @Resource - private FileConfigMapper fileConfigMapper; - - @MockBean - private Validator validator; - @MockBean - private FileClientFactory fileClientFactory; - - @Test - public void testCreateFileConfig_success() { - // 准备参数 - Map config = MapUtil.builder().put("basePath", "/yunai") - .put("domain", "https://www.iocoder.cn").build(); - FileConfigSaveReqVO reqVO = randomPojo(FileConfigSaveReqVO.class, - o -> o.setStorage(FileStorageEnum.LOCAL.getStorage()).setConfig(config)) - .setId(null); // 避免 id 被赋值 - - // 调用 - Long fileConfigId = fileConfigService.createFileConfig(reqVO); - // 断言 - assertNotNull(fileConfigId); - // 校验记录的属性是否正确 - FileConfigDO fileConfig = fileConfigMapper.selectById(fileConfigId); - assertPojoEquals(reqVO, fileConfig, "id", "config"); - assertFalse(fileConfig.getMaster()); - assertEquals("/yunai", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); - assertEquals("https://www.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); - // 验证 cache - assertNull(fileConfigService.getClientCache().getIfPresent(fileConfigId)); - } - - @Test - public void testUpdateFileConfig_success() { - // mock 数据 - FileConfigDO dbFileConfig = randomPojo(FileConfigDO.class, o -> o.setStorage(FileStorageEnum.LOCAL.getStorage()) - .setConfig(new LocalFileClientConfig().setBasePath("/yunai").setDomain("https://www.iocoder.cn"))); - fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 - // 准备参数 - FileConfigSaveReqVO reqVO = randomPojo(FileConfigSaveReqVO.class, o -> { - o.setId(dbFileConfig.getId()); // 设置更新的 ID - o.setStorage(FileStorageEnum.LOCAL.getStorage()); - Map config = MapUtil.builder().put("basePath", "/yunai2") - .put("domain", "https://doc.iocoder.cn").build(); - o.setConfig(config); - }); - - // 调用 - fileConfigService.updateFileConfig(reqVO); - // 校验是否更新正确 - FileConfigDO fileConfig = fileConfigMapper.selectById(reqVO.getId()); // 获取最新的 - assertPojoEquals(reqVO, fileConfig, "config"); - assertEquals("/yunai2", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); - assertEquals("https://doc.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); - // 验证 cache - assertNull(fileConfigService.getClientCache().getIfPresent(fileConfig.getId())); - } - - @Test - public void testUpdateFileConfig_notExists() { - // 准备参数 - FileConfigSaveReqVO reqVO = randomPojo(FileConfigSaveReqVO.class); - - // 调用, 并断言异常 - assertServiceException(() -> fileConfigService.updateFileConfig(reqVO), FILE_CONFIG_NOT_EXISTS); - } - - @Test - public void testUpdateFileConfigMaster_success() { - // mock 数据 - FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(false); - fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 - FileConfigDO masterFileConfig = randomFileConfigDO().setMaster(true); - fileConfigMapper.insert(masterFileConfig);// @Sql: 先插入出一条存在的数据 - - // 调用 - fileConfigService.updateFileConfigMaster(dbFileConfig.getId()); - // 断言数据 - assertTrue(fileConfigMapper.selectById(dbFileConfig.getId()).getMaster()); - assertFalse(fileConfigMapper.selectById(masterFileConfig.getId()).getMaster()); - // 验证 cache - assertNull(fileConfigService.getClientCache().getIfPresent(0L)); - } - - @Test - public void testUpdateFileConfigMaster_notExists() { - // 调用, 并断言异常 - assertServiceException(() -> fileConfigService.updateFileConfigMaster(randomLongId()), FILE_CONFIG_NOT_EXISTS); - } - - @Test - public void testDeleteFileConfig_success() { - // mock 数据 - FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(false); - fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbFileConfig.getId(); - - // 调用 - fileConfigService.deleteFileConfig(id); - // 校验数据不存在了 - assertNull(fileConfigMapper.selectById(id)); - // 验证 cache - assertNull(fileConfigService.getClientCache().getIfPresent(id)); - } - - @Test - public void testDeleteFileConfig_notExists() { - // 准备参数 - Long id = randomLongId(); - - // 调用, 并断言异常 - assertServiceException(() -> fileConfigService.deleteFileConfig(id), FILE_CONFIG_NOT_EXISTS); - } - - @Test - public void testDeleteFileConfig_master() { - // mock 数据 - FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(true); - fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbFileConfig.getId(); - - // 调用, 并断言异常 - assertServiceException(() -> fileConfigService.deleteFileConfig(id), FILE_CONFIG_DELETE_FAIL_MASTER); - } - - @Test - public void testGetFileConfigPage() { - // mock 数据 - FileConfigDO dbFileConfig = randomFileConfigDO().setName("芋道源码") - .setStorage(FileStorageEnum.LOCAL.getStorage()); - dbFileConfig.setCreateTime(LocalDateTimeUtil.parse("2020-01-23", DatePattern.NORM_DATE_PATTERN));// 等会查询到 - fileConfigMapper.insert(dbFileConfig); - // 测试 name 不匹配 - fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setName("源码"))); - // 测试 storage 不匹配 - fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setStorage(FileStorageEnum.DB.getStorage()))); - // 测试 createTime 不匹配 - fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setCreateTime(LocalDateTimeUtil.parse("2020-11-23", DatePattern.NORM_DATE_PATTERN)))); - // 准备参数 - FileConfigPageReqVO reqVO = new FileConfigPageReqVO(); - reqVO.setName("芋道"); - reqVO.setStorage(FileStorageEnum.LOCAL.getStorage()); - reqVO.setCreateTime((new LocalDateTime[]{buildTime(2020, 1, 1), - buildTime(2020, 1, 24)})); - - // 调用 - PageResult pageResult = fileConfigService.getFileConfigPage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbFileConfig, pageResult.getList().get(0)); - } - - @Test - public void testFileConfig() throws Exception { - // mock 数据 - FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(false); - fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbFileConfig.getId(); - // mock 获得 Client - FileClient fileClient = mock(FileClient.class); - when(fileClientFactory.getFileClient(eq(id))).thenReturn(fileClient); - when(fileClient.upload(any(), any(), any())).thenReturn("https://www.iocoder.cn"); - - // 调用,并断言 - assertEquals("https://www.iocoder.cn", fileConfigService.testFileConfig(id)); - } - - @Test - public void testGetFileConfig() { - // mock 数据 - FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(false); - fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbFileConfig.getId(); - - // 调用,并断言 - assertPojoEquals(dbFileConfig, fileConfigService.getFileConfig(id)); - } - - @Test - public void testGetFileClient() { - // mock 数据 - FileConfigDO fileConfig = randomFileConfigDO().setMaster(false); - fileConfigMapper.insert(fileConfig); - // 准备参数 - Long id = fileConfig.getId(); - // mock 获得 Client - FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig()); - when(fileClientFactory.getFileClient(eq(id))).thenReturn(fileClient); - - // 调用,并断言 - assertSame(fileClient, fileConfigService.getFileClient(id)); - // 断言缓存 - verify(fileClientFactory).createOrUpdateFileClient(eq(id), eq(fileConfig.getStorage()), - eq(fileConfig.getConfig())); - } - - @Test - public void testGetMasterFileClient() { - // mock 数据 - FileConfigDO fileConfig = randomFileConfigDO().setMaster(true); - fileConfigMapper.insert(fileConfig); - // 准备参数 - Long id = fileConfig.getId(); - // mock 获得 Client - FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig()); - when(fileClientFactory.getFileClient(eq(fileConfig.getId()))).thenReturn(fileClient); - - // 调用,并断言 - assertSame(fileClient, fileConfigService.getMasterFileClient()); - // 断言缓存 - verify(fileClientFactory).createOrUpdateFileClient(eq(fileConfig.getId()), eq(fileConfig.getStorage()), - eq(fileConfig.getConfig())); - } - - private FileConfigDO randomFileConfigDO() { - return randomPojo(FileConfigDO.class).setStorage(randomEle(FileStorageEnum.values()).getStorage()) - .setConfig(new EmptyFileClientConfig()); - } - - @Data - public static class EmptyFileClientConfig implements FileClientConfig, Serializable { - - } - -} diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java deleted file mode 100644 index dff95c96cb..0000000000 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java +++ /dev/null @@ -1,143 +0,0 @@ -package cn.iocoder.yudao.module.infra.service.file; - -import cn.hutool.core.io.resource.ResourceUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient; -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -import cn.iocoder.yudao.framework.test.core.util.AssertUtils; -import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO; -import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; -import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.Import; - -import javax.annotation.Resource; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_NOT_EXISTS; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.*; - -@Import({FileServiceImpl.class}) -public class FileServiceImplTest extends BaseDbUnitTest { - - @Resource - private FileService fileService; - - @Resource - private FileMapper fileMapper; - - @MockBean - private FileConfigService fileConfigService; - - @Test - public void testGetFilePage() { - // mock 数据 - FileDO dbFile = randomPojo(FileDO.class, o -> { // 等会查询到 - o.setPath("yunai"); - o.setType("image/jpg"); - o.setCreateTime(buildTime(2021, 1, 15)); - }); - fileMapper.insert(dbFile); - // 测试 path 不匹配 - fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> o.setPath("tudou"))); - // 测试 type 不匹配 - fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> { - o.setType("image/png"); - })); - // 测试 createTime 不匹配 - fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> { - o.setCreateTime(buildTime(2020, 1, 15)); - })); - // 准备参数 - FilePageReqVO reqVO = new FilePageReqVO(); - reqVO.setPath("yunai"); - reqVO.setType("jp"); - reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 1, 10), buildTime(2021, 1, 20)})); - - // 调用 - PageResult pageResult = fileService.getFilePage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - AssertUtils.assertPojoEquals(dbFile, pageResult.getList().get(0)); - } - - @Test - public void testCreateFile_success() throws Exception { - // 准备参数 - String path = randomString(); - byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); - // mock Master 文件客户端 - FileClient client = mock(FileClient.class); - when(fileConfigService.getMasterFileClient()).thenReturn(client); - String url = randomString(); - when(client.upload(same(content), same(path), eq("image/jpeg"))).thenReturn(url); - when(client.getId()).thenReturn(10L); - String name = "单测文件名"; - // 调用 - String result = fileService.createFile(name, path, content); - // 断言 - assertEquals(result, url); - // 校验数据 - FileDO file = fileMapper.selectOne(FileDO::getPath, path); - assertEquals(10L, file.getConfigId()); - assertEquals(path, file.getPath()); - assertEquals(url, file.getUrl()); - assertEquals("image/jpeg", file.getType()); - assertEquals(content.length, file.getSize()); - } - - @Test - public void testDeleteFile_success() throws Exception { - // mock 数据 - FileDO dbFile = randomPojo(FileDO.class, o -> o.setConfigId(10L).setPath("tudou.jpg")); - fileMapper.insert(dbFile);// @Sql: 先插入出一条存在的数据 - // mock Master 文件客户端 - FileClient client = mock(FileClient.class); - when(fileConfigService.getFileClient(eq(10L))).thenReturn(client); - // 准备参数 - Long id = dbFile.getId(); - - // 调用 - fileService.deleteFile(id); - // 校验数据不存在了 - assertNull(fileMapper.selectById(id)); - // 校验调用 - verify(client).delete(eq("tudou.jpg")); - } - - @Test - public void testDeleteFile_notExists() { - // 准备参数 - Long id = randomLongId(); - - // 调用, 并断言异常 - assertServiceException(() -> fileService.deleteFile(id), FILE_NOT_EXISTS); - } - - @Test - public void testGetFileContent() throws Exception { - // 准备参数 - Long configId = 10L; - String path = "tudou.jpg"; - // mock 方法 - FileClient client = mock(FileClient.class); - when(fileConfigService.getFileClient(eq(10L))).thenReturn(client); - byte[] content = new byte[]{}; - when(client.getContent(eq("tudou.jpg"))).thenReturn(content); - - // 调用 - byte[] result = fileService.getFileContent(configId, path); - // 断言 - assertSame(result, content); - } - -} diff --git a/yudao-module-mall/yudao-module-product-biz/pom.xml b/yudao-module-mall/yudao-module-product-biz/pom.xml deleted file mode 100644 index 7cf3364328..0000000000 --- a/yudao-module-mall/yudao-module-product-biz/pom.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - cn.iocoder.boot - yudao-module-mall - ${revision} - - 4.0.0 - yudao-module-product-biz - jar - - ${project.artifactId} - - product 模块,主要实现商品相关功能 - 例如:品牌、商品分类、spu、sku等功能。 - - - - - cn.iocoder.boot - yudao-module-product-api - ${revision} - - - cn.iocoder.boot - yudao-module-member-api - ${revision} - - - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-operatelog - - - - - cn.iocoder.boot - yudao-spring-boot-starter-web - - - cn.iocoder.boot - yudao-spring-boot-starter-security - - - - - cn.iocoder.boot - yudao-spring-boot-starter-mybatis - - - - - cn.iocoder.boot - yudao-spring-boot-starter-test - - - - - cn.iocoder.boot - yudao-spring-boot-starter-excel - - - - diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java deleted file mode 100644 index 47421d3153..0000000000 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java +++ /dev/null @@ -1,60 +0,0 @@ -package cn.iocoder.yudao.module.product.dal.mysql.comment; - -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentPageReqVO; -import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO; -import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; -import org.apache.ibatis.annotations.Mapper; - -@Mapper -public interface ProductCommentMapper extends BaseMapperX { - - default PageResult selectPage(ProductCommentPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .likeIfPresent(ProductCommentDO::getUserNickname, reqVO.getUserNickname()) - .eqIfPresent(ProductCommentDO::getOrderId, reqVO.getOrderId()) - .eqIfPresent(ProductCommentDO::getSpuId, reqVO.getSpuId()) - .eqIfPresent(ProductCommentDO::getScores, reqVO.getScores()) - .eqIfPresent(ProductCommentDO::getReplyStatus, reqVO.getReplyStatus()) - .betweenIfPresent(ProductCommentDO::getCreateTime, reqVO.getCreateTime()) - .likeIfPresent(ProductCommentDO::getSpuName, reqVO.getSpuName()) - .orderByDesc(ProductCommentDO::getId)); - } - - static void appendTabQuery(LambdaQueryWrapperX queryWrapper, Integer type) { - // 构建好评查询语句:好评计算 总评 >= 4 - if (ObjectUtil.equal(type, AppCommentPageReqVO.GOOD_COMMENT)) { - queryWrapper.ge(ProductCommentDO::getScores, 4); - } - // 构建中评查询语句:中评计算 总评 >= 3 且 总评 < 4 - if (ObjectUtil.equal(type, AppCommentPageReqVO.MEDIOCRE_COMMENT)) { - queryWrapper.ge(ProductCommentDO::getScores, 3); - queryWrapper.lt(ProductCommentDO::getScores, 4); - } - // 构建差评查询语句:差评计算 总评 < 3 - if (ObjectUtil.equal(type, AppCommentPageReqVO.NEGATIVE_COMMENT)) { - queryWrapper.lt(ProductCommentDO::getScores, 3); - } - } - - default PageResult selectPage(AppCommentPageReqVO reqVO, Boolean visible) { - LambdaQueryWrapperX queryWrapper = new LambdaQueryWrapperX() - .eqIfPresent(ProductCommentDO::getSpuId, reqVO.getSpuId()) - .eqIfPresent(ProductCommentDO::getVisible, visible); - // 构建评价查询语句 - appendTabQuery(queryWrapper, reqVO.getType()); - // 按评价时间排序最新的显示在前面 - queryWrapper.orderByDesc(ProductCommentDO::getCreateTime); - return selectPage(reqVO, queryWrapper); - } - - default ProductCommentDO selectByUserIdAndOrderItemId(Long userId, Long orderItemId) { - return selectOne(new LambdaQueryWrapperX() - .eq(ProductCommentDO::getUserId, userId) - .eq(ProductCommentDO::getOrderItemId, orderItemId)); - } - -} diff --git a/yudao-module-mall/yudao-module-promotion-biz/pom.xml b/yudao-module-mall/yudao-module-promotion-biz/pom.xml deleted file mode 100644 index f3d1340ba9..0000000000 --- a/yudao-module-mall/yudao-module-promotion-biz/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - cn.iocoder.boot - yudao-module-mall - ${revision} - - 4.0.0 - jar - yudao-module-promotion-biz - - ${project.artifactId} - - - promotion 模块,主要实现营销相关功能 - 例如:营销活动、banner 广告、优惠券、优惠码等功能。 - - - - - cn.iocoder.boot - yudao-module-promotion-api - ${revision} - - - cn.iocoder.boot - yudao-module-product-api - ${revision} - - - cn.iocoder.boot - yudao-module-trade-api - ${revision} - - - cn.iocoder.boot - yudao-module-member-api - ${revision} - - - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-operatelog - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-tenant - - - - - cn.iocoder.boot - yudao-spring-boot-starter-web - - - cn.iocoder.boot - yudao-spring-boot-starter-security - - - - - cn.iocoder.boot - yudao-spring-boot-starter-mybatis - - - - - cn.iocoder.boot - yudao-spring-boot-starter-test - - - - - cn.iocoder.boot - yudao-spring-boot-starter-excel - - - - diff --git a/yudao-module-mall/yudao-module-statistics-biz/pom.xml b/yudao-module-mall/yudao-module-statistics-biz/pom.xml deleted file mode 100644 index 77c7b1bff9..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/pom.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - cn.iocoder.boot - yudao-module-mall - ${revision} - - 4.0.0 - yudao-module-statistics-biz - jar - - ${project.artifactId} - - statistics 模块,主要实现统计相关功能 - 例如:统计商品、会员、交易等功能。 - - - - - cn.iocoder.boot - yudao-module-statistics-api - ${revision} - - - cn.iocoder.boot - yudao-module-promotion-api - ${revision} - - - cn.iocoder.boot - yudao-module-product-api - ${revision} - - - cn.iocoder.boot - yudao-module-trade-api - ${revision} - - - cn.iocoder.boot - yudao-module-member-api - ${revision} - - - cn.iocoder.boot - yudao-module-pay-api - ${revision} - - - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-operatelog - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-tenant - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-ip - - - - - cn.iocoder.boot - yudao-spring-boot-starter-web - - - cn.iocoder.boot - yudao-spring-boot-starter-security - - - - - cn.iocoder.boot - yudao-spring-boot-starter-mybatis - - - - - cn.iocoder.boot - yudao-spring-boot-starter-test - - - - - cn.iocoder.boot - yudao-spring-boot-starter-excel - - - - diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/MemberStatisticsController.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/MemberStatisticsController.java deleted file mode 100644 index 9b0f7158b1..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/controller/admin/member/MemberStatisticsController.java +++ /dev/null @@ -1,114 +0,0 @@ -package cn.iocoder.yudao.module.statistics.controller.admin.member; - -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.NumberUtil; -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; -import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.*; -import cn.iocoder.yudao.module.statistics.convert.member.MemberStatisticsConvert; -import cn.iocoder.yudao.module.statistics.service.infra.ApiAccessLogStatisticsService; -import cn.iocoder.yudao.module.statistics.service.member.MemberStatisticsService; -import cn.iocoder.yudao.module.statistics.service.trade.TradeOrderStatisticsService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.extern.slf4j.Slf4j; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.util.List; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - 会员统计") -@RestController -@RequestMapping("/statistics/member") -@Validated -@Slf4j -public class MemberStatisticsController { - - @Resource - private MemberStatisticsService memberStatisticsService; - @Resource - private TradeOrderStatisticsService tradeOrderStatisticsService; - @Resource - private ApiAccessLogStatisticsService apiAccessLogStatisticsService; - - @GetMapping("/summary") - @Operation(summary = "获得会员统计(实时统计)") - @PreAuthorize("@ss.hasPermission('statistics:member:query')") - public CommonResult getMemberSummary() { - return success(memberStatisticsService.getMemberSummary()); - } - - @GetMapping("/analyse") - @Operation(summary = "获得会员分析数据") - @PreAuthorize("@ss.hasPermission('statistics:member:query')") - public CommonResult getMemberAnalyse(MemberAnalyseReqVO reqVO) { - // 1. 查询数据 - LocalDateTime beginTime = ArrayUtil.get(reqVO.getTimes(), 0); - LocalDateTime endTime = ArrayUtil.get(reqVO.getTimes(), 1); - // 1.1 查询分析对照数据 - DataComparisonRespVO comparisonData = memberStatisticsService.getMemberAnalyseComparisonData(beginTime, endTime); - // TODO @疯狂:这个可能有点特殊,要按照 create_time 来查询;不然它的漏斗就不统一;因为是访问数量 > 今日下单人 > 今日支付人;是一个统一的维度; - // 1.2 查询成交用户数量 - Integer payUserCount = tradeOrderStatisticsService.getPayUserCount(beginTime, endTime); - // 1.3 计算客单价 - int atv = 0; - if (payUserCount != null && payUserCount > 0) { - // TODO @疯狂:类似上面的 payUserCount - Integer payPrice = tradeOrderStatisticsService.getOrderPayPrice(beginTime, endTime); - atv = NumberUtil.div(payPrice, payUserCount).intValue(); - } - // 1.4 查询访客数量 - Integer visitUserCount = apiAccessLogStatisticsService.getIpCount(UserTypeEnum.MEMBER.getValue(), beginTime, endTime); - // 1.5 下单用户数量 - Integer orderUserCount = tradeOrderStatisticsService.getOrderUserCount(beginTime, endTime); - - // 2. 拼接返回 - return success(MemberStatisticsConvert.INSTANCE.convert(visitUserCount, orderUserCount, payUserCount, atv, comparisonData)); - } - - @GetMapping("/area-statistics-list") - @Operation(summary = "按照省份,获得会员统计列表") - @PreAuthorize("@ss.hasPermission('statistics:member:query')") - public CommonResult> getMemberAreaStatisticsList() { - return success(memberStatisticsService.getMemberAreaStatisticsList()); - } - - @GetMapping("/sex-statistics-list") - @Operation(summary = "按照性别,获得会员统计列表") - @PreAuthorize("@ss.hasPermission('statistics:member:query')") - public CommonResult> getMemberSexStatisticsList() { - return success(memberStatisticsService.getMemberSexStatisticsList()); - } - - @GetMapping("/terminal-statistics-list") - @Operation(summary = "按照终端,获得会员统计列表") - @PreAuthorize("@ss.hasPermission('statistics:member:query')") - public CommonResult> getMemberTerminalStatisticsList() { - return success(memberStatisticsService.getMemberTerminalStatisticsList()); - } - - // TODO @疯狂:要注意 date 的排序; - @GetMapping("/user-count-comparison") - @Operation(summary = "获得用户数量对照") - @PreAuthorize("@ss.hasPermission('statistics:member:query')") - public CommonResult> getUserCountComparison() { - return success(memberStatisticsService.getUserCountComparison()); - } - - @GetMapping("/register-count-list") - @Operation(summary = "获得会员注册数量列表") - @PreAuthorize("@ss.hasPermission('statistics:member:query')") - public CommonResult> getMemberRegisterCountList(MemberAnalyseReqVO reqVO) { - return success(memberStatisticsService.getMemberRegisterCountList( - ArrayUtil.get(reqVO.getTimes(), 0), ArrayUtil.get(reqVO.getTimes(), 1))); - } - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/infra/ApiAccessLogStatisticsMapper.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/infra/ApiAccessLogStatisticsMapper.java deleted file mode 100644 index 5f76b58fd1..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/infra/ApiAccessLogStatisticsMapper.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.iocoder.yudao.module.statistics.dal.mysql.infra; - -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.time.LocalDateTime; - -// TODO @芋艿:api 访问日志,现在会清理,可能要单独有个偏业务的访问表; -/** - * API 访问日志的统计 Mapper - * - * @author owen - */ -@Mapper -@SuppressWarnings("rawtypes") -public interface ApiAccessLogStatisticsMapper extends BaseMapperX { - - Integer selectIpCountByUserTypeAndCreateTimeBetween(@Param("userType") Integer userType, - @Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - Integer selectUserCountByUserTypeAndCreateTimeBetween(@Param("userType") Integer userType, - @Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/member/MemberStatisticsMapper.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/member/MemberStatisticsMapper.java deleted file mode 100644 index 595e93d9e8..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/member/MemberStatisticsMapper.java +++ /dev/null @@ -1,42 +0,0 @@ -package cn.iocoder.yudao.module.statistics.dal.mysql.member; - -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.MemberRegisterCountRespVO; -import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.MemberSexStatisticsRespVO; -import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.MemberTerminalStatisticsRespVO; -import cn.iocoder.yudao.module.statistics.service.member.bo.MemberAreaStatisticsRespBO; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.time.LocalDateTime; -import java.util.List; - -/** - * 会员信息的统计 Mapper - * - * @author owen - */ -@Mapper -@SuppressWarnings("rawtypes") -public interface MemberStatisticsMapper extends BaseMapperX { - - List selectSummaryListByAreaId(); - - List selectSummaryListBySex(); - - List selectSummaryListByRegisterTerminal(); - - Integer selectUserCount(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - /** - * 获得用户的每天注册数量列表 - * - * @param beginTime 开始时间 - * @param endTime 结束时间 - * @return 每天注册数量列表 - */ - List selectListByCreateTimeBetween(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/pay/PayWalletStatisticsMapper.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/pay/PayWalletStatisticsMapper.java deleted file mode 100644 index b9b38fbbec..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/pay/PayWalletStatisticsMapper.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.iocoder.yudao.module.statistics.dal.mysql.pay; - -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.statistics.service.pay.bo.RechargeSummaryRespBO; -import cn.iocoder.yudao.module.statistics.service.trade.bo.WalletSummaryRespBO; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.time.LocalDateTime; - -/** - * 支付钱包的统计 Mapper - * - * @author owen - */ -@Mapper -@SuppressWarnings("rawtypes") -public interface PayWalletStatisticsMapper extends BaseMapperX { - - WalletSummaryRespBO selectRechargeSummaryByPayTimeBetween(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime, - @Param("payStatus") Boolean payStatus); - - WalletSummaryRespBO selectRechargeSummaryByRefundTimeBetween(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime, - @Param("refundStatus") Integer refundStatus); - - Integer selectPriceSummaryByBizTypeAndCreateTimeBetween(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime, - @Param("bizType") Integer bizType); - - RechargeSummaryRespBO selectRechargeSummaryGroupByWalletId(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime, - @Param("payStatus") Boolean payStatus); - - Integer selectRechargePriceSummary(@Param("payStatus") Integer payStatus); - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/AfterSaleStatisticsMapper.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/AfterSaleStatisticsMapper.java deleted file mode 100644 index 7de0cb07b2..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/AfterSaleStatisticsMapper.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.statistics.dal.mysql.trade; - -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.statistics.dal.dataobject.trade.TradeStatisticsDO; -import cn.iocoder.yudao.module.statistics.service.trade.bo.AfterSaleSummaryRespBO; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.time.LocalDateTime; - -/** - * 售后订单的统计 Mapper - * - * @author owen - */ -@Mapper -public interface AfterSaleStatisticsMapper extends BaseMapperX { - - AfterSaleSummaryRespBO selectSummaryByRefundTimeBetween(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - Long selectCountByStatus(@Param("status") Integer status); - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/BrokerageStatisticsMapper.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/BrokerageStatisticsMapper.java deleted file mode 100644 index 94ad068121..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/BrokerageStatisticsMapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.yudao.module.statistics.dal.mysql.trade; - -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.statistics.dal.dataobject.trade.TradeStatisticsDO; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.time.LocalDateTime; - -/** - * 订单分销的统计 Mapper - * - * @author owen - */ -@Mapper -public interface BrokerageStatisticsMapper extends BaseMapperX { - - Integer selectSummaryPriceByStatusAndUnfreezeTimeBetween(@Param("bizType") Integer bizType, - @Param("status") Integer status, - @Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - Long selectWithdrawCountByStatus(@Param("status") Integer status); - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeOrderStatisticsMapper.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeOrderStatisticsMapper.java deleted file mode 100644 index 1d7ffb6441..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeOrderStatisticsMapper.java +++ /dev/null @@ -1,65 +0,0 @@ -package cn.iocoder.yudao.module.statistics.dal.mysql.trade; - -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeOrderSummaryRespVO; -import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeOrderTrendRespVO; -import cn.iocoder.yudao.module.statistics.dal.dataobject.trade.TradeStatisticsDO; -import cn.iocoder.yudao.module.statistics.service.member.bo.MemberAreaStatisticsRespBO; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.time.LocalDateTime; -import java.util.List; - -/** - * 交易订单的统计 Mapper - * - * @author owen - */ -@Mapper -public interface TradeOrderStatisticsMapper extends BaseMapperX { - - List selectSummaryListByAreaId(); - - Integer selectCountByCreateTimeBetween(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - Integer selectCountByPayTimeBetween(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - Integer selectSummaryPriceByPayTimeBetween(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - Integer selectUserCountByCreateTimeBetween(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - Integer selectUserCountByPayTimeBetween(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - /** - * 按照支付时间统计订单(按天分组) - * - * @param beginTime 支付起始时间 - * @param endTime 支付截止时间 - * @return 订单统计列表 - */ - List selectListByPayTimeBetweenAndGroupByDay(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - /** - * 按照支付时间统计订单(按月分组) - * - * @param beginTime 支付起始时间 - * @param endTime 支付截止时间 - * @return 订单统计列表 - */ - List selectListByPayTimeBetweenAndGroupByMonth(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - Long selectCountByStatusAndDeliveryType(@Param("status") Integer status, @Param("deliveryType") Integer deliveryType); - - TradeOrderSummaryRespVO selectPaySummaryByStatusAndPayTimeBetween(@Param("status") Integer status, - @Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeStatisticsMapper.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeStatisticsMapper.java deleted file mode 100644 index 67d2d50073..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/mysql/trade/TradeStatisticsMapper.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.yudao.module.statistics.dal.mysql.trade; - -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeTrendSummaryRespVO; -import cn.iocoder.yudao.module.statistics.dal.dataobject.trade.TradeStatisticsDO; -import cn.iocoder.yudao.module.statistics.service.trade.bo.TradeSummaryRespBO; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.time.LocalDateTime; -import java.util.List; - -/** - * 交易统计 Mapper - * - * @author owen - */ -@Mapper -public interface TradeStatisticsMapper extends BaseMapperX { - - TradeSummaryRespBO selectOrderCreateCountSumAndOrderPayPriceSumByTimeBetween(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - TradeTrendSummaryRespVO selectVoByTimeBetween(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - default List selectListByTimeBetween(LocalDateTime beginTime, LocalDateTime endTime) { - return selectList(new LambdaQueryWrapperX() - .between(TradeStatisticsDO::getTime, beginTime, endTime)); - } - - Integer selectExpensePriceByTimeBetween(@Param("beginTime") LocalDateTime beginTime, - @Param("endTime") LocalDateTime endTime); - - default TradeStatisticsDO selectByTimeBetween(LocalDateTime beginTime, LocalDateTime endTime) { - return selectOne(new LambdaQueryWrapperX() - .between(TradeStatisticsDO::getTime, beginTime, endTime)); - } - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/infra/ApiAccessLogStatisticsService.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/infra/ApiAccessLogStatisticsService.java deleted file mode 100644 index 6c200fdefa..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/infra/ApiAccessLogStatisticsService.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.statistics.service.infra; - -import java.time.LocalDateTime; - -/** - * API 访问日志的统计 Service 接口 - * - * @author owen - */ -public interface ApiAccessLogStatisticsService { - - /** - * 获取活跃用户数量 - * - * @param userType 用户类型 - * @param beginTime 起始时间 - * @param endTime 截止时间 - * @return 活跃用户数量 - */ - Integer getUserCount(Integer userType, LocalDateTime beginTime, LocalDateTime endTime); - - /** - * 获取访问用户数量 - * - * @param userType 用户类型 - * @param beginTime 起始时间 - * @param endTime 截止时间 - * @return 访问用户数量 - */ - Integer getIpCount(Integer userType, LocalDateTime beginTime, LocalDateTime endTime); - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/member/MemberStatisticsService.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/member/MemberStatisticsService.java deleted file mode 100644 index 253cba68a6..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/member/MemberStatisticsService.java +++ /dev/null @@ -1,70 +0,0 @@ -package cn.iocoder.yudao.module.statistics.service.member; - -import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; -import cn.iocoder.yudao.module.statistics.controller.admin.member.vo.*; - -import java.time.LocalDateTime; -import java.util.List; - -/** - * 会员信息的统计 Service 接口 - * - * @author owen - */ -public interface MemberStatisticsService { - - /** - * 获取会员统计(实时统计) - * - * @return 会员统计 - */ - MemberSummaryRespVO getMemberSummary(); - - /** - * 获取会员分析对照数据 - * - * @param beginTime 起始时间 - * @param endTime 截止时间 - * @return 会员分析对照数据 - */ - DataComparisonRespVO getMemberAnalyseComparisonData(LocalDateTime beginTime, - LocalDateTime endTime); - - /** - * 按照省份,获得会员统计列表 - * - * @return 会员统计列表 - */ - List getMemberAreaStatisticsList(); - - /** - * 按照性别,获得会员统计列表 - * - * @return 会员统计列表 - */ - List getMemberSexStatisticsList(); - - /** - * 按照终端,获得会员统计列表 - * - * @return 会员统计列表 - */ - List getMemberTerminalStatisticsList(); - - /** - * 获取用户注册数量列表 - * - * @param beginTime 起始时间 - * @param endTime 截止时间 - * @return 注册数量列表 - */ - List getMemberRegisterCountList(LocalDateTime beginTime, LocalDateTime endTime); - - /** - * 获得用户数量量统计对照 - * - * @return 用户数量量统计对照 - */ - DataComparisonRespVO getUserCountComparison(); - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/PayWalletStatisticsService.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/PayWalletStatisticsService.java deleted file mode 100644 index d43a576824..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/pay/PayWalletStatisticsService.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.statistics.service.pay; - -import cn.iocoder.yudao.module.statistics.service.pay.bo.RechargeSummaryRespBO; -import cn.iocoder.yudao.module.statistics.service.trade.bo.WalletSummaryRespBO; - -import java.time.LocalDateTime; - -/** - * 钱包的统计 Service 接口 - * - * @author owen - */ -public interface PayWalletStatisticsService { - - /** - * 获取钱包统计 - * - * @param beginTime 起始时间 - * @param endTime 截止时间 - * @return 钱包统计 - */ - WalletSummaryRespBO getWalletSummary(LocalDateTime beginTime, LocalDateTime endTime); - - /** - * 获取钱包充值统计 - * - * @param beginTime 起始时间 - * @param endTime 截止时间 - * @return 钱包充值统计 - */ - RechargeSummaryRespBO getUserRechargeSummary(LocalDateTime beginTime, LocalDateTime endTime); - - /** - * 获取充值金额合计 - * - * @return 充值金额合计 - */ - Integer getRechargePriceSummary(); - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/AfterSaleStatisticsService.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/AfterSaleStatisticsService.java deleted file mode 100644 index f584c3dc76..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/AfterSaleStatisticsService.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.statistics.service.trade; - -import cn.iocoder.yudao.module.statistics.service.trade.bo.AfterSaleSummaryRespBO; -import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum; - -import java.time.LocalDateTime; - -/** - * 售后统计 Service 接口 - * - * @author owen - */ -public interface AfterSaleStatisticsService { - - /** - * 获取售后单统计 - * - * @param beginTime 起始时间 - * @param endTime 截止时间 - * @return 售后统计结果 - */ - AfterSaleSummaryRespBO getAfterSaleSummary(LocalDateTime beginTime, LocalDateTime endTime); - - /** - * 获取指定状态的售后订单数量 - * - * @param status 售后状态 - * @return 售后订单数量 - */ - Long getCountByStatus(AfterSaleStatusEnum status); - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/BrokerageStatisticsService.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/BrokerageStatisticsService.java deleted file mode 100644 index 6845b608ac..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/BrokerageStatisticsService.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.iocoder.yudao.module.statistics.service.trade; - -import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum; - -import java.time.LocalDateTime; - -/** - * 分销统计 Service 接口 - * - * @author owen - */ -public interface BrokerageStatisticsService { - - /** - * 获取已结算的佣金金额 - * - * @param beginTime 起始时间 - * @param endTime 截止时间 - * @return 已结算的佣金金额 - */ - Integer getBrokerageSettlementPriceSummary(LocalDateTime beginTime, LocalDateTime endTime); - - /** - * 获取指定状态的提现记录数量 - * - * @param status 提现记录状态 - * @return 提现记录数量 - */ - Long getWithdrawCountByStatus(BrokerageWithdrawStatusEnum status); - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeOrderStatisticsService.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeOrderStatisticsService.java deleted file mode 100644 index 2197515c42..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeOrderStatisticsService.java +++ /dev/null @@ -1,83 +0,0 @@ -package cn.iocoder.yudao.module.statistics.service.trade; - -import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; -import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.*; -import cn.iocoder.yudao.module.statistics.service.member.bo.MemberAreaStatisticsRespBO; -import cn.iocoder.yudao.module.statistics.service.trade.bo.TradeOrderSummaryRespBO; - -import java.time.LocalDateTime; -import java.util.List; - -/** - * 交易订单的统计 Service 接口 - * - * @author owen - */ -public interface TradeOrderStatisticsService { - - /** - * 获取订单统计 - * - * @param beginTime 起始时间 - * @param endTime 截止时间 - * @return 订单统计结果 - */ - TradeOrderSummaryRespBO getOrderSummary(LocalDateTime beginTime, LocalDateTime endTime); - - /** - * 获取地区订单统计 - * - * @return 订单统计结果 - */ - List getSummaryListByAreaId(); - - /** - * 获取下单用户数量 - * - * @param beginTime 起始时间 - * @param endTime 截止时间 - * @return 下单用户数量 - */ - Integer getOrderUserCount(LocalDateTime beginTime, LocalDateTime endTime); - - /** - * 获取支付用户数量 - * - * @param beginTime 起始时间 - * @param endTime 截止时间 - * @return 支付用户数量 - */ - Integer getPayUserCount(LocalDateTime beginTime, LocalDateTime endTime); - - /** - * 获取支付金额 - * - * @param beginTime 起始时间 - * @param endTime 截止时间 - * @return 支付用户金额 - */ - Integer getOrderPayPrice(LocalDateTime beginTime, LocalDateTime endTime); - - /** - * 根据订单状态、物流类型,获得交易订单数量 - * - * @return 订单数量 - */ - Long getCountByStatusAndDeliveryType(Integer status, Integer deliveryType); - - /** - * 交易订单销售额对照 - * - * @return 销售额对照 - */ - DataComparisonRespVO getOrderComparison(); - - /** - * 获得订单量趋势统计 - * - * @param reqVO 统计参数 - * @return 订单量趋势统计 - */ - List> getOrderCountTrendComparison(TradeOrderTrendReqVO reqVO); - -} diff --git a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeStatisticsService.java b/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeStatisticsService.java deleted file mode 100644 index e175985fbe..0000000000 --- a/yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/service/trade/TradeStatisticsService.java +++ /dev/null @@ -1,67 +0,0 @@ -package cn.iocoder.yudao.module.statistics.service.trade; - -import cn.iocoder.yudao.module.statistics.controller.admin.common.vo.DataComparisonRespVO; -import cn.iocoder.yudao.module.statistics.controller.admin.trade.vo.TradeTrendSummaryRespVO; -import cn.iocoder.yudao.module.statistics.dal.dataobject.trade.TradeStatisticsDO; -import cn.iocoder.yudao.module.statistics.service.trade.bo.TradeSummaryRespBO; - -import java.time.LocalDateTime; -import java.util.List; - -/** - * 交易统计 Service 接口 - * - * @author owen - */ -public interface TradeStatisticsService { - - /** - * 获得交易状况统计对照 - * - * @return 统计数据对照 - */ - DataComparisonRespVO getTradeStatisticsAnalyse( - LocalDateTime beginTime, LocalDateTime endTime); - - /** - * 获得交易状况统计 - * - * @param beginTime 开始时间 - * @param endTime 结束时间 - * @return 统计数据对照 - */ - Integer getExpensePrice(LocalDateTime beginTime, LocalDateTime endTime); - - /** - * 获得交易状况明细 - * - * @param beginTime 开始时间 - * @param endTime 结束时间 - * @return 统计数据列表 - */ - List getTradeStatisticsList(LocalDateTime beginTime, LocalDateTime endTime); - - /** - * 统计指定天数的交易数据 - * - * @return 统计结果 - */ - String statisticsTrade(Integer days); - - /** - * 统计指定日期的交易数据 - * - * @param days 增加的天数 - * @return 交易数据 - */ - TradeSummaryRespBO getTradeSummaryByDays(int days); - - /** - * 统计指定月份的交易数据 - * - * @param months 增加的月数 - * @return 交易数据 - */ - TradeSummaryRespBO getTradeSummaryByMonths(int months); - -} diff --git a/yudao-module-mall/yudao-module-trade-biz/pom.xml b/yudao-module-mall/yudao-module-trade-biz/pom.xml deleted file mode 100644 index 0ecadd7d35..0000000000 --- a/yudao-module-mall/yudao-module-trade-biz/pom.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - cn.iocoder.boot - yudao-module-mall - ${revision} - - 4.0.0 - yudao-module-trade-biz - jar - - ${project.artifactId} - - trade 模块,主要实现交易相关功能 - 例如:订单、退款、购物车等功能。 - - - - - cn.iocoder.boot - yudao-module-trade-api - ${revision} - - - cn.iocoder.boot - yudao-module-product-api - ${revision} - - - cn.iocoder.boot - yudao-module-pay-api - ${revision} - - - cn.iocoder.boot - yudao-module-promotion-api - ${revision} - - - cn.iocoder.boot - yudao-module-member-api - ${revision} - - - cn.iocoder.boot - yudao-module-system-api - ${revision} - - - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-operatelog - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-tenant - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-ip - - - - - cn.iocoder.boot - yudao-spring-boot-starter-web - - - - cn.iocoder.boot - yudao-spring-boot-starter-security - - - - - cn.iocoder.boot - yudao-spring-boot-starter-mybatis - - - - cn.iocoder.boot - yudao-spring-boot-starter-redis - - - - - cn.iocoder.boot - yudao-spring-boot-starter-test - - - - - cn.iocoder.boot - yudao-spring-boot-starter-excel - - - - diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageWithdrawConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageWithdrawConvert.java deleted file mode 100644 index 64e8ccc64a..0000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/BrokerageWithdrawConvert.java +++ /dev/null @@ -1,57 +0,0 @@ -package cn.iocoder.yudao.module.trade.convert.brokerage; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.dict.util.DictFrameworkUtils; -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; -import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawPageReqVO; -import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawRespVO; -import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawCreateReqVO; -import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawPageReqVO; -import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawRespVO; -import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO; -import cn.iocoder.yudao.module.trade.enums.DictTypeConstants; -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -import java.util.List; -import java.util.Map; -import java.util.Optional; - -/** - * 佣金提现 Convert - * - * @author 芋道源码 - */ -@Mapper -public interface BrokerageWithdrawConvert { - - BrokerageWithdrawConvert INSTANCE = Mappers.getMapper(BrokerageWithdrawConvert.class); - - BrokerageWithdrawDO convert(AppBrokerageWithdrawCreateReqVO createReqVO, Long userId, Integer feePrice); - - BrokerageWithdrawRespVO convert(BrokerageWithdrawDO bean); - - List convertList(List list); - - PageResult convertPage(PageResult page); - - default PageResult convertPage(PageResult pageResult, Map userMap) { - PageResult result = convertPage(pageResult); - for (BrokerageWithdrawRespVO vo : result.getList()) { - vo.setUserNickname(Optional.ofNullable(userMap.get(vo.getUserId())).map(MemberUserRespDTO::getNickname).orElse(null)); - } - return result; - } - - PageResult convertPage02(PageResult pageResult); - - default PageResult convertPage03(PageResult pageResult) { - PageResult result = convertPage02(pageResult); - for (AppBrokerageWithdrawRespVO vo : result.getList()) { - vo.setStatusName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.BROKERAGE_WITHDRAW_STATUS, vo.getStatus())); - } - return result; - } - - BrokerageWithdrawPageReqVO convert(AppBrokerageWithdrawPageReqVO pageReqVO, Long userId); -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java deleted file mode 100644 index ed556c6984..0000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ /dev/null @@ -1,288 +0,0 @@ -package cn.iocoder.yudao.module.trade.convert.order; - -import cn.hutool.core.util.BooleanUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.string.StrUtils; -import cn.iocoder.yudao.framework.dict.util.DictFrameworkUtils; -import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; -import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO; -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; -import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; -import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; -import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; -import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; -import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; -import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; -import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; -import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; -import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; -import cn.iocoder.yudao.module.trade.controller.admin.order.vo.*; -import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; -import cn.iocoder.yudao.module.trade.controller.app.order.vo.*; -import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO; -import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; -import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO; -import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; -import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; -import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; -import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO; -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; -import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO; -import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; -import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO; -import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; -import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Mappings; -import org.mapstruct.Named; -import org.mapstruct.factory.Mappers; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; - -@Mapper -public interface TradeOrderConvert { - - TradeOrderConvert INSTANCE = Mappers.getMapper(TradeOrderConvert.class); - - @Mappings({ - @Mapping(target = "id", ignore = true), - @Mapping(source = "userId", target = "userId"), - @Mapping(source = "createReqVO.couponId", target = "couponId"), - @Mapping(target = "remark", ignore = true), - @Mapping(source = "createReqVO.remark", target = "userRemark"), - @Mapping(source = "calculateRespBO.price.totalPrice", target = "totalPrice"), - @Mapping(source = "calculateRespBO.price.discountPrice", target = "discountPrice"), - @Mapping(source = "calculateRespBO.price.deliveryPrice", target = "deliveryPrice"), - @Mapping(source = "calculateRespBO.price.couponPrice", target = "couponPrice"), - @Mapping(source = "calculateRespBO.price.pointPrice", target = "pointPrice"), - @Mapping(source = "calculateRespBO.price.vipPrice", target = "vipPrice"), - @Mapping(source = "calculateRespBO.price.payPrice", target = "payPrice") - }) - TradeOrderDO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradePriceCalculateRespBO calculateRespBO); - - TradeOrderRespDTO convert(TradeOrderDO orderDO); - - default List convertList(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) { - return CollectionUtils.convertList(calculateRespBO.getItems(), item -> { - TradeOrderItemDO orderItem = convert(item); - orderItem.setOrderId(tradeOrderDO.getId()); - orderItem.setUserId(tradeOrderDO.getUserId()); - orderItem.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); - orderItem.setCommentStatus(false); - return orderItem; - }); - } - - TradeOrderItemDO convert(TradePriceCalculateRespBO.OrderItem item); - - default ProductSkuUpdateStockReqDTO convert(List list) { - List items = CollectionUtils.convertList(list, item -> - new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(item.getCount())); - return new ProductSkuUpdateStockReqDTO(items); - } - - default ProductSkuUpdateStockReqDTO convertNegative(List list) { - List items = CollectionUtils.convertList(list, item -> - new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(-item.getCount())); - return new ProductSkuUpdateStockReqDTO(items); - } - - default PayOrderCreateReqDTO convert(TradeOrderDO order, List orderItems, - TradeOrderProperties orderProperties) { - PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO() - .setAppId(orderProperties.getAppId()).setUserIp(order.getUserIp()); - // 商户相关字段 - createReqDTO.setMerchantOrderId(String.valueOf(order.getId())); - String subject = orderItems.get(0).getSpuName(); - subject = StrUtils.maxLength(subject, PayOrderCreateReqDTO.SUBJECT_MAX_LENGTH); // 避免超过 32 位 - createReqDTO.setSubject(subject); - createReqDTO.setBody(subject); // TODO 芋艿:临时写死 - // 订单相关字段 - createReqDTO.setPrice(order.getPayPrice()).setExpireTime(addTime(orderProperties.getPayExpireTime())); - return createReqDTO; - } - - default PageResult convertPage(PageResult pageResult, - List orderItems, - Map memberUserMap) { - Map> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId); - // 转化 List - List orderVOs = CollectionUtils.convertList(pageResult.getList(), order -> { - List xOrderItems = orderItemMap.get(order.getId()); - TradeOrderPageItemRespVO orderVO = convert(order, xOrderItems); - // 处理收货地址 - orderVO.setReceiverAreaName(AreaUtils.format(order.getReceiverAreaId())); - // 增加用户信息 - orderVO.setUser(convertUser(memberUserMap.get(orderVO.getUserId()))); - // 增加推广人信息 - orderVO.setBrokerageUser(convertUser(memberUserMap.get(orderVO.getBrokerageUserId()))); - return orderVO; - }); - return new PageResult<>(orderVOs, pageResult.getTotal()); - } - - MemberUserRespVO convertUser(MemberUserRespDTO memberUserRespDTO); - - TradeOrderPageItemRespVO convert(TradeOrderDO order, List items); - - ProductPropertyValueDetailRespVO convert(ProductPropertyValueDetailRespDTO bean); - - default TradeOrderDetailRespVO convert(TradeOrderDO order, List orderItems, - List orderLogs, - MemberUserRespDTO user, MemberUserRespDTO brokerageUser) { - TradeOrderDetailRespVO orderVO = convert2(order, orderItems); - // 处理收货地址 - orderVO.setReceiverAreaName(AreaUtils.format(order.getReceiverAreaId())); - // 处理用户信息 - orderVO.setUser(convert(user)); - orderVO.setBrokerageUser(convert(brokerageUser)); - // 处理日志 - orderVO.setLogs(convertList03(orderLogs)); - return orderVO; - } - List convertList03(List orderLogs); - - TradeOrderDetailRespVO convert2(TradeOrderDO order, List items); - - MemberUserRespVO convert(MemberUserRespDTO bean); - - default PageResult convertPage02(PageResult pageResult, - List orderItems) { - Map> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId); - // 转化 List - List orderVOs = CollectionUtils.convertList(pageResult.getList(), order -> { - List xOrderItems = orderItemMap.get(order.getId()); - return convert02(order, xOrderItems); - }); - return new PageResult<>(orderVOs, pageResult.getTotal()); - } - - AppTradeOrderPageItemRespVO convert02(TradeOrderDO order, List items); - - AppProductPropertyValueDetailRespVO convert02(ProductPropertyValueDetailRespDTO bean); - - default AppTradeOrderDetailRespVO convert02(TradeOrderDO order, List orderItems, - TradeOrderProperties tradeOrderProperties, - DeliveryExpressDO express) { - AppTradeOrderDetailRespVO orderVO = convert3(order, orderItems); - orderVO.setPayExpireTime(addTime(tradeOrderProperties.getPayExpireTime())); - if (StrUtil.isNotEmpty(order.getPayChannelCode())) { - orderVO.setPayChannelName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.CHANNEL_CODE, order.getPayChannelCode())); - } - // 处理收货地址 - orderVO.setReceiverAreaName(AreaUtils.format(order.getReceiverAreaId())); - if (express != null) { - orderVO.setLogisticsId(express.getId()).setLogisticsName(express.getName()); - } - return orderVO; - } - - AppTradeOrderDetailRespVO convert3(TradeOrderDO order, List items); - - AppTradeOrderItemRespVO convert03(TradeOrderItemDO bean); - - @Mappings({ - @Mapping(target = "skuId", source = "tradeOrderItemDO.skuId"), - @Mapping(target = "orderId", source = "tradeOrderItemDO.orderId"), - @Mapping(target = "orderItemId", source = "tradeOrderItemDO.id"), - @Mapping(target = "descriptionScores", source = "createReqVO.descriptionScores"), - @Mapping(target = "benefitScores", source = "createReqVO.benefitScores"), - @Mapping(target = "content", source = "createReqVO.content"), - @Mapping(target = "picUrls", source = "createReqVO.picUrls"), - @Mapping(target = "anonymous", source = "createReqVO.anonymous"), - @Mapping(target = "userId", source = "tradeOrderItemDO.userId") - }) - ProductCommentCreateReqDTO convert04(AppTradeOrderItemCommentCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItemDO); - - TradePriceCalculateReqBO convert(AppTradeOrderSettlementReqVO settlementReqVO); - - default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO, - List cartList) { - TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO().setUserId(userId) - .setItems(new ArrayList<>(settlementReqVO.getItems().size())) - .setCouponId(settlementReqVO.getCouponId()).setPointStatus(settlementReqVO.getPointStatus()) - // 物流信息 - .setDeliveryType(settlementReqVO.getDeliveryType()).setAddressId(settlementReqVO.getAddressId()) - .setPickUpStoreId(settlementReqVO.getPickUpStoreId()) - // 各种活动 - .setSeckillActivityId(settlementReqVO.getSeckillActivityId()) - .setBargainRecordId(settlementReqVO.getBargainRecordId()) - .setCombinationActivityId(settlementReqVO.getCombinationActivityId()) - .setCombinationHeadId(settlementReqVO.getCombinationHeadId()); - // 商品项的构建 - Map cartMap = convertMap(cartList, CartDO::getId); - for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) { - // 情况一:skuId + count - if (item.getSkuId() != null) { - reqBO.getItems().add(new TradePriceCalculateReqBO.Item().setSkuId(item.getSkuId()).setCount(item.getCount()) - .setSelected(true)); // true 的原因,下单一定选中 - continue; - } - // 情况二:cartId - CartDO cart = cartMap.get(item.getCartId()); - if (cart == null) { - continue; - } - reqBO.getItems().add(new TradePriceCalculateReqBO.Item().setSkuId(cart.getSkuId()).setCount(cart.getCount()) - .setCartId(item.getCartId()).setSelected(true)); // true 的原因,下单一定选中 - } - return reqBO; - } - - default AppTradeOrderSettlementRespVO convert(TradePriceCalculateRespBO calculate, MemberAddressRespDTO address) { - AppTradeOrderSettlementRespVO respVO = convert0(calculate, address); - if (address != null) { - respVO.getAddress().setAreaName(AreaUtils.format(address.getAreaId())); - } - return respVO; - } - - AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, MemberAddressRespDTO address); - - List convertList02(List list); - - TradeOrderDO convert(TradeOrderUpdateAddressReqVO reqVO); - - TradeOrderDO convert(TradeOrderUpdatePriceReqVO reqVO); - - TradeOrderDO convert(TradeOrderRemarkReqVO reqVO); - - default BrokerageAddReqBO convert(MemberUserRespDTO user, TradeOrderItemDO item, - ProductSpuRespDTO spu, ProductSkuRespDTO sku) { - BrokerageAddReqBO bo = new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId()) - .setBasePrice(item.getPayPrice() * item.getCount()) - .setTitle(StrUtil.format("{}成功购买{}", user.getNickname(), item.getSpuName())) - .setFirstFixedPrice(0).setSecondFixedPrice(0); - if (BooleanUtil.isTrue(spu.getSubCommissionType())) { - bo.setFirstFixedPrice(sku.getFirstBrokeragePrice()).setSecondFixedPrice(sku.getSecondBrokeragePrice()); - } - return bo; - } - - @Named("convertList04") - List convertList04(List list); - - @Mappings({ - @Mapping(target = "activityId", source = "order.combinationActivityId"), - @Mapping(target = "spuId", source = "item.spuId"), - @Mapping(target = "skuId", source = "item.skuId"), - @Mapping(target = "count", source = "item.count"), - @Mapping(target = "orderId", source = "order.id"), - @Mapping(target = "userId", source = "order.userId"), - @Mapping(target = "headId", source = "order.combinationHeadId"), - @Mapping(target = "combinationPrice", source = "item.payPrice"), - }) - CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO item); - -} diff --git a/yudao-module-pay/pom.xml b/yudao-module-pay/pom.xml deleted file mode 100644 index 85bcb1e2c7..0000000000 --- a/yudao-module-pay/pom.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - cn.iocoder.boot - yudao - ${revision} - - 4.0.0 - yudao-module-pay - pom - - yudao-module-pay-api - yudao-module-pay-biz - yudao-spring-boot-starter-biz-pay - - - ${project.artifactId} - - pay 模块,我们放支付业务,提供业务的支付能力。 - 例如说:商户、应用、支付、退款等等 - - - diff --git a/yudao-module-pay/yudao-module-pay-biz/pom.xml b/yudao-module-pay/yudao-module-pay-biz/pom.xml deleted file mode 100644 index de7afb1734..0000000000 --- a/yudao-module-pay/yudao-module-pay-biz/pom.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - cn.iocoder.boot - yudao-module-pay - ${revision} - - 4.0.0 - yudao-module-pay-biz - jar - - ${project.artifactId} - - pay 模块,我们放支付业务,提供业务的支付能力。 - 例如说:商户、应用、支付、退款等等 - - - - - cn.iocoder.boot - yudao-module-pay-api - ${revision} - - - cn.iocoder.boot - yudao-module-member-api - ${revision} - - - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-operatelog - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-pay - ${revision} - - - cn.iocoder.boot - yudao-spring-boot-starter-biz-tenant - - - - - cn.iocoder.boot - yudao-spring-boot-starter-security - - - - - cn.iocoder.boot - yudao-spring-boot-starter-mybatis - - - - cn.iocoder.boot - yudao-spring-boot-starter-redis - - - - - cn.iocoder.boot - yudao-spring-boot-starter-job - - - - - cn.iocoder.boot - yudao-spring-boot-starter-test - test - - - - - cn.iocoder.boot - yudao-spring-boot-starter-excel - - - - diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletRechargeConvert.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletRechargeConvert.java deleted file mode 100644 index dabb8b52b3..0000000000 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/wallet/PayWalletRechargeConvert.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.yudao.module.pay.convert.wallet; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.dict.util.DictFrameworkUtils; -import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateRespVO; -import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeRespVO; -import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; -import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO; -import cn.iocoder.yudao.module.pay.enums.DictTypeConstants; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.factory.Mappers; - -import java.util.List; -import java.util.Map; - -@Mapper -public interface PayWalletRechargeConvert { - - PayWalletRechargeConvert INSTANCE = Mappers.getMapper(PayWalletRechargeConvert.class); - - @Mapping(target = "totalPrice", expression = "java( payPrice + bonusPrice)") - PayWalletRechargeDO convert(Long walletId, Integer payPrice, Integer bonusPrice, Long packageId); - - AppPayWalletRechargeCreateRespVO convert(PayWalletRechargeDO bean); - - default PageResult convertPage(PageResult pageResult, - List payOrderList) { - PageResult voPageResult = BeanUtils.toBean(pageResult, AppPayWalletRechargeRespVO.class); - Map payOrderMap = CollectionUtils.convertMap(payOrderList, PayOrderDO::getId); - voPageResult.getList().forEach(recharge -> { - recharge.setPayChannelName(DictFrameworkUtils.getDictDataLabel( - DictTypeConstants.CHANNEL_CODE, recharge.getPayChannelCode())); - MapUtils.findAndThen(payOrderMap, recharge.getPayOrderId(), - order -> recharge.setPayOrderChannelOrderNo(order.getChannelOrderNo())); - }); - return voPageResult; - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/pom.xml b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/pom.xml deleted file mode 100644 index 93193d008e..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/pom.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - cn.iocoder.boot - yudao-module-pay - ${revision} - - 4.0.0 - - yudao-spring-boot-starter-biz-pay - ${project.artifactId} - 支付拓展,接入国内多个支付渠道 - 1. 支付宝,基于官方 SDK 接入 - 2. 微信支付,基于 weixin-java-pay 接入 - - - - - cn.iocoder.boot - yudao-common - - - - - org.springframework.boot - spring-boot-starter - - - - - org.springframework.boot - spring-boot-starter-validation - - - - org.slf4j - slf4j-api - - - - com.fasterxml.jackson.core - jackson-databind - - - com.fasterxml.jackson.core - jackson-core - - - - - com.alipay.sdk - alipay-sdk-java - 4.35.79.ALL - - - org.bouncycastle - bcprov-jdk15on - - - - - com.github.binarywang - weixin-java-pay - - - - - cn.iocoder.boot - yudao-spring-boot-starter-test - test - - - - diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/YudaoPayAutoConfiguration.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/YudaoPayAutoConfiguration.java deleted file mode 100644 index e57f4ac702..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/YudaoPayAutoConfiguration.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.framework.pay.config; - -import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; -import cn.iocoder.yudao.framework.pay.core.client.impl.PayClientFactoryImpl; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; - -/** - * 支付配置类 - * - * @author 芋道源码 - */ -@AutoConfiguration -public class YudaoPayAutoConfiguration { - - @Bean - public PayClientFactory payClientFactory() { - return new PayClientFactoryImpl(); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java deleted file mode 100644 index 86e3566b2b..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java +++ /dev/null @@ -1,98 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client; - -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; - -import java.util.Map; - -/** - * 支付客户端,用于对接各支付渠道的 SDK,实现发起支付、退款等功能 - * - * @author 芋道源码 - */ -public interface PayClient { - - /** - * 获得渠道编号 - * - * @return 渠道编号 - */ - Long getId(); - - // ============ 支付相关 ========== - - /** - * 调用支付渠道,统一下单 - * - * @param reqDTO 下单信息 - * @return 支付订单信息 - */ - PayOrderRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO); - - /** - * 解析 order 回调数据 - * - * @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数 - * @param body HTTP 回调接口的 request body - * @return 支付订单信息 - */ - PayOrderRespDTO parseOrderNotify(Map params, String body); - - /** - * 获得支付订单信息 - * - * @param outTradeNo 外部订单号 - * @return 支付订单信息 - */ - PayOrderRespDTO getOrder(String outTradeNo); - - // ============ 退款相关 ========== - - /** - * 调用支付渠道,进行退款 - * - * @param reqDTO 统一退款请求信息 - * @return 退款信息 - */ - PayRefundRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO); - - /** - * 解析 refund 回调数据 - * - * @param params HTTP 回调接口 content type 为 application/x-www-form-urlencoded 的所有参数 - * @param body HTTP 回调接口的 request body - * @return 支付订单信息 - */ - PayRefundRespDTO parseRefundNotify(Map params, String body); - - /** - * 获得退款订单信息 - * - * @param outTradeNo 外部订单号 - * @param outRefundNo 外部退款号 - * @return 退款订单信息 - */ - PayRefundRespDTO getRefund(String outTradeNo, String outRefundNo); - - /** - * 调用渠道,进行转账 - * - * @param reqDTO 统一转账请求信息 - * @return 转账信息 - */ - PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO); - - /** - * 获得转账订单信息 - * - * @param outTradeNo 外部订单号 - * @param type 转账类型 - * @return 转账信息 - */ - PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type); -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java deleted file mode 100644 index 5a38430342..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client; - -import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; -import com.fasterxml.jackson.annotation.JsonTypeInfo; - -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.Validator; -import java.util.Set; - -/** - * 支付客户端的配置,本质是支付渠道的配置 - * 每个不同的渠道,需要不同的配置,通过子类来定义 - * - * @author 芋道源码 - */ -@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) -// @JsonTypeInfo 注解的作用,Jackson 多态 -// 1. 序列化到时数据库时,增加 @class 属性。 -// 2. 反序列化到内存对象时,通过 @class 属性,可以创建出正确的类型 -public interface PayClientConfig { - - /** - * 参数校验 - * - * @param validator 校验对象 - */ - void validate(Validator validator); - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientFactory.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientFactory.java deleted file mode 100644 index 53f1a8c069..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientFactory.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client; - -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; - -/** - * 支付客户端的工厂接口 - * - * @author 芋道源码 - */ -public interface PayClientFactory { - - /** - * 获得支付客户端 - * - * @param channelId 渠道编号 - * @return 支付客户端 - */ - PayClient getPayClient(Long channelId); - - /** - * 创建支付客户端 - * - * @param channelId 渠道编号 - * @param channelCode 渠道编码 - * @param config 支付配置 - */ - void createOrUpdatePayClient(Long channelId, String channelCode, - Config config); - - /** - * 注册支付客户端 Class,用于模块中实现的 PayClient - * - * @param channel 支付渠道的编码的枚举 - * @param payClientClass 支付客户端 class - */ - void registerPayClientClass(PayChannelEnum channel, Class payClientClass); - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java deleted file mode 100644 index 82050a6fcb..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderRespDTO.java +++ /dev/null @@ -1,141 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.dto.order; - -import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; -import lombok.Data; - -import java.time.LocalDateTime; - -/** - * 渠道支付订单 Response DTO - * - * @author 芋道源码 - */ -@Data -public class PayOrderRespDTO { - - /** - * 支付状态 - * - * 枚举:{@link PayOrderStatusRespEnum} - */ - private Integer status; - - /** - * 外部订单号 - * - * 对应 PayOrderExtensionDO 的 no 字段 - */ - private String outTradeNo; - - /** - * 支付渠道编号 - */ - private String channelOrderNo; - /** - * 支付渠道用户编号 - */ - private String channelUserId; - - /** - * 支付成功时间 - */ - private LocalDateTime successTime; - - /** - * 原始的同步/异步通知结果 - */ - private Object rawData; - - // ========== 主动发起支付时,会返回的字段 ========== - - /** - * 展示模式 - * - * 枚举 {@link PayOrderDisplayModeEnum} 类 - */ - private String displayMode; - /** - * 展示内容 - */ - private String displayContent; - - /** - * 调用渠道的错误码 - * - * 注意:这里返回的是业务异常,而是不系统异常。 - * 如果是系统异常,则会抛出 {@link PayException} - */ - private String channelErrorCode; - /** - * 调用渠道报错时,错误信息 - */ - private String channelErrorMsg; - - public PayOrderRespDTO() { - } - - /** - * 创建【WAITING】状态的订单返回 - */ - public static PayOrderRespDTO waitingOf(String displayMode, String displayContent, - String outTradeNo, Object rawData) { - PayOrderRespDTO respDTO = new PayOrderRespDTO(); - respDTO.status = PayOrderStatusRespEnum.WAITING.getStatus(); - respDTO.displayMode = displayMode; - respDTO.displayContent = displayContent; - // 相对通用的字段 - respDTO.outTradeNo = outTradeNo; - respDTO.rawData = rawData; - return respDTO; - } - - /** - * 创建【SUCCESS】状态的订单返回 - */ - public static PayOrderRespDTO successOf(String channelOrderNo, String channelUserId, LocalDateTime successTime, - String outTradeNo, Object rawData) { - PayOrderRespDTO respDTO = new PayOrderRespDTO(); - respDTO.status = PayOrderStatusRespEnum.SUCCESS.getStatus(); - respDTO.channelOrderNo = channelOrderNo; - respDTO.channelUserId = channelUserId; - respDTO.successTime = successTime; - // 相对通用的字段 - respDTO.outTradeNo = outTradeNo; - respDTO.rawData = rawData; - return respDTO; - } - - /** - * 创建指定状态的订单返回,适合支付渠道回调时 - */ - public static PayOrderRespDTO of(Integer status, String channelOrderNo, String channelUserId, LocalDateTime successTime, - String outTradeNo, Object rawData) { - PayOrderRespDTO respDTO = new PayOrderRespDTO(); - respDTO.status = status; - respDTO.channelOrderNo = channelOrderNo; - respDTO.channelUserId = channelUserId; - respDTO.successTime = successTime; - // 相对通用的字段 - respDTO.outTradeNo = outTradeNo; - respDTO.rawData = rawData; - return respDTO; - } - - /** - * 创建【CLOSED】状态的订单返回,适合调用支付渠道失败时 - */ - public static PayOrderRespDTO closedOf(String channelErrorCode, String channelErrorMsg, - String outTradeNo, Object rawData) { - PayOrderRespDTO respDTO = new PayOrderRespDTO(); - respDTO.status = PayOrderStatusRespEnum.CLOSED.getStatus(); - respDTO.channelErrorCode = channelErrorCode; - respDTO.channelErrorMsg = channelErrorMsg; - // 相对通用的字段 - respDTO.outTradeNo = outTradeNo; - respDTO.rawData = rawData; - return respDTO; - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java deleted file mode 100644 index f269d2f8fe..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java +++ /dev/null @@ -1,92 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.dto.order; - -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import lombok.Data; -import org.hibernate.validator.constraints.Length; -import org.hibernate.validator.constraints.URL; - -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.time.LocalDateTime; -import java.util.Map; - -/** - * 统一下单 Request DTO - * - * @author 芋道源码 - */ -@Data -public class PayOrderUnifiedReqDTO { - - /** - * 用户 IP - */ - @NotEmpty(message = "用户 IP 不能为空") - private String userIp; - - // ========== 商户相关字段 ========== - - /** - * 外部订单号 - * - * 对应 PayOrderExtensionDO 的 no 字段 - */ - @NotEmpty(message = "外部订单编号不能为空") - private String outTradeNo; - /** - * 商品标题 - */ - @NotEmpty(message = "商品标题不能为空") - @Length(max = 32, message = "商品标题不能超过 32") - private String subject; - /** - * 商品描述信息 - */ - @Length(max = 128, message = "商品描述信息长度不能超过128") - private String body; - /** - * 支付结果的 notify 回调地址 - */ - @NotEmpty(message = "支付结果的回调地址不能为空") - @URL(message = "支付结果的 notify 回调地址必须是 URL 格式") - private String notifyUrl; - /** - * 支付结果的 return 回调地址 - */ - @URL(message = "支付结果的 return 回调地址必须是 URL 格式") - private String returnUrl; - - // ========== 订单相关字段 ========== - - /** - * 支付金额,单位:分 - */ - @NotNull(message = "支付金额不能为空") - @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") - private Integer price; - - /** - * 支付过期时间 - */ - @NotNull(message = "支付过期时间不能为空") - private LocalDateTime expireTime; - - // ========== 拓展参数 ========== - /** - * 支付渠道的额外参数 - * - * 例如说,微信公众号需要传递 openid 参数 - */ - private Map channelExtras; - - /** - * 展示模式 - * - * 如果不传递,则每个支付渠道使用默认的方式 - * - * 枚举 {@link PayOrderDisplayModeEnum} - */ - private String displayMode; - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java deleted file mode 100644 index 3184f278de..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java +++ /dev/null @@ -1,115 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.dto.refund; - -import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; -import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; -import lombok.Data; - -import java.time.LocalDateTime; - -/** - * 渠道退款订单 Response DTO - * - * @author jason - */ -@Data -public class PayRefundRespDTO { - - /** - * 退款状态 - * - * 枚举 {@link PayRefundStatusRespEnum} - */ - private Integer status; - - /** - * 外部退款号 - * - * 对应 PayRefundDO 的 no 字段 - */ - private String outRefundNo; - - /** - * 渠道退款单号 - * - * 对应 PayRefundDO.channelRefundNo 字段 - */ - private String channelRefundNo; - - /** - * 退款成功时间 - */ - private LocalDateTime successTime; - - /** - * 原始的异步通知结果 - */ - private Object rawData; - - /** - * 调用渠道的错误码 - * - * 注意:这里返回的是业务异常,而是不系统异常。 - * 如果是系统异常,则会抛出 {@link PayException} - */ - private String channelErrorCode; - /** - * 调用渠道报错时,错误信息 - */ - private String channelErrorMsg; - - private PayRefundRespDTO() { - } - - /** - * 创建【WAITING】状态的退款返回 - */ - public static PayRefundRespDTO waitingOf(String channelRefundNo, - String outRefundNo, Object rawData) { - PayRefundRespDTO respDTO = new PayRefundRespDTO(); - respDTO.status = PayRefundStatusRespEnum.WAITING.getStatus(); - respDTO.channelRefundNo = channelRefundNo; - // 相对通用的字段 - respDTO.outRefundNo = outRefundNo; - respDTO.rawData = rawData; - return respDTO; - } - - /** - * 创建【SUCCESS】状态的退款返回 - */ - public static PayRefundRespDTO successOf(String channelRefundNo, LocalDateTime successTime, - String outRefundNo, Object rawData) { - PayRefundRespDTO respDTO = new PayRefundRespDTO(); - respDTO.status = PayRefundStatusRespEnum.SUCCESS.getStatus(); - respDTO.channelRefundNo = channelRefundNo; - respDTO.successTime = successTime; - // 相对通用的字段 - respDTO.outRefundNo = outRefundNo; - respDTO.rawData = rawData; - return respDTO; - } - - /** - * 创建【FAILURE】状态的退款返回 - */ - public static PayRefundRespDTO failureOf(String outRefundNo, Object rawData) { - return failureOf(null, null, - outRefundNo, rawData); - } - - /** - * 创建【FAILURE】状态的退款返回 - */ - public static PayRefundRespDTO failureOf(String channelErrorCode, String channelErrorMsg, - String outRefundNo, Object rawData) { - PayRefundRespDTO respDTO = new PayRefundRespDTO(); - respDTO.status = PayRefundStatusRespEnum.FAILURE.getStatus(); - respDTO.channelErrorCode = channelErrorCode; - respDTO.channelErrorMsg = channelErrorMsg; - // 相对通用的字段 - respDTO.outRefundNo = outRefundNo; - respDTO.rawData = rawData; - return respDTO; - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundUnifiedReqDTO.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundUnifiedReqDTO.java deleted file mode 100644 index 4f5e203d2c..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundUnifiedReqDTO.java +++ /dev/null @@ -1,70 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.dto.refund; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; -import org.hibernate.validator.constraints.URL; - -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - -/** - * 统一 退款 Request DTO - * - * @author jason - */ -@Accessors(chain = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Data -public class PayRefundUnifiedReqDTO { - - /** - * 外部订单号 - * - * 对应 PayOrderExtensionDO 的 no 字段 - */ - @NotEmpty(message = "外部订单编号不能为空") - private String outTradeNo; - - /** - * 外部退款号 - * - * 对应 PayRefundDO 的 no 字段 - */ - @NotEmpty(message = "退款请求单号不能为空") - private String outRefundNo; - - /** - * 退款原因 - */ - @NotEmpty(message = "退款原因不能为空") - private String reason; - - /** - * 支付金额,单位:分 - * - * 目前微信支付在退款的时候,必须传递该字段 - */ - @NotNull(message = "支付金额不能为空") - @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") - private Integer payPrice; - /** - * 退款金额,单位:分 - */ - @NotNull(message = "退款金额不能为空") - @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") - private Integer refundPrice; - - /** - * 退款结果的 notify 回调地址 - */ - @NotEmpty(message = "支付结果的回调地址不能为空") - @URL(message = "支付结果的 notify 回调地址必须是 URL 格式") - private String notifyUrl; - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java deleted file mode 100644 index 0f9b48240c..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferRespDTO.java +++ /dev/null @@ -1,109 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.dto.transfer; - -import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum; -import lombok.Data; - -import java.time.LocalDateTime; - -/** - * 统一转账 Response DTO - * - * @author jason - */ -@Data -public class PayTransferRespDTO { - - /** - * 转账状态 - * - * 关联 {@link PayTransferStatusRespEnum#getStatus()} - */ - private Integer status; - - /** - * 外部转账单号 - * - */ - private String outTransferNo; - - /** - * 支付渠道编号 - */ - private String channelTransferNo; - - /** - * 支付成功时间 - */ - private LocalDateTime successTime; - - /** - * 原始的返回结果 - */ - private Object rawData; - - /** - * 调用渠道的错误码 - */ - private String channelErrorCode; - /** - * 调用渠道报错时,错误信息 - */ - private String channelErrorMsg; - - /** - * 创建【WAITING】状态的转账返回 - */ - public static PayTransferRespDTO waitingOf(String channelTransferNo, - String outTransferNo, Object rawData) { - PayTransferRespDTO respDTO = new PayTransferRespDTO(); - respDTO.status = PayTransferStatusRespEnum.WAITING.getStatus(); - respDTO.channelTransferNo = channelTransferNo; - respDTO.outTransferNo = outTransferNo; - respDTO.rawData = rawData; - return respDTO; - } - - /** - * 创建【IN_PROGRESS】状态的转账返回 - */ - public static PayTransferRespDTO dealingOf(String channelTransferNo, - String outTransferNo, Object rawData) { - PayTransferRespDTO respDTO = new PayTransferRespDTO(); - respDTO.status = PayTransferStatusRespEnum.IN_PROGRESS.getStatus(); - respDTO.channelTransferNo = channelTransferNo; - respDTO.outTransferNo = outTransferNo; - respDTO.rawData = rawData; - return respDTO; - } - - /** - * 创建【CLOSED】状态的转账返回 - */ - public static PayTransferRespDTO closedOf(String channelErrorCode, String channelErrorMsg, - String outTransferNo, Object rawData) { - PayTransferRespDTO respDTO = new PayTransferRespDTO(); - respDTO.status = PayTransferStatusRespEnum.CLOSED.getStatus(); - respDTO.channelErrorCode = channelErrorCode; - respDTO.channelErrorMsg = channelErrorMsg; - // 相对通用的字段 - respDTO.outTransferNo = outTransferNo; - respDTO.rawData = rawData; - return respDTO; - } - - /** - * 创建【SUCCESS】状态的转账返回 - */ - public static PayTransferRespDTO successOf(String channelTransferNo, LocalDateTime successTime, - String outTransferNo, Object rawData) { - PayTransferRespDTO respDTO = new PayTransferRespDTO(); - respDTO.status = PayTransferStatusRespEnum.SUCCESS.getStatus(); - respDTO.channelTransferNo = channelTransferNo; - respDTO.successTime = successTime; - // 相对通用的字段 - respDTO.outTransferNo = outTransferNo; - respDTO.rawData = rawData; - return respDTO; - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java deleted file mode 100644 index 9a13ddaf10..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java +++ /dev/null @@ -1,78 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.dto.transfer; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; -import lombok.Data; -import org.hibernate.validator.constraints.Length; - -import javax.validation.constraints.Min; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.util.Map; - -import static cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum.*; - -/** - * 统一转账 Request DTO - * - * @author jason - */ -@Data -public class PayTransferUnifiedReqDTO { - - /** - * 转账类型 - * - * 关联 {@link PayTransferTypeEnum#getType()} - */ - @NotNull(message = "转账类型不能为空") - @InEnum(PayTransferTypeEnum.class) - private Integer type; - - /** - * 用户 IP - */ - @NotEmpty(message = "用户 IP 不能为空") - private String userIp; - - @NotEmpty(message = "外部转账单编号不能为空") - private String outTransferNo; - - /** - * 转账金额,单位:分 - */ - @NotNull(message = "转账金额不能为空") - @Min(value = 1, message = "转账金额必须大于零") - private Integer price; - - /** - * 转账标题 - */ - @NotEmpty(message = "转账标题不能为空") - @Length(max = 128, message = "转账标题不能超过 128") - private String subject; - - /** - * 收款人姓名 - */ - @NotBlank(message = "收款人姓名不能为空", groups = {Alipay.class}) - private String userName; - - /** - * 支付宝登录号 - */ - @NotBlank(message = "支付宝登录号不能为空", groups = {Alipay.class}) - private String alipayLogonId; - - /** - * 微信 openId - */ - @NotBlank(message = "微信 openId 不能为空", groups = {WxPay.class}) - private String openid; - - /** - * 支付渠道的额外参数 - */ - private Map channelExtras; -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/exception/PayException.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/exception/PayException.java deleted file mode 100644 index 75f4c39750..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/exception/PayException.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.exception; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 支付系统异常 Exception - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class PayException extends RuntimeException { - - public PayException(Throwable cause) { - super(cause); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java deleted file mode 100644 index 82d68b58f6..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java +++ /dev/null @@ -1,250 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl; - -import cn.iocoder.yudao.framework.common.exception.ServiceException; -import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; -import cn.iocoder.yudao.framework.pay.core.client.PayClient; -import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; -import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; -import lombok.extern.slf4j.Slf4j; - -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; - -/** - * 支付客户端的抽象类,提供模板方法,减少子类的冗余代码 - * - * @author 芋道源码 - */ -@Slf4j -public abstract class AbstractPayClient implements PayClient { - - /** - * 渠道编号 - */ - private final Long channelId; - /** - * 渠道编码 - */ - @SuppressWarnings("FieldCanBeLocal") - private final String channelCode; - /** - * 支付配置 - */ - protected Config config; - - public AbstractPayClient(Long channelId, String channelCode, Config config) { - this.channelId = channelId; - this.channelCode = channelCode; - this.config = config; - } - - /** - * 初始化 - */ - public final void init() { - doInit(); - log.debug("[init][客户端({}) 初始化完成]", getId()); - } - - /** - * 自定义初始化 - */ - protected abstract void doInit(); - - public final void refresh(Config config) { - // 判断是否更新 - if (config.equals(this.config)) { - return; - } - log.info("[refresh][客户端({})发生变化,重新初始化]", getId()); - this.config = config; - // 初始化 - this.init(); - } - - @Override - public Long getId() { - return channelId; - } - - // ============ 支付相关 ========== - - @Override - public final PayOrderRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { - ValidationUtils.validate(reqDTO); - // 执行统一下单 - PayOrderRespDTO resp; - try { - resp = doUnifiedOrder(reqDTO); - } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 - throw ex; - } catch (Throwable ex) { - // 系统异常,则包装成 PayException 异常抛出 - log.error("[unifiedOrder][客户端({}) request({}) 发起支付异常]", - getId(), toJsonString(reqDTO), ex); - throw buildPayException(ex); - } - return resp; - } - - protected abstract PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) - throws Throwable; - - @Override - public final PayOrderRespDTO parseOrderNotify(Map params, String body) { - try { - return doParseOrderNotify(params, body); - } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 - throw ex; - } catch (Throwable ex) { - log.error("[parseOrderNotify][客户端({}) params({}) body({}) 解析失败]", - getId(), params, body, ex); - throw buildPayException(ex); - } - } - - protected abstract PayOrderRespDTO doParseOrderNotify(Map params, String body) - throws Throwable; - - @Override - public final PayOrderRespDTO getOrder(String outTradeNo) { - try { - return doGetOrder(outTradeNo); - } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 - throw ex; - } catch (Throwable ex) { - log.error("[getOrder][客户端({}) outTradeNo({}) 查询支付单异常]", - getId(), outTradeNo, ex); - throw buildPayException(ex); - } - } - - protected abstract PayOrderRespDTO doGetOrder(String outTradeNo) - throws Throwable; - - // ============ 退款相关 ========== - - @Override - public final PayRefundRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) { - ValidationUtils.validate(reqDTO); - // 执行统一退款 - PayRefundRespDTO resp; - try { - resp = doUnifiedRefund(reqDTO); - } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 - throw ex; - } catch (Throwable ex) { - // 系统异常,则包装成 PayException 异常抛出 - log.error("[unifiedRefund][客户端({}) request({}) 发起退款异常]", - getId(), toJsonString(reqDTO), ex); - throw buildPayException(ex); - } - return resp; - } - - protected abstract PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable; - - @Override - public final PayRefundRespDTO parseRefundNotify(Map params, String body) { - try { - return doParseRefundNotify(params, body); - } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 - throw ex; - } catch (Throwable ex) { - log.error("[parseRefundNotify][客户端({}) params({}) body({}) 解析失败]", - getId(), params, body, ex); - throw buildPayException(ex); - } - } - - protected abstract PayRefundRespDTO doParseRefundNotify(Map params, String body) - throws Throwable; - - @Override - public final PayRefundRespDTO getRefund(String outTradeNo, String outRefundNo) { - try { - return doGetRefund(outTradeNo, outRefundNo); - } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 - throw ex; - } catch (Throwable ex) { - log.error("[getRefund][客户端({}) outTradeNo({}) outRefundNo({}) 查询退款单异常]", - getId(), outTradeNo, outRefundNo, ex); - throw buildPayException(ex); - } - } - - protected abstract PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) - throws Throwable; - - @Override - public final PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { - validatePayTransferReqDTO(reqDTO); - PayTransferRespDTO resp; - try { - resp = doUnifiedTransfer(reqDTO); - } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 - throw ex; - } catch (Throwable ex) { - // 系统异常,则包装成 PayException 异常抛出 - log.error("[unifiedTransfer][客户端({}) request({}) 发起转账异常]", - getId(), toJsonString(reqDTO), ex); - throw buildPayException(ex); - } - return resp; - } - private void validatePayTransferReqDTO(PayTransferUnifiedReqDTO reqDTO) { - PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(reqDTO.getType()); - switch (transferType) { - case ALIPAY_BALANCE: { - ValidationUtils.validate(reqDTO, PayTransferTypeEnum.Alipay.class); - break; - } - case WX_BALANCE: { - ValidationUtils.validate(reqDTO, PayTransferTypeEnum.WxPay.class); - break; - } - default: { - throw exception(NOT_IMPLEMENTED); - } - } - } - - @Override - public final PayTransferRespDTO getTransfer(String outTradeNo, PayTransferTypeEnum type) { - try { - return doGetTransfer(outTradeNo, type); - } catch (ServiceException ex) { // 业务异常,都是实现类已经翻译,所以直接抛出即可 - throw ex; - } catch (Throwable ex) { - log.error("[getTransfer][客户端({}) outTradeNo({}) type({}) 查询转账单异常]", - getId(), outTradeNo, type, ex); - throw buildPayException(ex); - } - } - - protected abstract PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) - throws Throwable; - - protected abstract PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) - throws Throwable; - - // ========== 各种工具方法 ========== - - private PayException buildPayException(Throwable ex) { - if (ex instanceof PayException) { - return (PayException) ex; - } - throw new PayException(ex); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/NonePayClientConfig.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/NonePayClientConfig.java deleted file mode 100644 index 48319036c7..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/NonePayClientConfig.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl; - -import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; -import lombok.Data; - -import javax.validation.Validator; - -/** - * 无需任何配置 PayClientConfig 实现类 - * - * @author jason - */ -@Data -public class NonePayClientConfig implements PayClientConfig { - - /** - * 配置名称 - *

- * 如果不加任何属性,JsonUtils.parseObject2 解析会报错,所以暂时加个名称 - */ - private String name; - - public NonePayClientConfig(){ - this.name = "none-config"; - } - - @Override - public void validate(Validator validator) { - // 无任何配置不需要校验 - } -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java deleted file mode 100644 index 0b39587abb..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java +++ /dev/null @@ -1,95 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl; - -import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.ReflectUtil; -import cn.iocoder.yudao.framework.pay.core.client.PayClient; -import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; -import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; -import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.*; -import cn.iocoder.yudao.framework.pay.core.client.impl.mock.MockPayClient; -import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.*; -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; -import lombok.extern.slf4j.Slf4j; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import static cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum.*; - -/** - * 支付客户端的工厂实现类 - * - * @author 芋道源码 - */ -@Slf4j -public class PayClientFactoryImpl implements PayClientFactory { - - /** - * 支付客户端 Map - * - * key:渠道编号 - */ - private final ConcurrentMap> clients = new ConcurrentHashMap<>(); - - /** - * 支付客户端 Class Map - */ - private final Map> clientClass = new ConcurrentHashMap<>(); - - public PayClientFactoryImpl() { - // 微信支付客户端 - clientClass.put(WX_PUB, WxPubPayClient.class); - clientClass.put(WX_LITE, WxLitePayClient.class); - clientClass.put(WX_APP, WxAppPayClient.class); - clientClass.put(WX_BAR, WxBarPayClient.class); - clientClass.put(WX_NATIVE, WxNativePayClient.class); - // 支付包支付客户端 - clientClass.put(ALIPAY_WAP, AlipayWapPayClient.class); - clientClass.put(ALIPAY_QR, AlipayQrPayClient.class); - clientClass.put(ALIPAY_APP, AlipayAppPayClient.class); - clientClass.put(ALIPAY_PC, AlipayPcPayClient.class); - clientClass.put(ALIPAY_BAR, AlipayBarPayClient.class); - // Mock 支付客户端 - clientClass.put(MOCK, MockPayClient.class); - } - - @Override - public void registerPayClientClass(PayChannelEnum channel, Class payClientClass) { - clientClass.put(channel, payClientClass); - } - - @Override - public PayClient getPayClient(Long channelId) { - AbstractPayClient client = clients.get(channelId); - if (client == null) { - log.error("[getPayClient][渠道编号({}) 找不到客户端]", channelId); - } - return client; - } - - @Override - @SuppressWarnings("unchecked") - public void createOrUpdatePayClient(Long channelId, String channelCode, - Config config) { - AbstractPayClient client = (AbstractPayClient) clients.get(channelId); - if (client == null) { - client = this.createPayClient(channelId, channelCode, config); - client.init(); - clients.put(client.getId(), client); - } else { - client.refresh(config); - } - } - - @SuppressWarnings("unchecked") - private AbstractPayClient createPayClient(Long channelId, String channelCode, - Config config) { - PayChannelEnum channelEnum = PayChannelEnum.getByCode(channelCode); - Assert.notNull(channelEnum, String.format("支付渠道(%s) 为空", channelCode)); - Class payClientClass = clientClass.get(channelEnum); - Assert.notNull(payClientClass, String.format("支付渠道(%s) Class 为空", channelCode)); - return (AbstractPayClient) ReflectUtil.newInstance(payClientClass, channelId, config); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java deleted file mode 100644 index 4dcf236755..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java +++ /dev/null @@ -1,342 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; - -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.hutool.core.lang.Assert; -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.http.HttpUtil; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; -import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; -import com.alipay.api.AlipayApiException; -import com.alipay.api.AlipayConfig; -import com.alipay.api.AlipayResponse; -import com.alipay.api.DefaultAlipayClient; -import com.alipay.api.domain.*; -import com.alipay.api.internal.util.AlipaySignature; -import com.alipay.api.request.*; -import com.alipay.api.response.*; -import lombok.Getter; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; - -import java.nio.charset.StandardCharsets; -import java.time.LocalDateTime; -import java.util.Collections; -import java.util.Map; -import java.util.Objects; -import java.util.function.Supplier; - -import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.*; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; -import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_CERTIFICATE; - -/** - * 支付宝抽象类,实现支付宝统一的接口、以及部分实现(退款) - * - * @author jason - */ -@Slf4j -public abstract class AbstractAlipayPayClient extends AbstractPayClient { - - @Getter // 仅用于单测场景 - protected DefaultAlipayClient client; - - public AbstractAlipayPayClient(Long channelId, String channelCode, AlipayPayClientConfig config) { - super(channelId, channelCode, config); - } - - @Override - @SneakyThrows - protected void doInit() { - AlipayConfig alipayConfig = new AlipayConfig(); - BeanUtil.copyProperties(config, alipayConfig, false); - this.client = new DefaultAlipayClient(alipayConfig); - } - - // ============ 支付相关 ========== - - /** - * 构造支付关闭的 {@link PayOrderRespDTO} 对象 - * - * @return 支付关闭的 {@link PayOrderRespDTO} 对象 - */ - protected PayOrderRespDTO buildClosedPayOrderRespDTO(PayOrderUnifiedReqDTO reqDTO, AlipayResponse response) { - Assert.isFalse(response.isSuccess()); - return PayOrderRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), - reqDTO.getOutTradeNo(), response); - } - - @Override - public PayOrderRespDTO doParseOrderNotify(Map params, String body) throws Throwable { - // 1. 校验回调数据 - Map bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8); - AlipaySignature.rsaCheckV1(bodyObj, config.getAlipayPublicKey(), - StandardCharsets.UTF_8.name(), config.getSignType()); - - // 2. 解析订单的状态 - // 额外说明:支付宝不仅仅支付成功会回调,再各种触发支付单数据变化时,都会进行回调,所以这里 status 的解析会写的比较复杂 - Integer status = parseStatus(bodyObj.get("trade_status")); - // 特殊逻辑: 支付宝没有退款成功的状态,所以,如果有退款金额,我们认为是退款成功 - if (MapUtil.getDouble(bodyObj, "refund_fee", 0D) > 0) { - status = PayOrderStatusRespEnum.REFUND.getStatus(); - } - Assert.notNull(status, (Supplier) () -> { - throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", body)); - }); - return PayOrderRespDTO.of(status, bodyObj.get("trade_no"), bodyObj.get("seller_id"), parseTime(params.get("gmt_payment")), - bodyObj.get("out_trade_no"), body); - } - - @Override - protected PayOrderRespDTO doGetOrder(String outTradeNo) throws Throwable { - // 1.1 构建 AlipayTradeRefundModel 请求 - AlipayTradeQueryModel model = new AlipayTradeQueryModel(); - model.setOutTradeNo(outTradeNo); - // 1.2 构建 AlipayTradeQueryRequest 请求 - AlipayTradeQueryRequest request = new AlipayTradeQueryRequest(); - request.setBizModel(model); - AlipayTradeQueryResponse response; - if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { - // 证书模式 - response = client.certificateExecute(request); - } else { - response = client.execute(request); - } - if (!response.isSuccess()) { // 不成功,例如说订单不存在 - return PayOrderRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), - outTradeNo, response); - } - // 2.2 解析订单的状态 - Integer status = parseStatus(response.getTradeStatus()); - Assert.notNull(status, () -> { - throw new IllegalArgumentException(StrUtil.format("body({}) 的 trade_status 不正确", response.getBody())); - }); - return PayOrderRespDTO.of(status, response.getTradeNo(), response.getBuyerUserId(), LocalDateTimeUtil.of(response.getSendPayDate()), - outTradeNo, response); - } - - private static Integer parseStatus(String tradeStatus) { - return Objects.equals("WAIT_BUYER_PAY", tradeStatus) ? PayOrderStatusRespEnum.WAITING.getStatus() - : ObjectUtils.equalsAny(tradeStatus, "TRADE_FINISHED", "TRADE_SUCCESS") ? PayOrderStatusRespEnum.SUCCESS.getStatus() - : Objects.equals("TRADE_CLOSED", tradeStatus) ? PayOrderStatusRespEnum.CLOSED.getStatus() : null; - } - - // ============ 退款相关 ========== - - /** - * 支付宝统一的退款接口 alipay.trade.refund - * - * @param reqDTO 退款请求 request DTO - * @return 退款请求 Response - */ - @Override - protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws AlipayApiException { - // 1.1 构建 AlipayTradeRefundModel 请求 - AlipayTradeRefundModel model = new AlipayTradeRefundModel(); - model.setOutTradeNo(reqDTO.getOutTradeNo()); - model.setOutRequestNo(reqDTO.getOutRefundNo()); - model.setRefundAmount(formatAmount(reqDTO.getRefundPrice())); - model.setRefundReason(reqDTO.getReason()); - // 1.2 构建 AlipayTradePayRequest 请求 - AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); - request.setBizModel(model); - - // 2.1 执行请求 - AlipayTradeRefundResponse response; - if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { // 证书模式 - response = client.certificateExecute(request); - } else { - response = client.execute(request); - } - if (!response.isSuccess()) { - // 当出现 ACQ.SYSTEM_ERROR, 退款可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询 - if (ObjectUtils.equalsAny(response.getSubCode(), "ACQ.SYSTEM_ERROR", "SYSTEM_ERROR")) { - return PayRefundRespDTO.waitingOf(null, reqDTO.getOutRefundNo(), response); - } - return PayRefundRespDTO.failureOf(response.getSubCode(), response.getSubMsg(), reqDTO.getOutRefundNo(), response); - } - // 2.2 创建返回结果 - // 支付宝只要退款调用返回 success,就认为退款成功,不需要回调。具体可见 parseNotify 方法的说明。 - // 另外,支付宝没有退款单号,所以不用设置 - return PayRefundRespDTO.successOf(null, LocalDateTimeUtil.of(response.getGmtRefundPay()), - reqDTO.getOutRefundNo(), response); - } - - @Override - public PayRefundRespDTO doParseRefundNotify(Map params, String body) { - // 补充说明:支付宝退款时,没有回调,这点和微信支付是不同的。并且,退款分成部分退款、和全部退款。 - // ① 部分退款:是会有回调,但是它回调的是订单状态的同步回调,不是退款订单的回调 - // ② 全部退款:Wap 支付有订单状态的同步回调,但是 PC/扫码又没有 - // 所以,这里在解析时,即使是退款导致的订单状态同步,我们也忽略不做为“退款同步”,而是订单的回调。 - // 实际上,支付宝退款只要发起成功,就可以认为退款成功,不需要等待回调。 - throw new UnsupportedOperationException("支付宝无退款回调"); - } - - @Override - protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) throws AlipayApiException { - // 1.1 构建 AlipayTradeFastpayRefundQueryModel 请求 - AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel(); - model.setOutTradeNo(outTradeNo); - model.setOutRequestNo(outRefundNo); - model.setQueryOptions(Collections.singletonList("gmt_refund_pay")); - // 1.2 构建 AlipayTradeFastpayRefundQueryRequest 请求 - AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest(); - request.setBizModel(model); - - // 2.1 执行请求 - AlipayTradeFastpayRefundQueryResponse response; - if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { // 证书模式 - response = client.certificateExecute(request); - } else { - response = client.execute(request); - } - if (!response.isSuccess()) { - // 明确不存在的情况,应该就是失败,可进行关闭 - if (ObjectUtils.equalsAny(response.getSubCode(), "TRADE_NOT_EXIST", "ACQ.TRADE_NOT_EXIST")) { - return PayRefundRespDTO.failureOf(outRefundNo, response); - } - // 可能存在“ACQ.SYSTEM_ERROR”系统错误等情况,所以返回 WAIT 继续等待 - return PayRefundRespDTO.waitingOf(null, outRefundNo, response); - } - // 2.2 创建返回结果 - if (Objects.equals(response.getRefundStatus(), "REFUND_SUCCESS")) { - return PayRefundRespDTO.successOf(null, LocalDateTimeUtil.of(response.getGmtRefundPay()), - outRefundNo, response); - } - return PayRefundRespDTO.waitingOf(null, outRefundNo, response); - } - - @Override - protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws AlipayApiException { - // 1.1 校验公钥类型 必须使用公钥证书模式 - if (!Objects.equals(config.getMode(), MODE_CERTIFICATE)) { - throw exception0(ERROR_CONFIGURATION.getCode(), "支付宝单笔转账必须使用公钥证书模式"); - } - // 1.2 构建 AlipayFundTransUniTransferModel - AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel(); - // ① 通用的参数 - model.setTransAmount(formatAmount(reqDTO.getPrice())); // 转账金额 - model.setOrderTitle(reqDTO.getSubject()); // 转账业务的标题,用于在支付宝用户的账单里显示。 - model.setOutBizNo(reqDTO.getOutTransferNo()); - model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD - model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER - if (reqDTO.getChannelExtras() != null) { - model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras())); - } - // ② 个性化的参数 - Participant payeeInfo = new Participant(); - PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(reqDTO.getType()); - switch (transferType) { - // TODO @jason:是不是不用传递 transferType 参数哈?因为应该已经明确是支付宝啦? - // @芋艿。 是不是还要考虑转账到银行卡。所以传 transferType 但是转账到银行卡不知道要如何测试?? - case ALIPAY_BALANCE: { - payeeInfo.setIdentityType("ALIPAY_LOGON_ID"); - payeeInfo.setIdentity(reqDTO.getAlipayLogonId()); // 支付宝登录号 - payeeInfo.setName(reqDTO.getUserName()); // 支付宝账号姓名 - model.setPayeeInfo(payeeInfo); - break; - } - case BANK_CARD: { - payeeInfo.setIdentityType("BANKCARD_ACCOUNT"); - // TODO 待实现 - throw exception(NOT_IMPLEMENTED); - } - default: { - throw exception0(BAD_REQUEST.getCode(), "不正确的转账类型: {}", transferType); - } - } - // 1.3 构建 AlipayFundTransUniTransferRequest - AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest(); - request.setBizModel(model); - // 执行请求 - AlipayFundTransUniTransferResponse response = client.certificateExecute(request); - // 处理结果 - if (!response.isSuccess()) { - // 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询,或相同 outBizNo 重新发起转账 - // 发现 outBizNo 相同 两次请求参数相同. 会返回 "PAYMENT_INFO_INCONSISTENCY", 不知道哪里的问题. 暂时返回 WAIT. 后续job 会轮询 - if (ObjectUtils.equalsAny(response.getSubCode(),"PAYMENT_INFO_INCONSISTENCY", "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) { - return PayTransferRespDTO.waitingOf(null, reqDTO.getOutTransferNo(), response); - } - return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), - reqDTO.getOutTransferNo(), response); - } else { - if (ObjectUtils.equalsAny(response.getStatus(), "REFUND", "FAIL")) { // 转账到银行卡会出现 "REFUND" "FAIL" - return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), - reqDTO.getOutTransferNo(), response); - } - if (Objects.equals(response.getStatus(), "DEALING")) { // 转账到银行卡会出现 "DEALING" 处理中 - return PayTransferRespDTO.dealingOf(response.getOrderId(), reqDTO.getOutTransferNo(), response); - } - return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()), - response.getOutBizNo(), response); - } - - } - - @Override - protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) throws Throwable { - // 1.1 构建 AlipayFundTransCommonQueryModel - AlipayFundTransCommonQueryModel model = new AlipayFundTransCommonQueryModel(); - model.setProductCode(type == PayTransferTypeEnum.BANK_CARD ? "TRANS_BANKCARD_NO_PWD" : "TRANS_ACCOUNT_NO_PWD"); - model.setBizScene("DIRECT_TRANSFER"); //业务场景 - model.setOutBizNo(outTradeNo); - // 1.2 构建 AlipayFundTransCommonQueryRequest - AlipayFundTransCommonQueryRequest request = new AlipayFundTransCommonQueryRequest(); - request.setBizModel(model); - - // 2.1 执行请求 - AlipayFundTransCommonQueryResponse response; - if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { // 证书模式 - response = client.certificateExecute(request); - } else { - response = client.execute(request); - } - // 2.2 处理返回结果 - if (response.isSuccess()) { - if (ObjectUtils.equalsAny(response.getStatus(), "REFUND", "FAIL")) { // 转账到银行卡会出现 "REFUND" "FAIL" - return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), - outTradeNo, response); - } - if (Objects.equals(response.getStatus(), "DEALING")) { // 转账到银行卡会出现 "DEALING" 处理中 - return PayTransferRespDTO.dealingOf(response.getOrderId(), outTradeNo, response); - } - return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getPayDate()), - response.getOutBizNo(), response); - } else { - // 当出现 SYSTEM_ERROR, 转账可能成功也可能失败。 返回 WAIT 状态. 后续 job 会轮询, 或相同 outBizNo 重新发起转账 - // 当出现 ORDER_NOT_EXIST 可能是转账还在处理中,也可能是转账处理失败. 返回 WAIT 状态. 后续 job 会轮询, 或相同 outBizNo 重新发起转账 - if (ObjectUtils.equalsAny(response.getSubCode(), "ORDER_NOT_EXIST", "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) { - return PayTransferRespDTO.waitingOf(null, outTradeNo, response); - } - return PayTransferRespDTO.closedOf(response.getSubCode(), response.getSubMsg(), - outTradeNo, response); - } - } - - // ========== 各种工具方法 ========== - - protected String formatAmount(Integer amount) { - return String.valueOf(amount / 100.0); - } - - protected String formatTime(LocalDateTime time) { - return LocalDateTimeUtil.format(time, NORM_DATETIME_FORMATTER); - } - - protected LocalDateTime parseTime(String str) { - return LocalDateTimeUtil.parse(str, NORM_DATETIME_FORMATTER); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java deleted file mode 100644 index 4e5a37e9de..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java +++ /dev/null @@ -1,59 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; - -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import com.alipay.api.AlipayApiException; -import com.alipay.api.domain.AlipayTradeAppPayModel; -import com.alipay.api.request.AlipayTradeAppPayRequest; -import com.alipay.api.response.AlipayTradeAppPayResponse; -import lombok.extern.slf4j.Slf4j; - -/** - * 支付宝【App 支付】的 PayClient 实现类 - * - * 文档:App 支付 - * - * // TODO 芋艿:未详细测试,因为手头没 App - * - * @author 芋道源码 - */ -@Slf4j -public class AlipayAppPayClient extends AbstractAlipayPayClient { - - public AlipayAppPayClient(Long channelId, AlipayPayClientConfig config) { - super(channelId, PayChannelEnum.ALIPAY_APP.getCode(), config); - } - - @Override - public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { - // 1.1 构建 AlipayTradeAppPayModel 请求 - AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); - // ① 通用的参数 - model.setOutTradeNo(reqDTO.getOutTradeNo()); - model.setSubject(reqDTO.getSubject()); - model.setBody(reqDTO.getBody() + "test"); - model.setTotalAmount(formatAmount(reqDTO.getPrice())); - model.setTimeExpire(formatTime(reqDTO.getExpireTime())); - model.setProductCode("QUICK_MSECURITY_PAY"); // 销售产品码:无线快捷支付产品 - // ② 个性化的参数【无】 - // ③ 支付宝扫码支付只有一种展示 - String displayMode = PayOrderDisplayModeEnum.APP.getMode(); - - // 1.2 构建 AlipayTradePrecreateRequest 请求 - AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); - request.setBizModel(model); - request.setNotifyUrl(reqDTO.getNotifyUrl()); - request.setReturnUrl(reqDTO.getReturnUrl()); - - // 2.1 执行请求 - AlipayTradeAppPayResponse response = client.sdkExecute(request); - // 2.2 处理结果 - if (!response.isSuccess()) { - return buildClosedPayOrderRespDTO(reqDTO, response); - } - return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), - reqDTO.getOutTradeNo(), response); - } -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java deleted file mode 100644 index 1f90d6b58e..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java +++ /dev/null @@ -1,85 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; - -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import com.alipay.api.AlipayApiException; -import com.alipay.api.domain.AlipayTradePayModel; -import com.alipay.api.request.AlipayTradePayRequest; -import com.alipay.api.response.AlipayTradePayResponse; -import lombok.extern.slf4j.Slf4j; - -import java.time.LocalDateTime; -import java.util.Objects; - -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; -import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_CERTIFICATE; - -/** - * 支付宝【条码支付】的 PayClient 实现类 - * - * 文档:当面付 - * - * @author 芋道源码 - */ -@Slf4j -public class AlipayBarPayClient extends AbstractAlipayPayClient { - - public AlipayBarPayClient(Long channelId, AlipayPayClientConfig config) { - super(channelId, PayChannelEnum.ALIPAY_BAR.getCode(), config); - } - - @Override - public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { - String authCode = MapUtil.getStr(reqDTO.getChannelExtras(), "auth_code"); - if (StrUtil.isEmpty(authCode)) { - throw exception0(BAD_REQUEST.getCode(), "条形码不能为空"); - } - - // 1.1 构建 AlipayTradePayModel 请求 - AlipayTradePayModel model = new AlipayTradePayModel(); - // ① 通用的参数 - model.setOutTradeNo(reqDTO.getOutTradeNo()); - model.setSubject(reqDTO.getSubject()); - model.setBody(reqDTO.getBody()); - model.setTotalAmount(formatAmount(reqDTO.getPrice())); - model.setScene("bar_code"); // 当面付条码支付场景 - // ② 个性化的参数 - model.setAuthCode(authCode); - // ③ 支付宝条码支付只有一种展示 - String displayMode = PayOrderDisplayModeEnum.BAR_CODE.getMode(); - - // 1.2 构建 AlipayTradePayRequest 请求 - AlipayTradePayRequest request = new AlipayTradePayRequest(); - request.setBizModel(model); - request.setNotifyUrl(reqDTO.getNotifyUrl()); - request.setReturnUrl(reqDTO.getReturnUrl()); - - // 2.1 执行请求 - AlipayTradePayResponse response; - if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { - // 证书模式 - response = client.certificateExecute(request); - } else { - response = client.execute(request); - } - // 2.2 处理结果 - if (!response.isSuccess()) { - return buildClosedPayOrderRespDTO(reqDTO, response); - } - if ("10000".equals(response.getCode())) { // 免密支付 - LocalDateTime successTime = LocalDateTimeUtil.of(response.getGmtPayment()); - return PayOrderRespDTO.successOf(response.getTradeNo(), response.getBuyerUserId(), successTime, - response.getOutTradeNo(), response) - .setDisplayMode(displayMode).setDisplayContent(""); - } - // 大额支付,需要用户输入密码,所以返回 waiting。此时,前端一般会进行轮询 - return PayOrderRespDTO.waitingOf(displayMode, "", - reqDTO.getOutTradeNo(), response); - } -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayClientConfig.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayClientConfig.java deleted file mode 100644 index 066ff0122d..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayClientConfig.java +++ /dev/null @@ -1,109 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; - -import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; -import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; -import lombok.Data; - -import javax.validation.ConstraintViolation; -import javax.validation.Validator; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import java.util.Set; - -/** - * 支付宝的 PayClientConfig 实现类 - * 属性主要来自 {@link com.alipay.api.AlipayConfig} 的必要属性 - * - * @author 芋道源码 - */ -@Data -public class AlipayPayClientConfig implements PayClientConfig { - - /** - * 公钥类型 - 公钥模式 - */ - public static final Integer MODE_PUBLIC_KEY = 1; - /** - * 公钥类型 - 证书模式 - */ - public static final Integer MODE_CERTIFICATE = 2; - - /** - * 签名算法类型 - RSA - */ - public static final String SIGN_TYPE_DEFAULT = "RSA2"; - - /** - * 网关地址 - * - * 1. 生产环境 - * 2. 沙箱环境 - */ - @NotBlank(message = "网关地址不能为空", groups = {ModePublicKey.class, ModeCertificate.class}) - private String serverUrl; - - /** - * 开放平台上创建的应用的 ID - */ - @NotBlank(message = "开放平台上创建的应用的 ID不能为空", groups = {ModePublicKey.class, ModeCertificate.class}) - private String appId; - - /** - * 签名算法类型,推荐:RSA2 - *

- * {@link #SIGN_TYPE_DEFAULT} - */ - @NotBlank(message = "签名算法类型不能为空", groups = {ModePublicKey.class, ModeCertificate.class}) - private String signType; - - /** - * 公钥类型 - * 1. {@link #MODE_PUBLIC_KEY} 情况,privateKey + alipayPublicKey - * 2. {@link #MODE_CERTIFICATE} 情况,appCertContent + alipayPublicCertContent + rootCertContent - */ - @NotNull(message = "公钥类型不能为空", groups = {ModePublicKey.class, ModeCertificate.class}) - private Integer mode; - - // ========== 公钥模式 ========== - /** - * 商户私钥 - */ - @NotBlank(message = "商户私钥不能为空", groups = {ModePublicKey.class}) - private String privateKey; - - /** - * 支付宝公钥字符串 - */ - @NotBlank(message = "支付宝公钥字符串不能为空", groups = {ModePublicKey.class}) - private String alipayPublicKey; - - // ========== 证书模式 ========== - /** - * 指定商户公钥应用证书内容字符串 - */ - @NotBlank(message = "指定商户公钥应用证书内容不能为空", groups = {ModeCertificate.class}) - private String appCertContent; - /** - * 指定支付宝公钥证书内容字符串 - */ - @NotBlank(message = "指定支付宝公钥证书内容不能为空", groups = {ModeCertificate.class}) - private String alipayPublicCertContent; - /** - * 指定根证书内容字符串 - */ - @NotBlank(message = "指定根证书内容字符串不能为空", groups = {ModeCertificate.class}) - private String rootCertContent; - - public interface ModePublicKey { - } - - public interface ModeCertificate { - } - - @Override - public void validate(Validator validator) { - ValidationUtils.validate(validator, this, - MODE_PUBLIC_KEY.equals(this.getMode()) ? ModePublicKey.class : ModeCertificate.class); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java deleted file mode 100644 index 6dbd19bef3..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java +++ /dev/null @@ -1,69 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; - -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.http.Method; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import com.alipay.api.AlipayApiException; -import com.alipay.api.domain.AlipayTradePagePayModel; -import com.alipay.api.request.AlipayTradePagePayRequest; -import com.alipay.api.response.AlipayTradePagePayResponse; -import lombok.extern.slf4j.Slf4j; - -import java.util.Objects; - -/** - * 支付宝【PC 网站】的 PayClient 实现类 - * - * 文档:电脑网站支付 - * - * @author XGD - */ -@Slf4j -public class AlipayPcPayClient extends AbstractAlipayPayClient { - - public AlipayPcPayClient(Long channelId, AlipayPayClientConfig config) { - super(channelId, PayChannelEnum.ALIPAY_PC.getCode(), config); - } - - @Override - public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { - // 1.1 构建 AlipayTradePagePayModel 请求 - AlipayTradePagePayModel model = new AlipayTradePagePayModel(); - // ① 通用的参数 - model.setOutTradeNo(reqDTO.getOutTradeNo()); - model.setSubject(reqDTO.getSubject()); - model.setBody(reqDTO.getBody()); - model.setTotalAmount(formatAmount(reqDTO.getPrice())); - model.setTimeExpire(formatTime(reqDTO.getExpireTime())); - model.setProductCode("FAST_INSTANT_TRADE_PAY"); // 销售产品码. 目前 PC 支付场景下仅支持 FAST_INSTANT_TRADE_PAY - // ② 个性化的参数 - // 如果想弄更多个性化的参数,可参考 https://www.pingxx.com/api/支付渠道 extra 参数说明.html 的 alipay_pc_direct 部分进行拓展 - model.setQrPayMode("2"); // 跳转模式 - 订单码,效果参见:https://help.pingxx.com/article/1137360/ - // ③ 支付宝 PC 支付有两种展示模式:FORM、URL - String displayMode = ObjectUtil.defaultIfNull(reqDTO.getDisplayMode(), - PayOrderDisplayModeEnum.URL.getMode()); - - // 1.2 构建 AlipayTradePagePayRequest 请求 - AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); - request.setBizModel(model); - request.setNotifyUrl(reqDTO.getNotifyUrl()); - request.setReturnUrl(reqDTO.getReturnUrl()); - - // 2.1 执行请求 - AlipayTradePagePayResponse response; - if (Objects.equals(displayMode, PayOrderDisplayModeEnum.FORM.getMode())) { - response = client.pageExecute(request, Method.POST.name()); // 需要特殊使用 POST 请求 - } else { - response = client.pageExecute(request, Method.GET.name()); - } - // 2.2 处理结果 - if (!response.isSuccess()) { - return buildClosedPayOrderRespDTO(reqDTO, response); - } - return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), - reqDTO.getOutTradeNo(), response); - } -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java deleted file mode 100644 index bb3ad17713..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java +++ /dev/null @@ -1,66 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; - -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import com.alipay.api.AlipayApiException; -import com.alipay.api.domain.AlipayTradePrecreateModel; -import com.alipay.api.request.AlipayTradePrecreateRequest; -import com.alipay.api.response.AlipayTradePrecreateResponse; -import lombok.extern.slf4j.Slf4j; - -import java.util.Objects; - -import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_CERTIFICATE; - -/** - * 支付宝【扫码支付】的 PayClient 实现类 - * - * 文档:扫码支付 - * - * @author 芋道源码 - */ -@Slf4j -public class AlipayQrPayClient extends AbstractAlipayPayClient { - - public AlipayQrPayClient(Long channelId, AlipayPayClientConfig config) { - super(channelId, PayChannelEnum.ALIPAY_QR.getCode(), config); - } - - @Override - public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { - // 1.1 构建 AlipayTradePrecreateModel 请求 - AlipayTradePrecreateModel model = new AlipayTradePrecreateModel(); - // ① 通用的参数 - model.setOutTradeNo(reqDTO.getOutTradeNo()); - model.setSubject(reqDTO.getSubject()); - model.setBody(reqDTO.getBody()); - model.setTotalAmount(formatAmount(reqDTO.getPrice())); - model.setProductCode("FACE_TO_FACE_PAYMENT"); // 销售产品码. 目前扫码支付场景下仅支持 FACE_TO_FACE_PAYMENT - // ② 个性化的参数【无】 - // ③ 支付宝扫码支付只有一种展示,考虑到前端可能希望二维码扫描后,手机打开 - String displayMode = PayOrderDisplayModeEnum.QR_CODE.getMode(); - - // 1.2 构建 AlipayTradePrecreateRequest 请求 - AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest(); - request.setBizModel(model); - request.setNotifyUrl(reqDTO.getNotifyUrl()); - request.setReturnUrl(reqDTO.getReturnUrl()); - - // 2.1 执行请求 - AlipayTradePrecreateResponse response; - if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { - // 证书模式 - response = client.certificateExecute(request); - } else { - response = client.execute(request); - } - // 2.2 处理结果 - if (!response.isSuccess()) { - return buildClosedPayOrderRespDTO(reqDTO, response); - } - return PayOrderRespDTO.waitingOf(displayMode, response.getQrCode(), - reqDTO.getOutTradeNo(), response); - } -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java deleted file mode 100644 index f9dccf5a7e..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java +++ /dev/null @@ -1,58 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; - -import cn.hutool.http.Method; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import com.alipay.api.AlipayApiException; -import com.alipay.api.domain.AlipayTradeWapPayModel; -import com.alipay.api.request.AlipayTradeWapPayRequest; -import com.alipay.api.response.AlipayTradeWapPayResponse; -import lombok.extern.slf4j.Slf4j; - -/** - * 支付宝【Wap 网站】的 PayClient 实现类 - * - * 文档:手机网站支付接口 - * - * @author 芋道源码 - */ -@Slf4j -public class AlipayWapPayClient extends AbstractAlipayPayClient { - - public AlipayWapPayClient(Long channelId, AlipayPayClientConfig config) { - super(channelId, PayChannelEnum.ALIPAY_WAP.getCode(), config); - } - - @Override - public PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws AlipayApiException { - // 1.1 构建 AlipayTradeWapPayModel 请求 - AlipayTradeWapPayModel model = new AlipayTradeWapPayModel(); - // ① 通用的参数 - model.setOutTradeNo(reqDTO.getOutTradeNo()); - model.setSubject(reqDTO.getSubject()); - model.setBody(reqDTO.getBody()); - model.setTotalAmount(formatAmount(reqDTO.getPrice())); - model.setProductCode("QUICK_WAP_PAY"); // 销售产品码. 目前 Wap 支付场景下仅支持 QUICK_WAP_PAY - // ② 个性化的参数【无】 - // ③ 支付宝 Wap 支付只有一种展示:URL - String displayMode = PayOrderDisplayModeEnum.URL.getMode(); - - // 1.2 构建 AlipayTradeWapPayRequest 请求 - AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest(); - request.setBizModel(model); - request.setNotifyUrl(reqDTO.getNotifyUrl()); - request.setReturnUrl(reqDTO.getReturnUrl()); - model.setQuitUrl(reqDTO.getReturnUrl()); - - // 2.1 执行请求 - AlipayTradeWapPayResponse response = client.pageExecute(request, Method.GET.name()); - // 2.2 处理结果 - if (!response.isSuccess()) { - return buildClosedPayOrderRespDTO(reqDTO, response); - } - return PayOrderRespDTO.waitingOf(displayMode, response.getBody(), - reqDTO.getOutTradeNo(), response); - } -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java deleted file mode 100644 index 1ad1ad7134..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java +++ /dev/null @@ -1,80 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.mock; - -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; -import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; -import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; - -import java.time.LocalDateTime; -import java.util.Map; - -/** - * 模拟支付的 PayClient 实现类 - * - * 模拟支付返回结果都是成功,方便大家日常流畅 - * - * @author jason - */ -public class MockPayClient extends AbstractPayClient { - - private static final String MOCK_RESP_SUCCESS_DATA = "MOCK_SUCCESS"; - - public MockPayClient(Long channelId, NonePayClientConfig config) { - super(channelId, PayChannelEnum.MOCK.getCode(), config); - } - - @Override - protected void doInit() { - } - - @Override - protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { - return PayOrderRespDTO.successOf("MOCK-P-" + reqDTO.getOutTradeNo(), "", LocalDateTime.now(), - reqDTO.getOutTradeNo(), MOCK_RESP_SUCCESS_DATA); - } - - @Override - protected PayOrderRespDTO doGetOrder(String outTradeNo) { - return PayOrderRespDTO.successOf("MOCK-P-" + outTradeNo, "", LocalDateTime.now(), - outTradeNo, MOCK_RESP_SUCCESS_DATA); - } - - @Override - protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { - return PayRefundRespDTO.successOf("MOCK-R-" + reqDTO.getOutRefundNo(), LocalDateTime.now(), - reqDTO.getOutRefundNo(), MOCK_RESP_SUCCESS_DATA); - } - - @Override - protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) { - return PayRefundRespDTO.successOf("MOCK-R-" + outRefundNo, LocalDateTime.now(), - outRefundNo, MOCK_RESP_SUCCESS_DATA); - } - - @Override - protected PayRefundRespDTO doParseRefundNotify(Map params, String body) { - throw new UnsupportedOperationException("模拟支付无退款回调"); - } - - @Override - protected PayOrderRespDTO doParseOrderNotify(Map params, String body) { - throw new UnsupportedOperationException("模拟支付无支付回调"); - } - - @Override - protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { - throw new UnsupportedOperationException("待实现"); - } - - @Override - protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) { - throw new UnsupportedOperationException("待实现"); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java deleted file mode 100644 index a8c50cf1c4..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java +++ /dev/null @@ -1,484 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; - -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.codec.Base64; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.hutool.core.date.TemporalAccessorUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.io.FileUtils; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; -import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum; -import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result; -import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; -import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; -import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result; -import com.github.binarywang.wxpay.bean.request.*; -import com.github.binarywang.wxpay.bean.result.*; -import com.github.binarywang.wxpay.config.WxPayConfig; -import com.github.binarywang.wxpay.exception.WxPayException; -import com.github.binarywang.wxpay.service.WxPayService; -import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; -import lombok.extern.slf4j.Slf4j; - -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.Map; -import java.util.Objects; - -import static cn.hutool.core.date.DatePattern.*; -import static cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig.API_VERSION_V2; - -/** - * 微信支付抽象类,实现微信统一的接口、以及部分实现(退款) - * - * @author 遇到源码 - */ -@Slf4j -public abstract class AbstractWxPayClient extends AbstractPayClient { - - protected WxPayService client; - - public AbstractWxPayClient(Long channelId, String channelCode, WxPayClientConfig config) { - super(channelId, channelCode, config); - } - - /** - * 初始化 client 客户端 - * - * @param tradeType 交易类型 - */ - protected void doInit(String tradeType) { - // 创建 config 配置 - WxPayConfig payConfig = new WxPayConfig(); - BeanUtil.copyProperties(config, payConfig, "keyContent", "privateKeyContent", "privateCertContent"); - payConfig.setTradeType(tradeType); - // weixin-pay-java 无法设置内容,只允许读取文件,所以这里要创建临时文件来解决 - if (Base64.isBase64(config.getKeyContent())) { - payConfig.setKeyPath(FileUtils.createTempFile(Base64.decode(config.getKeyContent())).getPath()); - } - if (StrUtil.isNotEmpty(config.getPrivateKeyContent())) { - payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath()); - } - if (StrUtil.isNotEmpty(config.getPrivateCertContent())) { - payConfig.setPrivateCertPath(FileUtils.createTempFile(config.getPrivateCertContent()).getPath()); - } -// payConfig.setCertSerialNo(); - - // 创建 client 客户端 - client = new WxPayServiceImpl(); - client.setConfig(payConfig); - } - - // ============ 支付相关 ========== - - @Override - protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws Exception { - try { - switch (config.getApiVersion()) { - case API_VERSION_V2: - return doUnifiedOrderV2(reqDTO); - case WxPayClientConfig.API_VERSION_V3: - return doUnifiedOrderV3(reqDTO); - default: - throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); - } - } catch (WxPayException e) { - String errorCode = getErrorCode(e); - String errorMessage = getErrorMessage(e); - return PayOrderRespDTO.closedOf(errorCode, errorMessage, - reqDTO.getOutTradeNo(), e.getXmlString()); - } - } - - /** - * 【V2】调用支付渠道,统一下单 - * - * @param reqDTO 下单信息 - * @return 各支付渠道的返回结果 - */ - protected abstract PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) - throws Exception; - - /** - * 【V3】调用支付渠道,统一下单 - * - * @param reqDTO 下单信息 - * @return 各支付渠道的返回结果 - */ - protected abstract PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) - throws WxPayException; - - /** - * 【V2】创建微信下单请求 - * - * @param reqDTO 下信息 - * @return 下单请求 - */ - protected WxPayUnifiedOrderRequest buildPayUnifiedOrderRequestV2(PayOrderUnifiedReqDTO reqDTO) { - return WxPayUnifiedOrderRequest.newBuilder() - .outTradeNo(reqDTO.getOutTradeNo()) - .body(reqDTO.getSubject()) - .detail(reqDTO.getBody()) - .totalFee(reqDTO.getPrice()) // 单位分 - .timeExpire(formatDateV2(reqDTO.getExpireTime())) - .spbillCreateIp(reqDTO.getUserIp()) - .notifyUrl(reqDTO.getNotifyUrl()) - .build(); - } - - /** - * 【V3】创建微信下单请求 - * - * @param reqDTO 下信息 - * @return 下单请求 - */ - protected WxPayUnifiedOrderV3Request buildPayUnifiedOrderRequestV3(PayOrderUnifiedReqDTO reqDTO) { - WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); - request.setOutTradeNo(reqDTO.getOutTradeNo()); - request.setDescription(reqDTO.getSubject()); - request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getPrice())); // 单位分 - request.setTimeExpire(formatDateV3(reqDTO.getExpireTime())); - request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp())); - request.setNotifyUrl(reqDTO.getNotifyUrl()); - return request; - } - - @Override - public PayOrderRespDTO doParseOrderNotify(Map params, String body) throws WxPayException { - switch (config.getApiVersion()) { - case API_VERSION_V2: - return doParseOrderNotifyV2(body); - case WxPayClientConfig.API_VERSION_V3: - return doParseOrderNotifyV3(body); - default: - throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); - } - } - - private PayOrderRespDTO doParseOrderNotifyV2(String body) throws WxPayException { - // 1. 解析回调 - WxPayOrderNotifyResult response = client.parseOrderNotifyResult(body); - // 2. 构建结果 - // V2 微信支付的回调,只有 SUCCESS 支付成功、CLOSED 支付失败两种情况,无需像支付宝一样解析的比较复杂 - Integer status = Objects.equals(response.getResultCode(), "SUCCESS") ? - PayOrderStatusRespEnum.SUCCESS.getStatus() : PayOrderStatusRespEnum.CLOSED.getStatus(); - return PayOrderRespDTO.of(status, response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()), - response.getOutTradeNo(), body); - } - - private PayOrderRespDTO doParseOrderNotifyV3(String body) throws WxPayException { - // 1. 解析回调 - WxPayNotifyV3Result response = client.parseOrderNotifyV3Result(body, null); - WxPayNotifyV3Result.DecryptNotifyResult result = response.getResult(); - // 2. 构建结果 - Integer status = parseStatus(result.getTradeState()); - String openid = result.getPayer() != null ? result.getPayer().getOpenid() : null; - return PayOrderRespDTO.of(status, result.getTransactionId(), openid, parseDateV3(result.getSuccessTime()), - result.getOutTradeNo(), body); - } - - @Override - protected PayOrderRespDTO doGetOrder(String outTradeNo) throws Throwable { - try { - switch (config.getApiVersion()) { - case API_VERSION_V2: - return doGetOrderV2(outTradeNo); - case WxPayClientConfig.API_VERSION_V3: - return doGetOrderV3(outTradeNo); - default: - throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); - } - } catch (WxPayException e) { - if (ObjectUtils.equalsAny(e.getErrCode(), "ORDERNOTEXIST", "ORDER_NOT_EXIST")) { - String errorCode = getErrorCode(e); - String errorMessage = getErrorMessage(e); - return PayOrderRespDTO.closedOf(errorCode, errorMessage, - outTradeNo, e.getXmlString()); - } - throw e; - } - } - - private PayOrderRespDTO doGetOrderV2(String outTradeNo) throws WxPayException { - // 构建 WxPayUnifiedOrderRequest 对象 - WxPayOrderQueryRequest request = WxPayOrderQueryRequest.newBuilder() - .outTradeNo(outTradeNo).build(); - // 执行请求 - WxPayOrderQueryResult response = client.queryOrder(request); - - // 转换结果 - Integer status = parseStatus(response.getTradeState()); - return PayOrderRespDTO.of(status, response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()), - outTradeNo, response); - } - - private PayOrderRespDTO doGetOrderV3(String outTradeNo) throws WxPayException { - // 构建 WxPayUnifiedOrderRequest 对象 - WxPayOrderQueryV3Request request = new WxPayOrderQueryV3Request() - .setOutTradeNo(outTradeNo); - // 执行请求 - WxPayOrderQueryV3Result response = client.queryOrderV3(request); - - // 转换结果 - Integer status = parseStatus(response.getTradeState()); - String openid = response.getPayer() != null ? response.getPayer().getOpenid() : null; - return PayOrderRespDTO.of(status, response.getTransactionId(), openid, parseDateV3(response.getSuccessTime()), - outTradeNo, response); - } - - private static Integer parseStatus(String tradeState) { - switch (tradeState) { - case "NOTPAY": - case "USERPAYING": // 支付中,等待用户输入密码(条码支付独有) - return PayOrderStatusRespEnum.WAITING.getStatus(); - case "SUCCESS": - return PayOrderStatusRespEnum.SUCCESS.getStatus(); - case "REFUND": - return PayOrderStatusRespEnum.REFUND.getStatus(); - case "CLOSED": - case "REVOKED": // 已撤销(刷卡支付独有) - case "PAYERROR": // 支付失败(其它原因,如银行返回失败) - return PayOrderStatusRespEnum.CLOSED.getStatus(); - default: - throw new IllegalArgumentException(StrUtil.format("未知的支付状态({})", tradeState)); - } - } - - // ============ 退款相关 ========== - - @Override - protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable { - try { - switch (config.getApiVersion()) { - case API_VERSION_V2: - return doUnifiedRefundV2(reqDTO); - case WxPayClientConfig.API_VERSION_V3: - return doUnifiedRefundV3(reqDTO); - default: - throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); - } - } catch (WxPayException e) { - String errorCode = getErrorCode(e); - String errorMessage = getErrorMessage(e); - return PayRefundRespDTO.failureOf(errorCode, errorMessage, - reqDTO.getOutTradeNo(), e.getXmlString()); - } - } - - private PayRefundRespDTO doUnifiedRefundV2(PayRefundUnifiedReqDTO reqDTO) throws Throwable { - // 1. 构建 WxPayRefundRequest 请求 - WxPayRefundRequest request = new WxPayRefundRequest() - .setOutTradeNo(reqDTO.getOutTradeNo()) - .setOutRefundNo(reqDTO.getOutRefundNo()) - .setRefundFee(reqDTO.getRefundPrice()) - .setRefundDesc(reqDTO.getReason()) - .setTotalFee(reqDTO.getPayPrice()) - .setNotifyUrl(reqDTO.getNotifyUrl()); - // 2.1 执行请求 - WxPayRefundResult response = client.refundV2(request); - // 2.2 创建返回结果 - if (Objects.equals("SUCCESS", response.getResultCode())) { // V2 情况下,不直接返回退款成功,而是等待异步通知 - return PayRefundRespDTO.waitingOf(response.getRefundId(), - reqDTO.getOutRefundNo(), response); - } - return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response); - } - - private PayRefundRespDTO doUnifiedRefundV3(PayRefundUnifiedReqDTO reqDTO) throws Throwable { - // 1. 构建 WxPayRefundRequest 请求 - WxPayRefundV3Request request = new WxPayRefundV3Request() - .setOutTradeNo(reqDTO.getOutTradeNo()) - .setOutRefundNo(reqDTO.getOutRefundNo()) - .setAmount(new WxPayRefundV3Request.Amount().setRefund(reqDTO.getRefundPrice()) - .setTotal(reqDTO.getPayPrice()).setCurrency("CNY")) - .setReason(reqDTO.getReason()) - .setNotifyUrl(reqDTO.getNotifyUrl()); - // 2.1 执行请求 - WxPayRefundV3Result response = client.refundV3(request); - // 2.2 创建返回结果 - if (Objects.equals("SUCCESS", response.getStatus())) { - return PayRefundRespDTO.successOf(response.getRefundId(), parseDateV3(response.getSuccessTime()), - reqDTO.getOutRefundNo(), response); - } - if (Objects.equals("PROCESSING", response.getStatus())) { - return PayRefundRespDTO.waitingOf(response.getRefundId(), - reqDTO.getOutRefundNo(), response); - } - return PayRefundRespDTO.failureOf(reqDTO.getOutRefundNo(), response); - } - - @Override - public PayRefundRespDTO doParseRefundNotify(Map params, String body) throws WxPayException { - switch (config.getApiVersion()) { - case API_VERSION_V2: - return doParseRefundNotifyV2(body); - case WxPayClientConfig.API_VERSION_V3: - return parseRefundNotifyV3(body); - default: - throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); - } - } - - private PayRefundRespDTO doParseRefundNotifyV2(String body) throws WxPayException { - // 1. 解析回调 - WxPayRefundNotifyResult response = client.parseRefundNotifyResult(body); - WxPayRefundNotifyResult.ReqInfo result = response.getReqInfo(); - // 2. 构建结果 - if (Objects.equals("SUCCESS", result.getRefundStatus())) { - return PayRefundRespDTO.successOf(result.getRefundId(), parseDateV2B(result.getSuccessTime()), - result.getOutRefundNo(), response); - } - return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response); - } - - private PayRefundRespDTO parseRefundNotifyV3(String body) throws WxPayException { - // 1. 解析回调 - WxPayRefundNotifyV3Result response = client.parseRefundNotifyV3Result(body, null); - WxPayRefundNotifyV3Result.DecryptNotifyResult result = response.getResult(); - // 2. 构建结果 - if (Objects.equals("SUCCESS", result.getRefundStatus())) { - return PayRefundRespDTO.successOf(result.getRefundId(), parseDateV3(result.getSuccessTime()), - result.getOutRefundNo(), response); - } - return PayRefundRespDTO.failureOf(result.getOutRefundNo(), response); - } - - @Override - protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) throws WxPayException { - try { - switch (config.getApiVersion()) { - case API_VERSION_V2: - return doGetRefundV2(outTradeNo, outRefundNo); - case WxPayClientConfig.API_VERSION_V3: - return doGetRefundV3(outTradeNo, outRefundNo); - default: - throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); - } - } catch (WxPayException e) { - if (ObjectUtils.equalsAny(e.getErrCode(), "REFUNDNOTEXIST", "RESOURCE_NOT_EXISTS")) { - String errorCode = getErrorCode(e); - String errorMessage = getErrorMessage(e); - return PayRefundRespDTO.failureOf(errorCode, errorMessage, - outRefundNo, e.getXmlString()); - } - throw e; - } - } - - private PayRefundRespDTO doGetRefundV2(String outTradeNo, String outRefundNo) throws WxPayException { - // 1. 构建 WxPayRefundRequest 请求 - WxPayRefundQueryRequest request = WxPayRefundQueryRequest.newBuilder() - .outTradeNo(outTradeNo) - .outRefundNo(outRefundNo) - .build(); - // 2.1 执行请求 - WxPayRefundQueryResult response = client.refundQuery(request); - // 2.2 创建返回结果 - if (!Objects.equals("SUCCESS", response.getResultCode())) { - return PayRefundRespDTO.waitingOf(null, - outRefundNo, response); - } - WxPayRefundQueryResult.RefundRecord refund = CollUtil.findOne(response.getRefundRecords(), - record -> record.getOutRefundNo().equals(outRefundNo)); - if (refund == null) { - return PayRefundRespDTO.failureOf(outRefundNo, response); - } - switch (refund.getRefundStatus()) { - case "SUCCESS": - return PayRefundRespDTO.successOf(refund.getRefundId(), parseDateV2B(refund.getRefundSuccessTime()), - outRefundNo, response); - case "PROCESSING": - return PayRefundRespDTO.waitingOf(refund.getRefundId(), - outRefundNo, response); - case "CHANGE": // 退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,资金回流到商户的现金帐号,需要商户人工干预,通过线下或者财付通转账的方式进行退款 - case "FAIL": - return PayRefundRespDTO.failureOf(outRefundNo, response); - default: - throw new IllegalArgumentException(String.format("未知的退款状态(%s)", refund.getRefundStatus())); - } - } - - private PayRefundRespDTO doGetRefundV3(String outTradeNo, String outRefundNo) throws WxPayException { - // 1. 构建 WxPayRefundRequest 请求 - WxPayRefundQueryV3Request request = new WxPayRefundQueryV3Request(); - request.setOutRefundNo(outRefundNo); - // 2.1 执行请求 - WxPayRefundQueryV3Result response = client.refundQueryV3(request); - // 2.2 创建返回结果 - switch (response.getStatus()) { - case "SUCCESS": - return PayRefundRespDTO.successOf(response.getRefundId(), parseDateV3(response.getSuccessTime()), - outRefundNo, response); - case "PROCESSING": - return PayRefundRespDTO.waitingOf(response.getRefundId(), - outRefundNo, response); - case "ABNORMAL": // 退款异常 - case "CLOSED": - return PayRefundRespDTO.failureOf(outRefundNo, response); - default: - throw new IllegalArgumentException(String.format("未知的退款状态(%s)", response.getStatus())); - } - } - - @Override - protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) { - throw new UnsupportedOperationException("待实现"); - } - - @Override - protected PayTransferRespDTO doGetTransfer(String outTradeNo, PayTransferTypeEnum type) { - throw new UnsupportedOperationException("待实现"); - } - - // ========== 各种工具方法 ========== - - static String formatDateV2(LocalDateTime time) { - return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), PURE_DATETIME_PATTERN); - } - - static LocalDateTime parseDateV2(String time) { - return LocalDateTimeUtil.parse(time, PURE_DATETIME_PATTERN); - } - - static LocalDateTime parseDateV2B(String time) { - return LocalDateTimeUtil.parse(time, NORM_DATETIME_PATTERN); - } - - static String formatDateV3(LocalDateTime time) { - return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), UTC_WITH_XXX_OFFSET_PATTERN); - } - - static LocalDateTime parseDateV3(String time) { - return LocalDateTimeUtil.parse(time, UTC_WITH_XXX_OFFSET_PATTERN); - } - - static String getErrorCode(WxPayException e) { - if (StrUtil.isNotEmpty(e.getErrCode())) { - return e.getErrCode(); - } - if (StrUtil.isNotEmpty(e.getCustomErrorMsg())) { - return "CUSTOM_ERROR"; - } - return e.getReturnCode(); - } - - static String getErrorMessage(WxPayException e) { - if (StrUtil.isNotEmpty(e.getErrCode())) { - return e.getErrCodeDes(); - } - if (StrUtil.isNotEmpty(e.getCustomErrorMsg())) { - return e.getCustomErrorMsg(); - } - return e.getReturnMsg(); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxAppPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxAppPayClient.java deleted file mode 100644 index 396694a75b..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxAppPayClient.java +++ /dev/null @@ -1,63 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; - -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; -import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; -import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; -import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result; -import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; -import com.github.binarywang.wxpay.constant.WxPayConstants; -import com.github.binarywang.wxpay.exception.WxPayException; -import lombok.extern.slf4j.Slf4j; - -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; - -/** - * 微信支付【App 支付】的 PayClient 实现类 - * - * 文档:App 支付 - * - * // TODO 芋艿:未详细测试,因为手头没 App - * - * @author 芋道源码 - */ -@Slf4j -public class WxAppPayClient extends AbstractWxPayClient { - - public WxAppPayClient(Long channelId, WxPayClientConfig config) { - super(channelId, PayChannelEnum.WX_APP.getCode(), config); - } - - @Override - protected void doInit() { - super.doInit(WxPayConstants.TradeType.APP); - } - - @Override - protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { - // 构建 WxPayUnifiedOrderRequest 对象 - WxPayUnifiedOrderRequest request = buildPayUnifiedOrderRequestV2(reqDTO); - // 执行请求 - WxPayMpOrderResult response = client.createOrder(request); - - // 转换结果 - return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response), - reqDTO.getOutTradeNo(), response); - } - - @Override - protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { - // 构建 WxPayUnifiedOrderV3Request 对象 - WxPayUnifiedOrderV3Request request = buildPayUnifiedOrderRequestV3(reqDTO); - // 执行请求 - WxPayUnifiedOrderV3Result.AppResult response = client.createOrderV3(TradeTypeEnum.APP, request); - - // 转换结果 - return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response), - reqDTO.getOutTradeNo(), response); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClient.java deleted file mode 100644 index d01b504050..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClient.java +++ /dev/null @@ -1,107 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; - -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.thread.ThreadUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest; -import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult; -import com.github.binarywang.wxpay.constant.WxPayConstants; -import com.github.binarywang.wxpay.exception.WxPayException; -import lombok.extern.slf4j.Slf4j; - -import java.time.Duration; -import java.time.LocalDateTime; -import java.util.concurrent.TimeUnit; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException; -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; - -/** - * 微信支付【付款码支付】的 PayClient 实现类 - * - * 文档:付款码支付 - * - * @author 芋道源码 - */ -@Slf4j -public class WxBarPayClient extends AbstractWxPayClient { - - /** - * 微信付款码的过期时间 - */ - private static final Duration AUTH_CODE_EXPIRE = Duration.ofMinutes(3); - - public WxBarPayClient(Long channelId, WxPayClientConfig config) { - super(channelId, PayChannelEnum.WX_BAR.getCode(), config); - } - - @Override - protected void doInit() { - super.doInit(WxPayConstants.TradeType.MICROPAY); - } - - @Override - protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { - // 由于付款码需要不断轮询,所以需要在较短的时间完成支付 - LocalDateTime expireTime = LocalDateTimeUtils.addTime(AUTH_CODE_EXPIRE); - if (expireTime.isAfter(reqDTO.getExpireTime())) { - expireTime = reqDTO.getExpireTime(); - } - // 构建 WxPayMicropayRequest 对象 - WxPayMicropayRequest request = WxPayMicropayRequest.newBuilder() - .outTradeNo(reqDTO.getOutTradeNo()) - .body(reqDTO.getSubject()) - .detail(reqDTO.getBody()) - .totalFee(reqDTO.getPrice()) // 单位分 - .timeExpire(formatDateV2(expireTime)) - .spbillCreateIp(reqDTO.getUserIp()) - .authCode(getAuthCode(reqDTO)) - .build(); - // 执行请求,重试直到失败(过期),或者成功 - WxPayException lastWxPayException = null; - for (int i = 1; i < Byte.MAX_VALUE; i++) { - try { - WxPayMicropayResult response = client.micropay(request); - // 支付成功,例如说:1)用户输入了密码;2)用户免密支付 - return PayOrderRespDTO.successOf(response.getTransactionId(), response.getOpenid(), parseDateV2(response.getTimeEnd()), - response.getOutTradeNo(), response) - .setDisplayMode(PayOrderDisplayModeEnum.BAR_CODE.getMode()); - } catch (WxPayException ex) { - lastWxPayException = ex; - // 如果不满足这 3 种任一的,则直接抛出 WxPayException 异常,不仅需处理 - // 1. SYSTEMERROR:接口返回错误:请立即调用被扫订单结果查询API,查询当前订单状态,并根据订单的状态决定下一步的操作。 - // 2. USERPAYING:用户支付中,需要输入密码:等待 5 秒,然后调用被扫订单结果查询 API,查询当前订单的不同状态,决定下一步的操作。 - // 3. BANKERROR:银行系统异常:请立即调用被扫订单结果查询 API,查询当前订单的不同状态,决定下一步的操作。 - if (!StrUtil.equalsAny(ex.getErrCode(), "SYSTEMERROR", "USERPAYING", "BANKERROR")) { - throw ex; - } - // 等待 5 秒,继续下一轮重新发起支付 - log.info("[doUnifiedOrderV2][发起微信 Bar 支付第({})失败,等待下一轮重试,请求({}),响应({})]", i, - toJsonString(request), ex.getMessage()); - ThreadUtil.sleep(5, TimeUnit.SECONDS); - } - } - throw lastWxPayException; - } - - @Override - protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { - return doUnifiedOrderV2(reqDTO); - } - - // ========== 各种工具方法 ========== - - static String getAuthCode(PayOrderUnifiedReqDTO reqDTO) { - String authCode = MapUtil.getStr(reqDTO.getChannelExtras(), "authCode"); - if (StrUtil.isEmpty(authCode)) { - throw invalidParamException("支付请求的 authCode 不能为空!"); - } - return authCode; - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxLitePayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxLitePayClient.java deleted file mode 100644 index 9929955ae2..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxLitePayClient.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; - -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; -import lombok.extern.slf4j.Slf4j; - -/** - * 微信支付【小程序】的 PayClient 实现类 - * - * 由于公众号和小程序的微信支付逻辑一致,所以直接进行继承 - * - * 文档:JSAPI 下单 - * - * @author zwy - */ -@Slf4j -public class WxLitePayClient extends WxPubPayClient { - - public WxLitePayClient(Long channelId, WxPayClientConfig config) { - super(channelId, PayChannelEnum.WX_LITE.getCode(), config); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClient.java deleted file mode 100644 index 5a073501d4..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClient.java +++ /dev/null @@ -1,58 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; - -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult; -import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; -import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; -import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; -import com.github.binarywang.wxpay.constant.WxPayConstants; -import com.github.binarywang.wxpay.exception.WxPayException; -import lombok.extern.slf4j.Slf4j; - -/** - * 微信支付【Native 二维码】的 PayClient 实现类 - * - * 文档:Native 下单 - * - * @author zwy - */ -@Slf4j -public class WxNativePayClient extends AbstractWxPayClient { - - public WxNativePayClient(Long channelId, WxPayClientConfig config) { - super(channelId, PayChannelEnum.WX_NATIVE.getCode(), config); - } - - @Override - protected void doInit() { - super.doInit(WxPayConstants.TradeType.NATIVE); - } - - @Override - protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { - // 构建 WxPayUnifiedOrderRequest 对象 - WxPayUnifiedOrderRequest request = buildPayUnifiedOrderRequestV2(reqDTO); - // 执行请求 - WxPayNativeOrderResult response = client.createOrder(request); - - // 转换结果 - return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.QR_CODE.getMode(), response.getCodeUrl(), - reqDTO.getOutTradeNo(), response); - } - - @Override - protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { - // 构建 WxPayUnifiedOrderV3Request 对象 - WxPayUnifiedOrderV3Request request = buildPayUnifiedOrderRequestV3(reqDTO); - // 执行请求 - String response = client.createOrderV3(TradeTypeEnum.NATIVE, request); - - // 转换结果 - return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.QR_CODE.getMode(), response, - reqDTO.getOutTradeNo(), response); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java deleted file mode 100644 index 77027ae3aa..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPayClientConfig.java +++ /dev/null @@ -1,110 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; - -import cn.hutool.core.io.IoUtil; -import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; -import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; -import lombok.Data; - -import javax.validation.Validator; -import javax.validation.constraints.NotBlank; -import java.io.FileInputStream; -import java.io.FileNotFoundException; - -/** - * 微信支付的 PayClientConfig 实现类 - * 属性主要来自 {@link com.github.binarywang.wxpay.config.WxPayConfig} 的必要属性 - * - * @author 芋道源码 - */ -@Data -public class WxPayClientConfig implements PayClientConfig { - - /** - * API 版本 - V2 - * - * V2 协议说明 - */ - public static final String API_VERSION_V2 = "v2"; - /** - * API 版本 - V3 - * - * V3 协议说明 - */ - public static final String API_VERSION_V3 = "v3"; - - /** - * 公众号或者小程序的 appid - * - * 只有公众号或小程序需要该字段 - */ - @NotBlank(message = "APPID 不能为空", groups = {V2.class, V3.class}) - private String appId; - /** - * 商户号 - */ - @NotBlank(message = "商户号不能为空", groups = {V2.class, V3.class}) - private String mchId; - /** - * API 版本 - */ - @NotBlank(message = "API 版本不能为空", groups = {V2.class, V3.class}) - private String apiVersion; - - // ========== V2 版本的参数 ========== - - /** - * 商户密钥 - */ - @NotBlank(message = "商户密钥不能为空", groups = V2.class) - private String mchKey; - /** - * apiclient_cert.p12 证书文件的对应字符串【base64 格式】 - * - * 为什么采用 base64 格式?因为 p12 读取后是二进制,需要转换成 base64 格式才好传输和存储 - */ - @NotBlank(message = "apiclient_cert.p12 不能为空", groups = V2.class) - private String keyContent; - - // ========== V3 版本的参数 ========== - /** - * apiclient_key.pem 证书文件的对应字符串 - */ - @NotBlank(message = "apiclient_key 不能为空", groups = V3.class) - private String privateKeyContent; - /** - * apiclient_cert.pem 证书文件的对应的字符串 - */ - @NotBlank(message = "apiclient_cert 不能为空", groups = V3.class) - private String privateCertContent; - /** - * apiV3 密钥值 - */ - @NotBlank(message = "apiV3 密钥值不能为空", groups = V3.class) - private String apiV3Key; - - /** - * 分组校验 v2版本 - */ - public interface V2 { - } - - /** - * 分组校验 v3版本 - */ - public interface V3 { - } - - @Override - public void validate(Validator validator) { - ValidationUtils.validate(validator, this, - API_VERSION_V2.equals(this.getApiVersion()) ? V2.class : V3.class); - } - - public static void main(String[] args) throws FileNotFoundException { - String path = "/Users/yunai/Downloads/wx_pay/apiclient_cert.p12"; - /// String path = "/Users/yunai/Downloads/wx_pay/apiclient_key.pem"; - /// String path = "/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"; - System.out.println(IoUtil.readUtf8(new FileInputStream(path))); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java deleted file mode 100644 index 390c513630..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java +++ /dev/null @@ -1,80 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; - -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; -import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; -import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; -import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result; -import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; -import com.github.binarywang.wxpay.constant.WxPayConstants; -import com.github.binarywang.wxpay.exception.WxPayException; -import lombok.extern.slf4j.Slf4j; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException; -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; - -/** - * 微信支付(公众号)的 PayClient 实现类 - * - * 文档:JSAPI 下单 - * - * @author 芋道源码 - */ -@Slf4j -public class WxPubPayClient extends AbstractWxPayClient { - - public WxPubPayClient(Long channelId, WxPayClientConfig config) { - super(channelId, PayChannelEnum.WX_PUB.getCode(), config); - } - - protected WxPubPayClient(Long channelId, String channelCode, WxPayClientConfig config) { - super(channelId, channelCode, config); - } - - @Override - protected void doInit() { - super.doInit(WxPayConstants.TradeType.JSAPI); - } - - @Override - protected PayOrderRespDTO doUnifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { - // 构建 WxPayUnifiedOrderRequest 对象 - WxPayUnifiedOrderRequest request = buildPayUnifiedOrderRequestV2(reqDTO) - .setOpenid(getOpenid(reqDTO)); - // 执行请求 - WxPayMpOrderResult response = client.createOrder(request); - - // 转换结果 - return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response), - reqDTO.getOutTradeNo(), response); - } - - @Override - protected PayOrderRespDTO doUnifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { - // 构建 WxPayUnifiedOrderRequest 对象 - WxPayUnifiedOrderV3Request request = buildPayUnifiedOrderRequestV3(reqDTO) - .setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(getOpenid(reqDTO))); - // 执行请求 - WxPayUnifiedOrderV3Result.JsapiResult response = client.createOrderV3(TradeTypeEnum.JSAPI, request); - - // 转换结果 - return PayOrderRespDTO.waitingOf(PayOrderDisplayModeEnum.APP.getMode(), toJsonString(response), - reqDTO.getOutTradeNo(), response); - } - - // ========== 各种工具方法 ========== - - static String getOpenid(PayOrderUnifiedReqDTO reqDTO) { - String openid = MapUtil.getStr(reqDTO.getChannelExtras(), "openid"); - if (StrUtil.isEmpty(openid)) { - throw invalidParamException("支付请求的 openid 不能为空!"); - } - return openid; - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/channel/PayChannelEnum.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/channel/PayChannelEnum.java deleted file mode 100644 index 83d2d13add..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/channel/PayChannelEnum.java +++ /dev/null @@ -1,68 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.enums.channel; - -import cn.hutool.core.util.ArrayUtil; -import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; -import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; -import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; -import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig; -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * 支付渠道的编码的枚举 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum PayChannelEnum { - - WX_PUB("wx_pub", "微信 JSAPI 支付", WxPayClientConfig.class), // 公众号网页 - WX_LITE("wx_lite", "微信小程序支付", WxPayClientConfig.class), - WX_APP("wx_app", "微信 App 支付", WxPayClientConfig.class), - WX_NATIVE("wx_native", "微信 Native 支付", WxPayClientConfig.class), - WX_BAR("wx_bar", "微信付款码支付", WxPayClientConfig.class), - - ALIPAY_PC("alipay_pc", "支付宝 PC 网站支付", AlipayPayClientConfig.class), - ALIPAY_WAP("alipay_wap", "支付宝 Wap 网站支付", AlipayPayClientConfig.class), - ALIPAY_APP("alipay_app", "支付宝App 支付", AlipayPayClientConfig.class), - ALIPAY_QR("alipay_qr", "支付宝扫码支付", AlipayPayClientConfig.class), - ALIPAY_BAR("alipay_bar", "支付宝条码支付", AlipayPayClientConfig.class), - MOCK("mock", "模拟支付", NonePayClientConfig.class), - - WALLET("wallet", "钱包支付", NonePayClientConfig.class); - - /** - * 编码 - * - * 参考 支付渠道属性值 - */ - private final String code; - /** - * 名字 - */ - private final String name; - - /** - * 配置类 - */ - private final Class configClass; - - /** - * 微信支付 - */ - public static final String WECHAT = "WECHAT"; - - /** - * 支付宝支付 - */ - public static final String ALIPAY = "ALIPAY"; - - public static PayChannelEnum getByCode(String code) { - return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values()); - } - - public static boolean isAlipay(String channelCode) { - return channelCode != null && channelCode.startsWith("alipay"); - } -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderDisplayModeEnum.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderDisplayModeEnum.java deleted file mode 100644 index 129c406029..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderDisplayModeEnum.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.enums.order; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * 支付 UI 展示模式 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum PayOrderDisplayModeEnum { - - URL("url"), // Redirect 跳转链接的方式 - IFRAME("iframe"), // IFrame 内嵌链接的方式【目前暂时用不到】 - FORM("form"), // HTML 表单提交 - QR_CODE("qr_code"), // 二维码的文字内容 - QR_CODE_URL("qr_code_url"), // 二维码的图片链接 - BAR_CODE("bar_code"), // 条形码 - APP("app"), // 应用:Android、iOS、微信小程序、微信公众号等,需要做自定义处理的 - ; - - /** - * 展示模式 - */ - private final String mode; - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderStatusRespEnum.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderStatusRespEnum.java deleted file mode 100644 index eac381c472..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/order/PayOrderStatusRespEnum.java +++ /dev/null @@ -1,56 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.enums.order; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Objects; - -/** - * 渠道的支付状态枚举 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum PayOrderStatusRespEnum { - - WAITING(0, "未支付"), - SUCCESS(10, "支付成功"), - REFUND(20, "已退款"), - CLOSED(30, "支付关闭"), - ; - - private final Integer status; - private final String name; - - /** - * 判断是否支付成功 - * - * @param status 状态 - * @return 是否支付成功 - */ - public static boolean isSuccess(Integer status) { - return Objects.equals(status, SUCCESS.getStatus()); - } - - /** - * 判断是否已退款 - * - * @param status 状态 - * @return 是否支付成功 - */ - public static boolean isRefund(Integer status) { - return Objects.equals(status, REFUND.getStatus()); - } - - /** - * 判断是否支付关闭 - * - * @param status 状态 - * @return 是否支付关闭 - */ - public static boolean isClosed(Integer status) { - return Objects.equals(status, CLOSED.getStatus()); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayRefundStatusRespEnum.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayRefundStatusRespEnum.java deleted file mode 100644 index 8ad61a6cff..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/refund/PayRefundStatusRespEnum.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.enums.refund; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Objects; - -/** - * 渠道的退款状态枚举 - * - * @author jason - */ -@Getter -@AllArgsConstructor -public enum PayRefundStatusRespEnum { - - WAITING(0, "等待退款"), - SUCCESS(10, "退款成功"), - FAILURE(20, "退款失败"); - - private final Integer status; - private final String name; - - public static boolean isSuccess(Integer status) { - return Objects.equals(status, SUCCESS.getStatus()); - } - - public static boolean isFailure(Integer status) { - return Objects.equals(status, FAILURE.getStatus()); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java deleted file mode 100644 index 35ea344da2..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferStatusRespEnum.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.enums.transfer; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Objects; - -/** - * 渠道的转账状态枚举 - * - * @author jason - */ -@Getter -@AllArgsConstructor -public enum PayTransferStatusRespEnum { - - WAITING(0, "等待转账"), - - /** - * TODO 转账到银行卡. 会有T+0 T+1 到账的请情况。 还未实现 - * TODO @jason:可以看看其它开源项目,针对这个场景,处理策略是怎么样的?例如说,每天主动轮询?这个状态的单子? - */ - IN_PROGRESS(10, "转账进行中"), - - SUCCESS(20, "转账成功"), - /** - * 转账关闭 (失败,或者其它情况) - */ - CLOSED(30, "转账关闭"); - - private final Integer status; - private final String name; - - public static boolean isSuccess(Integer status) { - return Objects.equals(status, SUCCESS.getStatus()); - } - - public static boolean isClosed(Integer status) { - return Objects.equals(status, CLOSED.getStatus()); - } - - public static boolean isInProgress(Integer status) { - return Objects.equals(status, IN_PROGRESS.getStatus()); - } -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferTypeEnum.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferTypeEnum.java deleted file mode 100644 index a7580f0132..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/transfer/PayTransferTypeEnum.java +++ /dev/null @@ -1,44 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.enums.transfer; - -import cn.hutool.core.util.ArrayUtil; -import cn.iocoder.yudao.framework.common.core.IntArrayValuable; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Arrays; - -/** - * 转账类型枚举 - * - * @author jason - */ -@AllArgsConstructor -@Getter -public enum PayTransferTypeEnum implements IntArrayValuable { - - ALIPAY_BALANCE(1, "支付宝余额"), - WX_BALANCE(2, "微信余额"), - BANK_CARD(3, "银行卡"), - WALLET_BALANCE(4, "钱包余额"); - - public interface WxPay { - } - - public interface Alipay { - } - - private final Integer type; - private final String name; - - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PayTransferTypeEnum::getType).toArray(); - - @Override - public int[] array() { - return ARRAYS; - } - - public static PayTransferTypeEnum typeOf(Integer type) { - return ArrayUtil.firstMatch(item -> item.getType().equals(type), values()); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index f2a8bf1463..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1 +0,0 @@ -cn.iocoder.yudao.framework.pay.config.YudaoPayAutoConfiguration \ No newline at end of file diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java deleted file mode 100644 index 9842560636..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImplIntegrationTest.java +++ /dev/null @@ -1,133 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl; - -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.RandomUtil; -import cn.iocoder.yudao.framework.pay.core.client.PayClient; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; -import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayQrPayClient; -import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayWapPayClient; -import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig; -import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPubPayClient; -import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; - -/** - * {@link PayClientFactoryImpl} 的集成测试 - * - * @author 芋道源码 - */ -@Disabled -public class PayClientFactoryImplIntegrationTest { - - private static final String SERVER_URL_SANDBOX = "https://openapi.alipaydev.com/gateway.do"; - - private final PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl(); - - /** - * {@link WxPubPayClient} 的 V2 版本 - */ - @Test - public void testCreatePayClient_WX_PUB_V2() { - // 创建配置 - WxPayClientConfig config = new WxPayClientConfig(); - config.setAppId("wx041349c6f39b268b"); - config.setMchId("1545083881"); - config.setApiVersion(WxPayClientConfig.API_VERSION_V2); - config.setMchKey("0alL64UDQdlCwiKZ73ib7ypaIjMns06p"); - // 创建客户端 - Long channelId = RandomUtil.randomLong(); - payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.WX_PUB.getCode(), config); - PayClient client = payClientFactory.getPayClient(channelId); - // 发起支付 - PayOrderUnifiedReqDTO reqDTO = buildPayOrderUnifiedReqDTO(); -// CommonResult result = client.unifiedOrder(reqDTO); -// System.out.println(result); - } - - /** - * {@link WxPubPayClient} 的 V3 版本 - */ - @Test - public void testCreatePayClient_WX_PUB_V3() throws FileNotFoundException { - // 创建配置 - WxPayClientConfig config = new WxPayClientConfig(); - config.setAppId("wx041349c6f39b268b"); - config.setMchId("1545083881"); - config.setApiVersion(WxPayClientConfig.API_VERSION_V3); - config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_key.pem"))); - config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"))); - config.setApiV3Key("joerVi8y5DJ3o4ttA0o1uH47Xz1u2Ase"); - // 创建客户端 - Long channelId = RandomUtil.randomLong(); - payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.WX_PUB.getCode(), config); - PayClient client = payClientFactory.getPayClient(channelId); - // 发起支付 - PayOrderUnifiedReqDTO reqDTO = buildPayOrderUnifiedReqDTO(); -// CommonResult result = client.unifiedOrder(reqDTO); -// System.out.println(result); - } - - /** - * {@link AlipayQrPayClient} - */ - @Test - @SuppressWarnings("unchecked") - public void testCreatePayClient_ALIPAY_QR() { - // 创建配置 - AlipayPayClientConfig config = new AlipayPayClientConfig(); - config.setAppId("2021000118634035"); - config.setServerUrl(SERVER_URL_SANDBOX); - config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT); - config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8="); - config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB"); - // 创建客户端 - Long channelId = RandomUtil.randomLong(); - payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.ALIPAY_QR.getCode(), config); - PayClient client = payClientFactory.getPayClient(channelId); - // 发起支付 - PayOrderUnifiedReqDTO reqDTO = buildPayOrderUnifiedReqDTO(); - reqDTO.setNotifyUrl("http://yunai.natapp1.cc/admin-api/pay/notify/callback/18"); // TODO @tina: 这里改成你的 natapp 回调地址 -// CommonResult result = (CommonResult) client.unifiedOrder(reqDTO); -// System.out.println(JsonUtils.toJsonString(result)); -// System.out.println(result.getData().getQrCode()); - } - - /** - * {@link AlipayWapPayClient} - */ - @Test - public void testCreatePayClient_ALIPAY_WAP() { - // 创建配置 - AlipayPayClientConfig config = new AlipayPayClientConfig(); - config.setAppId("2021000118634035"); - config.setServerUrl(SERVER_URL_SANDBOX); - config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT); - config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8="); - config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB"); - // 创建客户端 - Long channelId = RandomUtil.randomLong(); - payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.ALIPAY_WAP.getCode(), config); - PayClient client = payClientFactory.getPayClient(channelId); - // 发起支付 - PayOrderUnifiedReqDTO reqDTO = buildPayOrderUnifiedReqDTO(); -// CommonResult result = client.unifiedOrder(reqDTO); -// System.out.println(JsonUtils.toJsonString(result)); - } - - private static PayOrderUnifiedReqDTO buildPayOrderUnifiedReqDTO() { - PayOrderUnifiedReqDTO reqDTO = new PayOrderUnifiedReqDTO(); - reqDTO.setPrice(123); - reqDTO.setSubject("IPhone 13"); - reqDTO.setBody("biubiubiu"); - reqDTO.setOutTradeNo(String.valueOf(System.currentTimeMillis())); - reqDTO.setUserIp("127.0.0.1"); - reqDTO.setNotifyUrl("http://127.0.0.1:8080"); - return reqDTO; - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClientTest.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClientTest.java deleted file mode 100644 index 2d220079eb..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClientTest.java +++ /dev/null @@ -1,221 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; - -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.hutool.core.util.RandomUtil; -import cn.iocoder.yudao.framework.common.exception.ServiceException; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; -import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; -import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; -import com.alipay.api.AlipayApiException; -import com.alipay.api.DefaultAlipayClient; -import com.alipay.api.DefaultSigner; -import com.alipay.api.domain.AlipayTradeRefundModel; -import com.alipay.api.request.AlipayTradeRefundRequest; -import com.alipay.api.response.AlipayTradeRefundResponse; -import lombok.Setter; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatcher; -import org.mockito.Mock; - -import javax.validation.ConstraintViolationException; -import java.util.Date; - -import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_PUBLIC_KEY; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.when; - -/** - * 支付宝 Client 的测试基类 - * - * @author jason - */ -public abstract class AbstractAlipayClientTest extends BaseMockitoUnitTest { - - protected AlipayPayClientConfig config = randomPojo(AlipayPayClientConfig.class, o -> { - o.setServerUrl(randomURL()); - o.setPrivateKey(randomString()); - o.setMode(MODE_PUBLIC_KEY); - o.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT); - o.setAppCertContent(""); - o.setAlipayPublicCertContent(""); - o.setRootCertContent(""); - }); - - @Mock - protected DefaultAlipayClient defaultAlipayClient; - - @Setter - private AbstractAlipayPayClient client; - - /** - * 子类需要实现该方法. 设置 client 的具体实现 - */ - @BeforeEach - public abstract void setUp(); - - @Test - @DisplayName("支付宝 Client 初始化") - public void testDoInit() { - // 调用 - client.doInit(); - // 断言 - DefaultAlipayClient realClient = client.getClient(); - assertNotSame(defaultAlipayClient, realClient); - assertInstanceOf(DefaultSigner.class, realClient.getSigner()); - assertEquals(config.getPrivateKey(), ((DefaultSigner) realClient.getSigner()).getPrivateKey()); - } - - @Test - @DisplayName("支付宝 Client 统一退款:成功") - public void testUnifiedRefund_success() throws AlipayApiException { - // mock 方法 - String notifyUrl = randomURL(); - Date refundTime = randomDate(); - String outRefundNo = randomString(); - String outTradeNo = randomString(); - Integer refundAmount = randomInteger(); - AlipayTradeRefundResponse response = randomPojo(AlipayTradeRefundResponse.class, o -> { - o.setSubCode(""); - o.setGmtRefundPay(refundTime); - }); - when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { - assertInstanceOf(AlipayTradeRefundModel.class, request.getBizModel()); - AlipayTradeRefundModel bizModel = (AlipayTradeRefundModel) request.getBizModel(); - assertEquals(outRefundNo, bizModel.getOutRequestNo()); - assertEquals(outTradeNo, bizModel.getOutTradeNo()); - assertEquals(String.valueOf(refundAmount / 100.0), bizModel.getRefundAmount()); - return true; - }))).thenReturn(response); - // 准备请求参数 - PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> { - o.setOutRefundNo(outRefundNo); - o.setOutTradeNo(outTradeNo); - o.setNotifyUrl(notifyUrl); - o.setRefundPrice(refundAmount); - }); - - // 调用 - PayRefundRespDTO resp = client.unifiedRefund(refundReqDTO); - // 断言 - assertEquals(PayRefundStatusRespEnum.SUCCESS.getStatus(), resp.getStatus()); - assertEquals(outRefundNo, resp.getOutRefundNo()); - assertNull(resp.getChannelRefundNo()); - assertEquals(LocalDateTimeUtil.of(refundTime), resp.getSuccessTime()); - assertSame(response, resp.getRawData()); - assertNull(resp.getChannelErrorCode()); - assertNull(resp.getChannelErrorMsg()); - } - - @Test - @DisplayName("支付宝 Client 统一退款:渠道返回失败") - public void test_unified_refund_channel_failed() throws AlipayApiException { - // mock 方法 - String notifyUrl = randomURL(); - String subCode = randomString(); - String subMsg = randomString(); - AlipayTradeRefundResponse response = randomPojo(AlipayTradeRefundResponse.class, o -> { - o.setSubCode(subCode); - o.setSubMsg(subMsg); - }); - when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { - assertInstanceOf(AlipayTradeRefundModel.class, request.getBizModel()); - return true; - }))).thenReturn(response); - // 准备请求参数 - String outRefundNo = randomString(); - String outTradeNo = randomString(); - PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> { - o.setOutRefundNo(outRefundNo); - o.setOutTradeNo(outTradeNo); - o.setNotifyUrl(notifyUrl); - }); - - // 调用 - PayRefundRespDTO resp = client.unifiedRefund(refundReqDTO); - // 断言 - assertEquals(PayRefundStatusRespEnum.FAILURE.getStatus(), resp.getStatus()); - assertEquals(outRefundNo, resp.getOutRefundNo()); - assertNull(resp.getChannelRefundNo()); - assertNull(resp.getSuccessTime()); - assertSame(response, resp.getRawData()); - assertEquals(subCode, resp.getChannelErrorCode()); - assertEquals(subMsg, resp.getChannelErrorMsg()); - } - - @Test - @DisplayName("支付宝 Client 统一退款:参数校验不通过") - public void testUnifiedRefund_paramInvalidate() { - // 准备请求参数 - String notifyUrl = randomURL(); - PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> { - o.setOutTradeNo(""); - o.setNotifyUrl(notifyUrl); - }); - - // 调用,并断言 - assertThrows(ConstraintViolationException.class, () -> client.unifiedRefund(refundReqDTO)); - } - - @Test - @DisplayName("支付宝 Client 统一退款:抛出业务异常") - public void testUnifiedRefund_throwServiceException() throws AlipayApiException { - // mock 方法 - when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> true))) - .thenThrow(ServiceExceptionUtil.exception(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR)); - // 准备请求参数 - String notifyUrl = randomURL(); - PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> o.setNotifyUrl(notifyUrl)); - - // 调用,并断言 - assertThrows(ServiceException.class, () -> client.unifiedRefund(refundReqDTO)); - } - - @Test - @DisplayName("支付宝 Client 统一退款:抛出系统异常") - public void testUnifiedRefund_throwPayException() throws AlipayApiException { - // mock 方法 - when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> true))) - .thenThrow(new RuntimeException("系统异常")); - // 准备请求参数 - String notifyUrl = randomURL(); - PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> o.setNotifyUrl(notifyUrl)); - - // 调用,并断言 - assertThrows(PayException.class, () -> client.unifiedRefund(refundReqDTO)); - } - - @Test - @DisplayName("支付宝 Client 统一下单:参数校验不通过") - public void testUnifiedOrder_paramInvalidate() { - // 准备请求参数 - String outTradeNo = randomString(); - String notifyUrl = randomURL(); - PayOrderUnifiedReqDTO reqDTO = randomPojo(PayOrderUnifiedReqDTO.class, o -> { - o.setOutTradeNo(outTradeNo); - o.setNotifyUrl(notifyUrl); - }); - - // 调用,并断言 - assertThrows(ConstraintViolationException.class, () -> client.unifiedOrder(reqDTO)); - } - - protected PayOrderUnifiedReqDTO buildOrderUnifiedReqDTO(String notifyUrl, String outTradeNo, Integer price) { - return randomPojo(PayOrderUnifiedReqDTO.class, o -> { - o.setOutTradeNo(outTradeNo); - o.setNotifyUrl(notifyUrl); - o.setPrice(price); - o.setSubject(RandomUtil.randomString(32)); - o.setBody(RandomUtil.randomString(32)); - }); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClientTest.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClientTest.java deleted file mode 100644 index 47f10081ca..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClientTest.java +++ /dev/null @@ -1,170 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; - -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.iocoder.yudao.framework.common.exception.ServiceException; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; -import com.alipay.api.AlipayApiException; -import com.alipay.api.domain.AlipayTradePayModel; -import com.alipay.api.request.AlipayTradePayRequest; -import com.alipay.api.response.AlipayTradePayResponse; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatcher; -import org.mockito.InjectMocks; - -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED; -import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.WAITING; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.when; - -/** - * {@link AlipayBarPayClient} 单元测试 - * - * @author jason - */ -public class AlipayBarPayClientTest extends AbstractAlipayClientTest { - - @InjectMocks - private AlipayBarPayClient client = new AlipayBarPayClient(randomLongId(), config); - - @Override - @BeforeEach - public void setUp() { - setClient(client); - } - - @Test - @DisplayName("支付宝条码支付:非免密码支付下单成功") - public void testUnifiedOrder_success() throws AlipayApiException { - // mock 方法 - String outTradeNo = randomString(); - String notifyUrl = randomURL(); - Integer price = randomInteger(); - String authCode = randomString(); - AlipayTradePayResponse response = randomPojo(AlipayTradePayResponse.class, o -> o.setSubCode("")); - when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { - assertInstanceOf(AlipayTradePayModel.class, request.getBizModel()); - assertEquals(notifyUrl, request.getNotifyUrl()); - AlipayTradePayModel model = (AlipayTradePayModel) request.getBizModel(); - assertEquals(outTradeNo, model.getOutTradeNo()); - assertEquals(String.valueOf(price / 100.0), model.getTotalAmount()); - assertEquals(authCode, model.getAuthCode()); - return true; - }))).thenReturn(response); - // 准备请求参数 - PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); - Map extraParam = new HashMap<>(); - extraParam.put("auth_code", authCode); - reqDTO.setChannelExtras(extraParam); - - // 调用方法 - PayOrderRespDTO resp = client.unifiedOrder(reqDTO); - // 断言 - assertEquals(WAITING.getStatus(), resp.getStatus()); - assertEquals(outTradeNo, resp.getOutTradeNo()); - assertNull(resp.getChannelOrderNo()); - assertNull(resp.getChannelUserId()); - assertNull(resp.getSuccessTime()); - assertEquals(PayOrderDisplayModeEnum.BAR_CODE.getMode(), resp.getDisplayMode()); - assertEquals("", resp.getDisplayContent()); - assertSame(response, resp.getRawData()); - assertNull(resp.getChannelErrorCode()); - assertNull(resp.getChannelErrorMsg()); - } - - @Test - @DisplayName("支付宝条码支付:免密码支付下单成功") - public void testUnifiedOrder_code10000Success() throws AlipayApiException { - // mock 方法 - String outTradeNo = randomString(); - String channelNo = randomString(); - String channelUserId = randomString(); - Date payTime = randomDate(); - AlipayTradePayResponse response = randomPojo(AlipayTradePayResponse.class, o -> { - o.setSubCode(""); - o.setCode("10000"); - o.setOutTradeNo(outTradeNo); - o.setTradeNo(channelNo); - o.setBuyerUserId(channelUserId); - o.setGmtPayment(payTime); - }); - when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> true))) - .thenReturn(response); - // 准备请求参数 - String authCode = randomString(); - PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), outTradeNo, randomInteger()); - Map extraParam = new HashMap<>(); - extraParam.put("auth_code", authCode); - reqDTO.setChannelExtras(extraParam); - - // 下单请求 - PayOrderRespDTO resp = client.unifiedOrder(reqDTO); - // 断言 - assertEquals(PayOrderStatusRespEnum.SUCCESS.getStatus(), resp.getStatus()); - assertEquals(outTradeNo, resp.getOutTradeNo()); - assertEquals(channelNo, resp.getChannelOrderNo()); - assertEquals(channelUserId, resp.getChannelUserId()); - assertEquals(LocalDateTimeUtil.of(payTime), resp.getSuccessTime()); - assertEquals(PayOrderDisplayModeEnum.BAR_CODE.getMode(), resp.getDisplayMode()); - assertEquals("", resp.getDisplayContent()); - assertSame(response, resp.getRawData()); - assertNull(resp.getChannelErrorCode()); - assertNull(resp.getChannelErrorMsg()); - } - - @Test - @DisplayName("支付宝条码支付:没有传条码") - public void testUnifiedOrder_emptyAuthCode() { - // 准备参数 - PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), randomString(), randomInteger()); - - // 调用,并断言 - assertThrows(ServiceException.class, () -> client.unifiedOrder(reqDTO)); - } - - @Test - @DisplayName("支付宝条码支付:渠道返回失败") - public void test_unified_order_channel_failed() throws AlipayApiException { - // mock 方法 - String subCode = randomString(); - String subMsg = randomString(); - AlipayTradePayResponse response = randomPojo(AlipayTradePayResponse.class, o -> { - o.setSubCode(subCode); - o.setSubMsg(subMsg); - }); - when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> true))) - .thenReturn(response); - // 准备请求参数 - String authCode = randomString(); - String outTradeNo = randomString(); - PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), outTradeNo, randomInteger()); - Map extraParam = new HashMap<>(); - extraParam.put("auth_code", authCode); - reqDTO.setChannelExtras(extraParam); - - // 调用方法 - PayOrderRespDTO resp = client.unifiedOrder(reqDTO); - // 断言 - assertEquals(CLOSED.getStatus(), resp.getStatus()); - assertEquals(outTradeNo, resp.getOutTradeNo()); - assertNull(resp.getChannelOrderNo()); - assertNull(resp.getChannelUserId()); - assertNull(resp.getSuccessTime()); - assertNull(resp.getDisplayMode()); - assertNull(resp.getDisplayContent()); - assertSame(response, resp.getRawData()); - assertEquals(subCode, resp.getChannelErrorCode()); - assertEquals(subMsg, resp.getChannelErrorMsg()); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClientTest.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClientTest.java deleted file mode 100644 index d78caf28c5..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClientTest.java +++ /dev/null @@ -1,131 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; - -import cn.hutool.http.Method; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import com.alipay.api.AlipayApiException; -import com.alipay.api.request.AlipayTradePagePayRequest; -import com.alipay.api.response.AlipayTradePagePayResponse; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatcher; -import org.mockito.InjectMocks; - -import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED; -import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.WAITING; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -/** - * {@link AlipayPcPayClient} 单元测试 - * - * @author jason - */ -public class AlipayPcPayClientTest extends AbstractAlipayClientTest { - - @InjectMocks - private AlipayPcPayClient client = new AlipayPcPayClient(randomLongId(), config); - - @Override - @BeforeEach - public void setUp() { - setClient(client); - } - - @Test - @DisplayName("支付宝 PC 网站支付:URL Display Mode 下单成功") - public void testUnifiedOrder_urlSuccess() throws AlipayApiException { - // mock 方法 - String notifyUrl = randomURL(); - AlipayTradePagePayResponse response = randomPojo(AlipayTradePagePayResponse.class, o -> o.setSubCode("")); - when(defaultAlipayClient.pageExecute(argThat((ArgumentMatcher) request -> true), - eq(Method.GET.name()))).thenReturn(response); - // 准备请求参数 - String outTradeNo = randomString(); - Integer price = randomInteger(); - PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); - reqDTO.setDisplayMode(null); - - // 调用 - PayOrderRespDTO resp = client.unifiedOrder(reqDTO); - // 断言 - assertEquals(WAITING.getStatus(), resp.getStatus()); - assertEquals(outTradeNo, resp.getOutTradeNo()); - assertNull(resp.getChannelOrderNo()); - assertNull(resp.getChannelUserId()); - assertNull(resp.getSuccessTime()); - assertEquals(PayOrderDisplayModeEnum.URL.getMode(), resp.getDisplayMode()); - assertEquals(response.getBody(), resp.getDisplayContent()); - assertSame(response, resp.getRawData()); - assertNull(resp.getChannelErrorCode()); - assertNull(resp.getChannelErrorMsg()); - } - - @Test - @DisplayName("支付宝 PC 网站支付:Form Display Mode 下单成功") - public void testUnifiedOrder_formSuccess() throws AlipayApiException { - // mock 方法 - String notifyUrl = randomURL(); - AlipayTradePagePayResponse response = randomPojo(AlipayTradePagePayResponse.class, o -> o.setSubCode("")); - when(defaultAlipayClient.pageExecute(argThat((ArgumentMatcher) request -> true), - eq(Method.POST.name()))).thenReturn(response); - // 准备请求参数 - String outTradeNo = randomString(); - Integer price = randomInteger(); - PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); - reqDTO.setDisplayMode(PayOrderDisplayModeEnum.FORM.getMode()); - - // 调用 - PayOrderRespDTO resp = client.unifiedOrder(reqDTO); - // 断言 - assertEquals(WAITING.getStatus(), resp.getStatus()); - assertEquals(outTradeNo, resp.getOutTradeNo()); - assertNull(resp.getChannelOrderNo()); - assertNull(resp.getChannelUserId()); - assertNull(resp.getSuccessTime()); - assertEquals(PayOrderDisplayModeEnum.FORM.getMode(), resp.getDisplayMode()); - assertEquals(response.getBody(), resp.getDisplayContent()); - assertSame(response, resp.getRawData()); - assertNull(resp.getChannelErrorCode()); - assertNull(resp.getChannelErrorMsg()); - } - - @Test - @DisplayName("支付宝 PC 网站支付:渠道返回失败") - public void testUnifiedOrder_channelFailed() throws AlipayApiException { - // mock 方法 - String subCode = randomString(); - String subMsg = randomString(); - AlipayTradePagePayResponse response = randomPojo(AlipayTradePagePayResponse.class, o -> { - o.setSubCode(subCode); - o.setSubMsg(subMsg); - }); - when(defaultAlipayClient.pageExecute(argThat((ArgumentMatcher) request -> true), - eq(Method.GET.name()))).thenReturn(response); - // 准备请求参数 - String outTradeNo = randomString(); - PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), outTradeNo, randomInteger()); - reqDTO.setDisplayMode(PayOrderDisplayModeEnum.URL.getMode()); - - // 调用 - PayOrderRespDTO resp = client.unifiedOrder(reqDTO); - // 断言 - assertEquals(CLOSED.getStatus(), resp.getStatus()); - assertEquals(outTradeNo, resp.getOutTradeNo()); - assertNull(resp.getChannelOrderNo()); - assertNull(resp.getChannelUserId()); - assertNull(resp.getSuccessTime()); - assertNull(resp.getDisplayMode()); - assertNull(resp.getDisplayContent()); - assertSame(response, resp.getRawData()); - assertEquals(subCode, resp.getChannelErrorCode()); - assertEquals(subMsg, resp.getChannelErrorMsg()); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java deleted file mode 100644 index c7e1eb33f7..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java +++ /dev/null @@ -1,147 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; - -import cn.iocoder.yudao.framework.common.exception.ServiceException; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import com.alipay.api.AlipayApiException; -import com.alipay.api.request.AlipayTradePrecreateRequest; -import com.alipay.api.response.AlipayTradePrecreateResponse; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatcher; -import org.mockito.InjectMocks; - -import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED; -import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.WAITING; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.when; - -/** - * {@link AlipayQrPayClient} 单元测试 - * - * @author jason - */ -public class AlipayQrPayClientTest extends AbstractAlipayClientTest { - - @InjectMocks - private AlipayQrPayClient client = new AlipayQrPayClient(randomLongId(), config); - - @BeforeEach - public void setUp() { - setClient(client); - } - - @Test - @DisplayName("支付宝扫描支付:下单成功") - public void testUnifiedOrder_success() throws AlipayApiException { - // mock 方法 - String notifyUrl = randomURL(); - String qrCode = randomString(); - Integer price = randomInteger(); - AlipayTradePrecreateResponse response = randomPojo(AlipayTradePrecreateResponse.class, o -> { - o.setQrCode(qrCode); - o.setSubCode(""); - }); - when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { - assertEquals(notifyUrl, request.getNotifyUrl()); - return true; - }))).thenReturn(response); - // 准备请求参数 - String outTradeNo = randomString(); - PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); - - // 调用 - PayOrderRespDTO resp = client.unifiedOrder(reqDTO); - // 断言 - assertEquals(WAITING.getStatus(), resp.getStatus()); - assertEquals(outTradeNo, resp.getOutTradeNo()); - assertNull(resp.getChannelOrderNo()); - assertNull(resp.getChannelUserId()); - assertNull(resp.getSuccessTime()); - assertEquals(PayOrderDisplayModeEnum.QR_CODE.getMode(), resp.getDisplayMode()); - assertEquals(response.getQrCode(), resp.getDisplayContent()); - assertSame(response, resp.getRawData()); - assertNull(resp.getChannelErrorCode()); - assertNull(resp.getChannelErrorMsg()); - } - - @Test - @DisplayName("支付宝扫描支付:渠道返回失败") - public void testUnifiedOrder_channelFailed() throws AlipayApiException { - // mock 方法 - String notifyUrl = randomURL(); - String subCode = randomString(); - String subMsg = randomString(); - Integer price = randomInteger(); - AlipayTradePrecreateResponse response = randomPojo(AlipayTradePrecreateResponse.class, o -> { - o.setSubCode(subCode); - o.setSubMsg(subMsg); - }); - // mock - when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { - assertEquals(notifyUrl, request.getNotifyUrl()); - return true; - }))).thenReturn(response); - // 准备请求参数 - String outTradeNo = randomString(); - PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); - - // 调用 - PayOrderRespDTO resp = client.unifiedOrder(reqDTO); - // 断言 - assertEquals(CLOSED.getStatus(), resp.getStatus()); - assertEquals(outTradeNo, resp.getOutTradeNo()); - assertNull(resp.getChannelOrderNo()); - assertNull(resp.getChannelUserId()); - assertNull(resp.getSuccessTime()); - assertNull(resp.getDisplayMode()); - assertNull(resp.getDisplayContent()); - assertSame(response, resp.getRawData()); - assertEquals(subCode, resp.getChannelErrorCode()); - assertEquals(subMsg, resp.getChannelErrorMsg()); - } - - @Test - @DisplayName("支付宝扫描支付, 抛出系统异常") - public void testUnifiedOrder_throwPayException() throws AlipayApiException { - // mock 方法 - String outTradeNo = randomString(); - String notifyUrl = randomURL(); - Integer price = randomInteger(); - when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { - assertEquals(notifyUrl, request.getNotifyUrl()); - return true; - }))).thenThrow(new RuntimeException("系统异常")); - // 准备请求参数 - PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo,price); - - // 调用,并断言 - assertThrows(PayException.class, () -> client.unifiedOrder(reqDTO)); - } - - @Test - @DisplayName("支付宝 Client 统一下单:抛出业务异常") - public void testUnifiedOrder_throwServiceException() throws AlipayApiException { - // mock 方法 - String outTradeNo = randomString(); - String notifyUrl = randomURL(); - Integer price = randomInteger(); - when(defaultAlipayClient.execute(argThat((ArgumentMatcher) request -> { - assertEquals(notifyUrl, request.getNotifyUrl()); - return true; - }))).thenThrow(ServiceExceptionUtil.exception(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR)); - // 准备请求参数 - PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); - - // 调用,并断言 - assertThrows(ServiceException.class, () -> client.unifiedOrder(reqDTO)); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClientTest.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClientTest.java deleted file mode 100644 index af0c7170bf..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClientTest.java +++ /dev/null @@ -1,111 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; - -import cn.hutool.http.Method; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; -import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; -import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; -import com.alipay.api.AlipayApiException; -import com.alipay.api.domain.AlipayTradeWapPayModel; -import com.alipay.api.request.AlipayTradeWapPayRequest; -import com.alipay.api.response.AlipayTradeWapPayResponse; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatcher; -import org.mockito.InjectMocks; - -import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED; -import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.WAITING; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -/** - * {@link AlipayWapPayClient} 单元测试 - * - * @author jason - */ -public class AlipayWapPayClientTest extends AbstractAlipayClientTest { - - /** - * 支付宝 H5 支付 Client - */ - @InjectMocks - private AlipayWapPayClient client = new AlipayWapPayClient(randomLongId(), config); - - @BeforeEach - public void setUp() { - setClient(client); - } - - @Test - @DisplayName("支付宝 H5 支付:下单成功") - public void testUnifiedOrder_success() throws AlipayApiException { - // mock 方法 - String h5Body = randomString(); - Integer price = randomInteger(); - AlipayTradeWapPayResponse response = randomPojo(AlipayTradeWapPayResponse.class, o -> { - o.setSubCode(""); - o.setBody(h5Body); - }); - String notifyUrl = randomURL(); - when(defaultAlipayClient.pageExecute(argThat((ArgumentMatcher) request -> { - assertInstanceOf(AlipayTradeWapPayModel.class, request.getBizModel()); - AlipayTradeWapPayModel bizModel = (AlipayTradeWapPayModel) request.getBizModel(); - assertEquals(String.valueOf(price / 100.0), bizModel.getTotalAmount()); - assertEquals(notifyUrl, request.getNotifyUrl()); - return true; - }), eq(Method.GET.name()))).thenReturn(response); - // 准备请求参数 - String outTradeNo = randomString(); - PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(notifyUrl, outTradeNo, price); - - // 调用 - PayOrderRespDTO resp = client.unifiedOrder(reqDTO); - // 断言 - assertEquals(WAITING.getStatus(), resp.getStatus()); - assertEquals(outTradeNo, resp.getOutTradeNo()); - assertNull(resp.getChannelOrderNo()); - assertNull(resp.getChannelUserId()); - assertNull(resp.getSuccessTime()); - assertEquals(PayOrderDisplayModeEnum.URL.getMode(), resp.getDisplayMode()); - assertEquals(response.getBody(), resp.getDisplayContent()); - assertSame(response, resp.getRawData()); - assertNull(resp.getChannelErrorCode()); - assertNull(resp.getChannelErrorMsg()); - } - - @Test - @DisplayName("支付宝 H5 支付:渠道返回失败") - public void test_unified_order_channel_failed() throws AlipayApiException { - // mock 方法 - String subCode = randomString(); - String subMsg = randomString(); - AlipayTradeWapPayResponse response = randomPojo(AlipayTradeWapPayResponse.class, o -> { - o.setSubCode(subCode); - o.setSubMsg(subMsg); - }); - when(defaultAlipayClient.pageExecute(argThat((ArgumentMatcher) request -> true), - eq(Method.GET.name()))).thenReturn(response); - String outTradeNo = randomString(); - PayOrderUnifiedReqDTO reqDTO = buildOrderUnifiedReqDTO(randomURL(), outTradeNo, randomInteger()); - - // 调用 - PayOrderRespDTO resp = client.unifiedOrder(reqDTO); - // 断言 - assertEquals(CLOSED.getStatus(), resp.getStatus()); - assertEquals(outTradeNo, resp.getOutTradeNo()); - assertNull(resp.getChannelOrderNo()); - assertNull(resp.getChannelUserId()); - assertNull(resp.getSuccessTime()); - assertNull(resp.getDisplayMode()); - assertNull(resp.getDisplayContent()); - assertSame(response, resp.getRawData()); - assertEquals(subCode, resp.getChannelErrorCode()); - assertEquals(subMsg, resp.getChannelErrorMsg()); - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClientIntegrationTest.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClientIntegrationTest.java deleted file mode 100644 index 9af11ac3fc..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClientIntegrationTest.java +++ /dev/null @@ -1,123 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; - -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; -import com.github.binarywang.wxpay.bean.request.WxPayMicropayRequest; -import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest; -import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request; -import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult; -import com.github.binarywang.wxpay.bean.result.WxPayRefundResult; -import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result; -import com.github.binarywang.wxpay.config.WxPayConfig; -import com.github.binarywang.wxpay.exception.WxPayException; -import com.github.binarywang.wxpay.service.WxPayService; -import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import java.time.Duration; - -import static cn.iocoder.yudao.framework.pay.core.client.impl.weixin.AbstractWxPayClient.formatDateV2; - -/** - * {@link WxBarPayClient} 的集成测试,用于快速调试微信条码支付 - * - * @author 芋道源码 - */ -@Disabled -public class WxBarPayClientIntegrationTest { - - @Test - public void testPayV2() throws WxPayException { - // 创建 config 配置 - WxPayConfig config = buildWxPayConfigV2(); - // 创建 WxPayService 客户端 - WxPayService client = new WxPayServiceImpl(); - client.setConfig(config); - - // 执行发起支付 - WxPayMicropayRequest request = WxPayMicropayRequest.newBuilder() - .outTradeNo(String.valueOf(System.currentTimeMillis())) - .body("测试支付-body") - .detail("测试支付-detail") - .totalFee(1) // 单位分 - .timeExpire(formatDateV2(LocalDateTimeUtils.addTime(Duration.ofMinutes(2)))) - .spbillCreateIp("127.0.0.1") - .authCode("134298744426278497") - .build(); - System.out.println("========= request =========="); - System.out.println(JsonUtils.toJsonPrettyString(request)); - WxPayMicropayResult response = client.micropay(request); - System.out.println("========= response =========="); - System.out.println(JsonUtils.toJsonPrettyString(response)); - } - - @Test - public void testParseRefundNotifyV2() throws WxPayException { - // 创建 config 配置 - WxPayConfig config = buildWxPayConfigV2(); - // 创建 WxPayService 客户端 - WxPayService client = new WxPayServiceImpl(); - client.setConfig(config); - - // 执行解析 - String xml = "SUCCESS"; - WxPayRefundNotifyResult response = client.parseRefundNotifyResult(xml); - System.out.println(response.getReqInfo()); - } - - @Test - public void testRefundV2() throws WxPayException { - // 创建 config 配置 - WxPayConfig config = buildWxPayConfigV2(); - // 创建 WxPayService 客户端 - WxPayService client = new WxPayServiceImpl(); - client.setConfig(config); - - // 执行发起退款 - WxPayRefundRequest request = new WxPayRefundRequest() - .setOutTradeNo("1689545667276") - .setOutRefundNo(String.valueOf(System.currentTimeMillis())) - .setRefundFee(1) - .setRefundDesc("就是想退了") - .setTotalFee(1); - System.out.println("========= request =========="); - System.out.println(JsonUtils.toJsonPrettyString(request)); - WxPayRefundResult response = client.refund(request); - System.out.println("========= response =========="); - System.out.println(JsonUtils.toJsonPrettyString(response)); - } - - @Test - public void testRefundV3() throws WxPayException { - // 创建 config 配置 - WxPayConfig config = buildWxPayConfigV2(); - // 创建 WxPayService 客户端 - WxPayService client = new WxPayServiceImpl(); - client.setConfig(config); - - // 执行发起退款 - WxPayRefundV3Request request = new WxPayRefundV3Request() - .setOutTradeNo("1689506325635") - .setOutRefundNo(String.valueOf(System.currentTimeMillis())) - .setAmount(new WxPayRefundV3Request.Amount().setTotal(1).setRefund(1).setCurrency("CNY")) - .setReason("就是想退了"); - System.out.println("========= request =========="); - System.out.println(JsonUtils.toJsonPrettyString(request)); - WxPayRefundV3Result response = client.refundV3(request); - System.out.println("========= response =========="); - System.out.println(JsonUtils.toJsonPrettyString(response)); - } - - private WxPayConfig buildWxPayConfigV2() { - WxPayConfig config = new WxPayConfig(); - config.setAppId("wx62056c0d5e8db250"); - config.setMchId("1545083881"); - config.setMchKey("dS1ngeN63JLr3NRbvPH9AJy3MyUxZdim"); -// config.setSignType(WxPayConstants.SignType.MD5); - config.setKeyPath("/Users/yunai/Downloads/wx_pay/apiclient_cert.p12"); - return config; - } - -} diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClientIntegrationTest.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClientIntegrationTest.java deleted file mode 100644 index 5e73601c2b..0000000000 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxNativePayClientIntegrationTest.java +++ /dev/null @@ -1,83 +0,0 @@ -package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; - -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request; -import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; -import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result; -import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; -import com.github.binarywang.wxpay.config.WxPayConfig; -import com.github.binarywang.wxpay.exception.WxPayException; -import com.github.binarywang.wxpay.service.WxPayService; -import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import java.time.Duration; - -import static cn.iocoder.yudao.framework.pay.core.client.impl.weixin.AbstractWxPayClient.formatDateV3; - -/** - * {@link WxNativePayClient} 的集成测试,用于快速调试微信扫码支付 - * - * @author 芋道源码 - */ -@Disabled -public class WxNativePayClientIntegrationTest { - - @Test - public void testPayV3() throws WxPayException { - // 创建 config 配置 - WxPayConfig config = buildWxPayConfigV3(); - // 创建 WxPayService 客户端 - WxPayService client = new WxPayServiceImpl(); - client.setConfig(config); - - // 执行发起支付 - WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request() - .setOutTradeNo(String.valueOf(System.currentTimeMillis())) - .setDescription("测试支付-body") - .setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(1)) // 单位分 - .setTimeExpire(formatDateV3(LocalDateTimeUtils.addTime(Duration.ofMinutes(2)))) - .setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp("127.0.0.1")) - .setNotifyUrl("http://127.0.0.1:48080"); - System.out.println("========= request =========="); - System.out.println(JsonUtils.toJsonPrettyString(request)); - String response = client.createOrderV3(TradeTypeEnum.NATIVE, request); - System.out.println("========= response =========="); - System.out.println(JsonUtils.toJsonPrettyString(response)); - } - - @Test - public void testRefundV3() throws WxPayException { - // 创建 config 配置 - WxPayConfig config = buildWxPayConfigV3(); - // 创建 WxPayService 客户端 - WxPayService client = new WxPayServiceImpl(); - client.setConfig(config); - - // 执行发起退款 - WxPayRefundV3Request request = new WxPayRefundV3Request() - .setOutTradeNo("1689545729695") - .setOutRefundNo(String.valueOf(System.currentTimeMillis())) - .setAmount(new WxPayRefundV3Request.Amount().setTotal(1).setRefund(1).setCurrency("CNY")) - .setReason("就是想退了"); - System.out.println("========= request =========="); - System.out.println(JsonUtils.toJsonPrettyString(request)); - WxPayRefundV3Result response = client.refundV3(request); - System.out.println("========= response =========="); - System.out.println(JsonUtils.toJsonPrettyString(response)); - } - - private WxPayConfig buildWxPayConfigV3() { - WxPayConfig config = new WxPayConfig(); - config.setAppId("wx62056c0d5e8db250"); - config.setMchId("1545083881"); - config.setApiV3Key("459arNsYHl1mgkiO6H9ZH5KkhFXSxaA4"); -// config.setCertSerialNo(serialNo); - config.setPrivateCertPath("/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"); - config.setPrivateKeyPath("/Users/yunai/Downloads/wx_pay/apiclient_key.pem"); - return config; - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java deleted file mode 100644 index 9ade60aa09..0000000000 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java +++ /dev/null @@ -1,372 +0,0 @@ -package cn.iocoder.yudao.module.system.service.auth; - -import cn.hutool.core.util.ReflectUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; -import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; -import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; -import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; -import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; -import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; -import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; -import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; -import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; -import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; -import cn.iocoder.yudao.module.system.service.logger.LoginLogService; -import cn.iocoder.yudao.module.system.service.member.MemberService; -import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; -import cn.iocoder.yudao.module.system.service.social.SocialUserService; -import cn.iocoder.yudao.module.system.service.user.AdminUserService; -import com.xingyuv.captcha.model.common.ResponseModel; -import com.xingyuv.captcha.service.CaptchaService; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.Import; - -import javax.annotation.Resource; -import javax.validation.ConstraintViolationException; -import javax.validation.Validation; -import javax.validation.Validator; - -import static cn.hutool.core.util.RandomUtil.randomEle; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; - -@Import(AdminAuthServiceImpl.class) -public class AdminAuthServiceImplTest extends BaseDbUnitTest { - - @Resource - private AdminAuthServiceImpl authService; - - @MockBean - private AdminUserService userService; - @MockBean - private CaptchaService captchaService; - @MockBean - private LoginLogService loginLogService; - @MockBean - private SocialUserService socialUserService; - @MockBean - private SmsCodeApi smsCodeApi; - @MockBean - private OAuth2TokenService oauth2TokenService; - @MockBean - private MemberService memberService; - @MockBean - private Validator validator; - - @BeforeEach - public void setUp() { - ReflectUtil.setFieldValue(authService, "captchaEnable", true); - // 注入一个 Validator 对象 - ReflectUtil.setFieldValue(authService, "validator", - Validation.buildDefaultValidatorFactory().getValidator()); - } - - @Test - public void testAuthenticate_success() { - // 准备参数 - String username = randomString(); - String password = randomString(); - // mock user 数据 - AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setUsername(username) - .setPassword(password).setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(userService.getUserByUsername(eq(username))).thenReturn(user); - // mock password 匹配 - when(userService.isPasswordMatch(eq(password), eq(user.getPassword()))).thenReturn(true); - - // 调用 - AdminUserDO loginUser = authService.authenticate(username, password); - // 校验 - assertPojoEquals(user, loginUser); - } - - @Test - public void testAuthenticate_userNotFound() { - // 准备参数 - String username = randomString(); - String password = randomString(); - - // 调用, 并断言异常 - assertServiceException(() -> authService.authenticate(username, password), - AUTH_LOGIN_BAD_CREDENTIALS); - verify(loginLogService).createLoginLog( - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) - && o.getResult().equals(LoginResultEnum.BAD_CREDENTIALS.getResult()) - && o.getUserId() == null) - ); - } - - @Test - public void testAuthenticate_badCredentials() { - // 准备参数 - String username = randomString(); - String password = randomString(); - // mock user 数据 - AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setUsername(username) - .setPassword(password).setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(userService.getUserByUsername(eq(username))).thenReturn(user); - - // 调用, 并断言异常 - assertServiceException(() -> authService.authenticate(username, password), - AUTH_LOGIN_BAD_CREDENTIALS); - verify(loginLogService).createLoginLog( - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) - && o.getResult().equals(LoginResultEnum.BAD_CREDENTIALS.getResult()) - && o.getUserId().equals(user.getId())) - ); - } - - @Test - public void testAuthenticate_userDisabled() { - // 准备参数 - String username = randomString(); - String password = randomString(); - // mock user 数据 - AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setUsername(username) - .setPassword(password).setStatus(CommonStatusEnum.DISABLE.getStatus())); - when(userService.getUserByUsername(eq(username))).thenReturn(user); - // mock password 匹配 - when(userService.isPasswordMatch(eq(password), eq(user.getPassword()))).thenReturn(true); - - // 调用, 并断言异常 - assertServiceException(() -> authService.authenticate(username, password), - AUTH_LOGIN_USER_DISABLED); - verify(loginLogService).createLoginLog( - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) - && o.getResult().equals(LoginResultEnum.USER_DISABLED.getResult()) - && o.getUserId().equals(user.getId())) - ); - } - - @Test - public void testLogin_success() { - // 准备参数 - AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class, o -> - o.setUsername("test_username").setPassword("test_password") - .setSocialType(randomEle(SocialTypeEnum.values()).getType())); - - // mock 验证码正确 - ReflectUtil.setFieldValue(authService, "captchaEnable", false); - // mock user 数据 - AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(1L).setUsername("test_username") - .setPassword("test_password").setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(userService.getUserByUsername(eq("test_username"))).thenReturn(user); - // mock password 匹配 - when(userService.isPasswordMatch(eq("test_password"), eq(user.getPassword()))).thenReturn(true); - // mock 缓存登录用户到 Redis - OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class, o -> o.setUserId(1L) - .setUserType(UserTypeEnum.ADMIN.getValue())); - when(oauth2TokenService.createAccessToken(eq(1L), eq(UserTypeEnum.ADMIN.getValue()), eq("default"), isNull())) - .thenReturn(accessTokenDO); - - // 调用,并校验 - AuthLoginRespVO loginRespVO = authService.login(reqVO); - assertPojoEquals(accessTokenDO, loginRespVO); - // 校验调用参数 - verify(loginLogService).createLoginLog( - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) - && o.getResult().equals(LoginResultEnum.SUCCESS.getResult()) - && o.getUserId().equals(user.getId())) - ); - verify(socialUserService).bindSocialUser(eq(new SocialUserBindReqDTO( - user.getId(), UserTypeEnum.ADMIN.getValue(), - reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()))); - } - - @Test - public void testSendSmsCode() { - // 准备参数 - String mobile = randomString(); - Integer scene = randomEle(SmsSceneEnum.values()).getScene(); - AuthSmsSendReqVO reqVO = new AuthSmsSendReqVO(mobile, scene); - // mock 方法(用户信息) - AdminUserDO user = randomPojo(AdminUserDO.class); - when(userService.getUserByMobile(eq(mobile))).thenReturn(user); - - // 调用 - authService.sendSmsCode(reqVO); - // 断言 - verify(smsCodeApi).sendSmsCode(argThat(sendReqDTO -> { - assertEquals(mobile, sendReqDTO.getMobile()); - assertEquals(scene, sendReqDTO.getScene()); - return true; - })); - } - - @Test - public void testSmsLogin_success() { - // 准备参数 - String mobile = randomString(); - String code = randomString(); - AuthSmsLoginReqVO reqVO = new AuthSmsLoginReqVO(mobile, code); - // mock 方法(用户信息) - AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(1L)); - when(userService.getUserByMobile(eq(mobile))).thenReturn(user); - // mock 缓存登录用户到 Redis - OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class, o -> o.setUserId(1L) - .setUserType(UserTypeEnum.ADMIN.getValue())); - when(oauth2TokenService.createAccessToken(eq(1L), eq(UserTypeEnum.ADMIN.getValue()), eq("default"), isNull())) - .thenReturn(accessTokenDO); - - // 调用,并断言 - AuthLoginRespVO loginRespVO = authService.smsLogin(reqVO); - assertPojoEquals(accessTokenDO, loginRespVO); - // 断言调用 - verify(loginLogService).createLoginLog( - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_MOBILE.getType()) - && o.getResult().equals(LoginResultEnum.SUCCESS.getResult()) - && o.getUserId().equals(user.getId())) - ); - } - - @Test - public void testSocialLogin_success() { - // 准备参数 - AuthSocialLoginReqVO reqVO = randomPojo(AuthSocialLoginReqVO.class); - // mock 方法(绑定的用户编号) - Long userId = 1L; - when(socialUserService.getSocialUserByCode(eq(UserTypeEnum.ADMIN.getValue()), eq(reqVO.getType()), - eq(reqVO.getCode()), eq(reqVO.getState()))).thenReturn(new SocialUserRespDTO(randomString(), randomString(), randomString(), userId)); - // mock(用户) - AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(userId)); - when(userService.getUser(eq(userId))).thenReturn(user); - // mock 缓存登录用户到 Redis - OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class, o -> o.setUserId(1L) - .setUserType(UserTypeEnum.ADMIN.getValue())); - when(oauth2TokenService.createAccessToken(eq(1L), eq(UserTypeEnum.ADMIN.getValue()), eq("default"), isNull())) - .thenReturn(accessTokenDO); - - // 调用,并断言 - AuthLoginRespVO loginRespVO = authService.socialLogin(reqVO); - assertPojoEquals(accessTokenDO, loginRespVO); - // 断言调用 - verify(loginLogService).createLoginLog( - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_SOCIAL.getType()) - && o.getResult().equals(LoginResultEnum.SUCCESS.getResult()) - && o.getUserId().equals(user.getId())) - ); - } - - @Test - public void testValidateCaptcha_successWithEnable() { - // 准备参数 - AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class); - - // mock 验证码打开 - ReflectUtil.setFieldValue(authService, "captchaEnable", true); - // mock 验证通过 - when(captchaService.verification(argThat(captchaVO -> { - assertEquals(reqVO.getCaptchaVerification(), captchaVO.getCaptchaVerification()); - return true; - }))).thenReturn(ResponseModel.success()); - - // 调用,无需断言 - authService.validateCaptcha(reqVO); - } - - @Test - public void testValidateCaptcha_successWithDisable() { - // 准备参数 - AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class); - - // mock 验证码关闭 - ReflectUtil.setFieldValue(authService, "captchaEnable", false); - - // 调用,无需断言 - authService.validateCaptcha(reqVO); - } - - @Test - public void testValidateCaptcha_constraintViolationException() { - // 准备参数 - AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class).setCaptchaVerification(null); - - // mock 验证码打开 - ReflectUtil.setFieldValue(authService, "captchaEnable", true); - - // 调用,并断言异常 - assertThrows(ConstraintViolationException.class, () -> authService.validateCaptcha(reqVO), - "验证码不能为空"); - } - - - @Test - public void testCaptcha_fail() { - // 准备参数 - AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class); - - // mock 验证码打开 - ReflectUtil.setFieldValue(authService, "captchaEnable", true); - // mock 验证通过 - when(captchaService.verification(argThat(captchaVO -> { - assertEquals(reqVO.getCaptchaVerification(), captchaVO.getCaptchaVerification()); - return true; - }))).thenReturn(ResponseModel.errorMsg("就是不对")); - - // 调用, 并断言异常 - assertServiceException(() -> authService.validateCaptcha(reqVO), AUTH_LOGIN_CAPTCHA_CODE_ERROR, "就是不对"); - // 校验调用参数 - verify(loginLogService).createLoginLog( - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) - && o.getResult().equals(LoginResultEnum.CAPTCHA_CODE_ERROR.getResult())) - ); - } - - @Test - public void testRefreshToken() { - // 准备参数 - String refreshToken = randomString(); - // mock 方法 - OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class); - when(oauth2TokenService.refreshAccessToken(eq(refreshToken), eq("default"))) - .thenReturn(accessTokenDO); - - // 调用 - AuthLoginRespVO loginRespVO = authService.refreshToken(refreshToken); - // 断言 - assertPojoEquals(accessTokenDO, loginRespVO); - } - - @Test - public void testLogout_success() { - // 准备参数 - String token = randomString(); - // mock - OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class, o -> o.setUserId(1L) - .setUserType(UserTypeEnum.ADMIN.getValue())); - when(oauth2TokenService.removeAccessToken(eq(token))).thenReturn(accessTokenDO); - - // 调用 - authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); - // 校验调用参数 - verify(loginLogService).createLoginLog( - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGOUT_SELF.getType()) - && o.getResult().equals(LoginResultEnum.SUCCESS.getResult())) - ); - // 调用,并校验 - - } - - @Test - public void testLogout_fail() { - // 准备参数 - String token = randomString(); - - // 调用 - authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); - // 校验调用参数 - verify(loginLogService, never()).createLoginLog(any()); - } - -}