feat(bpm): 新增合同审批功能
- 添加合同审批相关的 API 接口和实现类 - 创建合同审批的请求和响应对象 - 实现合同审批的创建、查询等功能 - 添加合同统计相关接口和实现 - 优化合同审批页面列表展示
This commit is contained in:
parent
c26f8f723f
commit
b1e7f9a9f6
@ -42,6 +42,10 @@
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-protection</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@ -0,0 +1,43 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.BpmOAContractDTO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.BpmOAContractVO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.ContractStatisticsDTO;
|
||||
import cn.iocoder.yudao.module.bpm.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||
@Tag(name = "RPC 服务 - 流程实例")
|
||||
public interface BpmOAContractApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/oa/contract";
|
||||
|
||||
@PostMapping(PREFIX + "/create")
|
||||
@Operation(summary = "创建合同审批流程")
|
||||
@Idempotent(timeout = 10)
|
||||
CommonResult<Long> create(@RequestBody BpmOAContractDTO createReqVO);
|
||||
|
||||
@GetMapping(PREFIX + "/get-contract-count")
|
||||
@Operation(summary = "获得当日合同统计 | 新增数量、新增金额")
|
||||
CommonResult<ContractStatisticsDTO> getContractCount(@RequestParam("relation") String relation);
|
||||
|
||||
@GetMapping(PREFIX + "/get-contract-statistics")
|
||||
@Operation(summary = "获得指定用户的合同统计信息")
|
||||
CommonResult<List<ContractStatisticsDTO>> getContractStatistics(@RequestParam("userId") List<Long> userIds,
|
||||
@RequestParam(name = "createTime", required = false) LocalDateTime[] createTime);
|
||||
|
||||
@PostMapping(PREFIX + "/getList")
|
||||
@Operation(summary = "获得合同列表")
|
||||
CommonResult<List<BpmOAContractDTO>> getContractList(@RequestBody BpmOAContractVO respVO);
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOAEntryDTO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.entry.BpmOAEntryDTO;
|
||||
import cn.iocoder.yudao.module.bpm.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
|
@ -0,0 +1,21 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.invoice.BpmOAInvoiceDTO;
|
||||
import cn.iocoder.yudao.module.bpm.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||
@Tag(name = "RPC 服务 - 流程实例")
|
||||
public interface BpmOAInvoiceApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/oa/invoice";
|
||||
|
||||
@PostMapping(PREFIX + "/create")
|
||||
@Operation(summary = "创建开票申请流程")
|
||||
CommonResult<Long> create(@RequestBody BpmOAInvoiceDTO createReqVO);
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOALeaveRpcVO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.leave.BpmOALeaveRpcVO;
|
||||
import cn.iocoder.yudao.module.bpm.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOARefundDTO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.refund.BpmOARefundDTO;
|
||||
import cn.iocoder.yudao.module.bpm.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
|
@ -0,0 +1,97 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo.contract;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
|
||||
|
||||
/**
|
||||
* 合同审批 创建 Request VO
|
||||
*
|
||||
* @author 符溶馨
|
||||
*/
|
||||
@Schema(description = "管理后台 - 合同审批创建 Request VO")
|
||||
@Data
|
||||
public class BpmOAContractDTO {
|
||||
|
||||
@Schema(description = "合同类型 | 字典值 bpm_oa_contract_type", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "合同类型不能为空")
|
||||
private Integer contractType;
|
||||
|
||||
@Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "合同名称不能为空")
|
||||
private String contractName;
|
||||
|
||||
@Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "合同编号不能为空")
|
||||
private String contractNo;
|
||||
|
||||
@Schema(description = "签约日期", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "签约日期不能为空")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate signingDate;
|
||||
|
||||
@Schema(description = "客户编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "客户名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "客户签约人(联系人ID)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long contactsId;
|
||||
|
||||
@Schema(description = "客户签约人(联系人)名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String contactsName;
|
||||
|
||||
@Schema(description = "签约公司编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "签约公司不能为空")
|
||||
private Long companyId;
|
||||
|
||||
@Schema(description = "签约人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long signatoryId;
|
||||
|
||||
@Schema(description = "合同金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal contractMoney;
|
||||
|
||||
@Schema(description = "已收/已付金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal returnMoney;
|
||||
|
||||
@Schema(description = "已开票金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal invoiceMoney;
|
||||
|
||||
@Schema(description = "产品总金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal totalPrice;
|
||||
|
||||
@Schema(description = "整单优惠金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal discountRate;
|
||||
|
||||
@Schema(description = "商机ID", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long businessId;
|
||||
|
||||
@Schema(description = "合同开始时间", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate startDate;
|
||||
|
||||
@Schema(description = "合同结束时间", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate endDate;
|
||||
|
||||
@Schema(description = "合同状态 | 1已签约 2过期", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "流程实例编号")
|
||||
private String processInstanceId;
|
||||
|
||||
@Schema(description = "状态-参见 bpm_process_instance_result 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer result;
|
||||
|
||||
@Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<UploadUserFile> fileItems;
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo.contract;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "BpmOA合同审批流程的VO对象")
|
||||
@Data
|
||||
public class BpmOAContractVO {
|
||||
|
||||
/**
|
||||
* 合同类型
|
||||
* 1 销售合同
|
||||
*/
|
||||
public static final Integer SALE_CONTRACT = 1;
|
||||
|
||||
@Schema(description = "用户编号")
|
||||
private List<Long> userId;
|
||||
|
||||
@Schema(description = "合同类型")
|
||||
private Integer contractType;
|
||||
|
||||
@Schema(description = "开始时间")
|
||||
private Date starTime;
|
||||
|
||||
@Schema(description = "结束时间")
|
||||
private Date endTime;
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo.contract;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 合同审批 请求Request VO")
|
||||
@Data
|
||||
public class ContractStatisticsDTO {
|
||||
|
||||
@Schema(description = "用户编号")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "今日新增合同数")
|
||||
private Integer todayAdditions;
|
||||
|
||||
@Schema(description = "昨日新增合同数")
|
||||
private Integer yesterdayAdditions;
|
||||
|
||||
@Schema(description = "较昨日百分比 | 数量")
|
||||
private BigDecimal countPercentage;
|
||||
|
||||
@Schema(description = "今日新增合同金额")
|
||||
private BigDecimal todayAddMoney;
|
||||
|
||||
@Schema(description = "昨日新增合同金额")
|
||||
private BigDecimal yesterdayAddMoney;
|
||||
|
||||
@Schema(description = "较昨日百分比 | 金额")
|
||||
private BigDecimal moneyPercentage;
|
||||
|
||||
@Schema(description = "合同总数")
|
||||
private Integer count;
|
||||
|
||||
@Schema(description = "合同总金额")
|
||||
private BigDecimal money;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo;
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo.entry;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo;
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo.evection;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
@ -0,0 +1,88 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo.invoice;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 开票申请创建 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode()
|
||||
@ToString(callSuper = true)
|
||||
public class BpmOAInvoiceDTO {
|
||||
|
||||
@Schema(description = "计划开票日期", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "计划开票日期不能为空")
|
||||
private LocalDate invoiceDate;
|
||||
|
||||
@Schema(description = "关联合同业务编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "合同编号不能为空")
|
||||
private Long contractId;
|
||||
|
||||
@Schema(description = "关联合同流程实例编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String contractInstanceId;
|
||||
|
||||
@Schema(description = "客户编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "开票主体", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "开票主体不能为空")
|
||||
private String invoiceBody;
|
||||
|
||||
@Schema(description = "发票抬头", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "发票抬头不能为空")
|
||||
private String invoiceName;
|
||||
|
||||
@Schema(description = "抬头类型 | 1企业2个人3事业单位", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "抬头类型不能为空")
|
||||
private Integer invoiceIssue;
|
||||
|
||||
@Schema(description = "发票类型 | 1普票 2专票", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "发票类型不能为空")
|
||||
private Integer invoiceType;
|
||||
|
||||
@Schema(description = "统一社会信用代码", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "统一社会信用代码不能为空")
|
||||
private String registerNo;
|
||||
|
||||
@Schema(description = "开票金额", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "开票金额不能为空")
|
||||
private BigDecimal amount;
|
||||
|
||||
@Schema(description = "开票内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "开票内容不能为空")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "开票单位地址")
|
||||
private String unitAddress;
|
||||
|
||||
@Schema(description = "开票单位电话")
|
||||
private String unitPhone;
|
||||
|
||||
@Schema(description = "开票单位开户银行")
|
||||
private String unitBankName;
|
||||
|
||||
@Schema(description = "开票单位银行账号")
|
||||
private String unitBankNo;
|
||||
|
||||
@Schema(description = "开票单位邮箱")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "开票状态", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "流程实例编号")
|
||||
private String processInstanceId;
|
||||
|
||||
@Schema(description = "状态-参见 bpm_process_instance_result 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer result;
|
||||
|
||||
@Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<UploadUserFile> fileItems ;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo;
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo.leave;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo;
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo.refund;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
@ -59,7 +59,7 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode OA_REPLACEMENT_CARD_NOT_EXISTS = new ErrorCode(1_009_001_122, "补卡申请不存在");
|
||||
ErrorCode OA_REFUND_NOT_EXISTS = new ErrorCode(1_009_001_123, "退款申请不存在");
|
||||
ErrorCode OA_PROJECT_NOT_EXISTS = new ErrorCode(1_009_001_124, "项目申请不存在");
|
||||
|
||||
ErrorCode OA_CONTRACT_INVOICE_AMOUNT_LACK = new ErrorCode(1_009_001_125, "该合同的开票余额不足!");
|
||||
|
||||
// ========== 流程模型 1-009-002-000 ==========
|
||||
ErrorCode MODEL_KEY_EXISTS = new ErrorCode(1_009_002_000, "已经存在流程标识为【{}】的流程");
|
||||
|
@ -118,6 +118,22 @@
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-flowable</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-module-product-api</artifactId>
|
||||
<version>2.0.0-jdk8-snapshot</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-module-crm-api</artifactId>
|
||||
<version>2.0.0-jdk8-snapshot</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-protection</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
|
@ -0,0 +1,55 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.BpmOAContractDTO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.BpmOAContractVO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.ContractStatisticsDTO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.BpmOAContractCreateReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.ContractStatisticsRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAContractDO;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAContractService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
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;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
/**
|
||||
* Flowable 流程实例 Api 实现类
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
public class BpmOAContractApiImpl implements BpmOAContractApi{
|
||||
|
||||
@Resource
|
||||
private BpmOAContractService contractService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> create(BpmOAContractDTO createReqVO) {
|
||||
|
||||
return success(contractService.createContract(getLoginUserId(), BeanUtils.toBean(createReqVO, BpmOAContractCreateReqVO.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<ContractStatisticsDTO> getContractCount(String relation) {
|
||||
ContractStatisticsRespVO respVO = contractService.getContractStatistics(getLoginUserId(), relation);
|
||||
return success(BeanUtils.toBean(respVO, ContractStatisticsDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<ContractStatisticsDTO>> getContractStatistics(List<Long> userIds, LocalDateTime[] createTime) {
|
||||
List<ContractStatisticsRespVO> respVOS = contractService.getContractStatisticsListByUserIds(userIds, createTime);
|
||||
return success(BeanUtils.toBean(respVOS, ContractStatisticsDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<BpmOAContractDTO>> getContractList(BpmOAContractVO respVO) {
|
||||
List<BpmOAContractDO> contractDO = contractService.getContractList(respVO);
|
||||
return success(BeanUtils.toBean(contractDO, BpmOAContractDTO.class));
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.bpm.api.oa;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOAEntryDTO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.entry.BpmOAEntryDTO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAEntryDO;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAEntryService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
@ -0,0 +1,32 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.invoice.BpmOAInvoiceDTO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.invoice.BpmOAInvoiceCreateReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAInvoiceService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
/**
|
||||
* Flowable 流程实例 Api 实现类
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
public class BpmOAInvoiceApiImpl implements BpmOAInvoiceApi{
|
||||
|
||||
@Resource
|
||||
private BpmOAInvoiceService invoiceService;
|
||||
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> create(BpmOAInvoiceDTO createReqVO) {
|
||||
|
||||
return success(invoiceService.createInvoice(getLoginUserId(), BeanUtils.toBean(createReqVO, BpmOAInvoiceCreateReqVO.class)));
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOALeaveRpcVO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.leave.BpmOALeaveRpcVO;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOALeaveService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.bpm.api.oa;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOARefundDTO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.refund.BpmOARefundDTO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOARefundDO;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOARefundService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
@ -1,13 +1,23 @@
|
||||
package cn.iocoder.yudao.module.bpm.controller.admin.oa;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
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.framework.idempotent.core.annotation.Idempotent;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.BpmOAContractCreateReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.BpmOAContractPageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.BpmOAContractRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.ContractStatisticsRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAContractConvert;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAContractDO;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAContractService;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmbusiness.BusinessApi;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmbusiness.dto.CrmBusinessDTO;
|
||||
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;
|
||||
@ -16,7 +26,9 @@ import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
@ -39,8 +51,15 @@ public class BpmOAContractController {
|
||||
@Resource
|
||||
private AdminUserApi userApi;
|
||||
|
||||
@Resource
|
||||
private DeptApi deptApi;
|
||||
|
||||
@Resource
|
||||
private BusinessApi businessApi;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建请求申请")
|
||||
@Idempotent(timeout = 10)
|
||||
public CommonResult<Long> createContract(@Valid @RequestBody BpmOAContractCreateReqVO createReqVO) {
|
||||
return success(contractService.createContract(getLoginUserId(), createReqVO));
|
||||
}
|
||||
@ -51,8 +70,31 @@ public class BpmOAContractController {
|
||||
public CommonResult<BpmOAContractRespVO> getContract(@RequestParam("id") Long id) {
|
||||
|
||||
BpmOAContractDO contract = contractService.getContract(id);
|
||||
BpmOAContractRespVO respVO = BpmOAContractConvert.INSTANCE.convert(contract);
|
||||
if (respVO != null) {
|
||||
// 获取用户和签约人信息
|
||||
List<Long> userIds = Arrays.asList(contract.getUserId(), contract.getSignatoryId());
|
||||
Map<Long, AdminUserRespDTO> userMap = userApi.getUserMap(userIds);
|
||||
if (CollectionUtil.isNotEmpty(userMap)) {
|
||||
// 设置创建人、签约人名称
|
||||
respVO.setSignatoryName(userMap.get(contract.getSignatoryId()).getNickname());
|
||||
respVO.setCreateName(userMap.get(contract.getUserId()).getNickname());
|
||||
}
|
||||
|
||||
return success(BpmOAContractConvert.INSTANCE.convert(contract));
|
||||
// 获取公司信息
|
||||
DeptRespDTO dto = deptApi.getDept(contract.getCompanyId()).getCheckedData();
|
||||
if (dto != null) {
|
||||
respVO.setCompanyName(dto.getName());
|
||||
}
|
||||
|
||||
if (respVO.getBusinessId() != null) {
|
||||
// 获取商机信息
|
||||
CrmBusinessDTO businessDTO = businessApi.getBusiness(respVO.getBusinessId()).getCheckedData();
|
||||
respVO.setBusinessName(businessDTO != null ? businessDTO.getName() : null);
|
||||
}
|
||||
}
|
||||
|
||||
return success(respVO);
|
||||
}
|
||||
|
||||
@GetMapping("/getByProcessInstanceId")
|
||||
@ -61,12 +103,42 @@ public class BpmOAContractController {
|
||||
public CommonResult<BpmOAContractRespVO> getContractByProcessInstanceId(@RequestParam("processInstanceId") String processInstanceId) {
|
||||
|
||||
BpmOAContractDO contract = contractService.getByProcessInstanceId(processInstanceId);
|
||||
BpmOAContractRespVO respVO = BpmOAContractConvert.INSTANCE.convert(contract);
|
||||
if (respVO != null) {
|
||||
// 获取用户和签约人信息
|
||||
List<Long> userIds = Arrays.asList(contract.getUserId(), contract.getSignatoryId());
|
||||
Map<Long, AdminUserRespDTO> userMap = userApi.getUserMap(userIds);
|
||||
if (CollectionUtil.isNotEmpty(userMap)) {
|
||||
// 设置创建人、签约人名称
|
||||
respVO.setSignatoryName(userMap.get(contract.getSignatoryId()).getNickname());
|
||||
respVO.setCreateName(userMap.get(contract.getUserId()).getNickname());
|
||||
}
|
||||
|
||||
return success(BpmOAContractConvert.INSTANCE.convert(contract));
|
||||
// 获取公司信息
|
||||
DeptRespDTO dto = deptApi.getDept(contract.getCompanyId()).getCheckedData();
|
||||
if (dto != null) {
|
||||
respVO.setCompanyName(dto.getName());
|
||||
}
|
||||
|
||||
if (respVO.getBusinessId() != null) {
|
||||
// 获取商机信息
|
||||
CrmBusinessDTO businessDTO = businessApi.getBusiness(respVO.getBusinessId()).getCheckedData();
|
||||
respVO.setBusinessName(businessDTO != null ? businessDTO.getName() : null);
|
||||
}
|
||||
}
|
||||
|
||||
return success(respVO);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得合同审批分页列表")
|
||||
public CommonResult<PageResult<BpmOAContractRespVO>> getPage(@Valid BpmOAContractPageReqVO pageReqVO) {
|
||||
|
||||
return success(contractService.getContractPage(pageReqVO));
|
||||
}
|
||||
|
||||
@GetMapping("/getListByDeptId")
|
||||
@Operation(summary = "获得同部门的合同审批")
|
||||
@Operation(summary = "获得同部门的销售合同")
|
||||
public CommonResult<List<BpmOAContractRespVO>> getListByDeptId() {
|
||||
|
||||
// 获取同部门所有用户id
|
||||
@ -76,4 +148,16 @@ public class BpmOAContractController {
|
||||
|
||||
return success(BeanUtils.toBean(contracts, BpmOAContractRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get-contract-statistics")
|
||||
@Operation(summary = "获得当日合同统计 | 新增数量、新增金额")
|
||||
@Parameter(name = "relation", description = "查询类型 my我的 sub下属| ", required = true)
|
||||
public CommonResult<ContractStatisticsRespVO> getListByDeptId(@RequestParam("relation") String relation) {
|
||||
|
||||
ContractStatisticsRespVO respVO = contractService.getContractStatistics(getLoginUserId(), relation);
|
||||
|
||||
return success(respVO);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package cn.iocoder.yudao.module.bpm.controller.admin.oa;
|
||||
|
||||
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.bpm.controller.admin.oa.vo.invoice.BpmOAInvoiceCreateReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.invoice.BpmOAInvoicePageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.invoice.BpmOAInvoiceRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAInvoiceDO;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAInvoiceService;
|
||||
@ -61,4 +63,11 @@ public class BpmOAInvoiceController {
|
||||
BpmOAInvoiceRespVO bpmOAInvoiceRespVO = BeanUtils.toBean(invoice, BpmOAInvoiceRespVO.class);
|
||||
return success(bpmOAInvoiceRespVO);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得开票申请分页列表")
|
||||
public CommonResult<PageResult<BpmOAInvoiceRespVO>> getPage(@Valid BpmOAInvoicePageReqVO pageReqVO) {
|
||||
|
||||
return success(invoiceService.getInvoicePage(pageReqVO));
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@ -16,32 +18,78 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
|
||||
* @author 符溶馨
|
||||
*/
|
||||
@Schema(description = "管理后台 - 合同审批创建 Request VO")
|
||||
@Data
|
||||
public class BpmOAContractCreateReqVO {
|
||||
|
||||
@Schema(description = "ID", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "合同类型 | 字典值 bpm_oa_contract_type", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "合同类型不能为空")
|
||||
private Integer contractType;
|
||||
|
||||
@Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "合同名称不能为空")
|
||||
private String contractName;
|
||||
|
||||
@Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "合同编号不能为空")
|
||||
private String contractNumber;
|
||||
@Schema(description = "合同编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String contractNo;
|
||||
|
||||
@Schema(description = "签约日期", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "签约日期不能为空")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate signingDate;
|
||||
|
||||
@Schema(description = "我方公司名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String mCompanyName;
|
||||
@Schema(description = "客户编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "我方负责人", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String mHeadName;
|
||||
@Schema(description = "客户名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "对方公司名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String oCompanyName;
|
||||
@Schema(description = "客户签约人(联系人ID)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long contactsId;
|
||||
|
||||
@Schema(description = "对方负责人", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String oHeadName;
|
||||
@Schema(description = "客户签约人(联系人)名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String contactsName;
|
||||
|
||||
@Schema(description = "签约公司编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "签约公司不能为空")
|
||||
private Long companyId;
|
||||
|
||||
@Schema(description = "签约人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long signatoryId;
|
||||
|
||||
@Schema(description = "合同金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal contractMoney;
|
||||
|
||||
@Schema(description = "已收/已付金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal returnMoney;
|
||||
|
||||
@Schema(description = "已开票金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal invoiceMoney;
|
||||
|
||||
@Schema(description = "产品总金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal totalPrice;
|
||||
|
||||
@Schema(description = "整单优惠金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal discountRate;
|
||||
|
||||
@Schema(description = "商机ID", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long businessId;
|
||||
|
||||
@Schema(description = "合同开始时间", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate startDate;
|
||||
|
||||
@Schema(description = "合同结束时间", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate endDate;
|
||||
|
||||
@Schema(description = "合同状态 | 1已签约 2过期", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "合同产品关系列表")
|
||||
private List<CrmContractProductVO> contractProducts;
|
||||
|
||||
@Schema(description = "流程实例编号")
|
||||
private String processInstanceId;
|
||||
@ -51,103 +99,4 @@ public class BpmOAContractCreateReqVO {
|
||||
|
||||
@Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<UploadUserFile> fileItems;
|
||||
|
||||
public BpmOAContractCreateReqVO() {
|
||||
}
|
||||
|
||||
public BpmOAContractCreateReqVO(String contractName, String contractNumber, LocalDate signingDate,
|
||||
String mCompanyName, String mHeadName, String oCompanyName,
|
||||
String oHeadName, String processInstanceId, List<UploadUserFile> fileItems,
|
||||
Integer result) {
|
||||
this.contractName = contractName;
|
||||
this.contractNumber = contractNumber;
|
||||
this.signingDate = signingDate;
|
||||
this.mCompanyName = mCompanyName;
|
||||
this.mHeadName = mHeadName;
|
||||
this.oCompanyName = oCompanyName;
|
||||
this.oHeadName = oHeadName;
|
||||
this.processInstanceId = processInstanceId;
|
||||
this.result = result;
|
||||
this.fileItems = fileItems;
|
||||
}
|
||||
|
||||
public Integer getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(Integer result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public String getContractName() {
|
||||
return contractName;
|
||||
}
|
||||
|
||||
public String getProcessInstanceId() {
|
||||
return processInstanceId;
|
||||
}
|
||||
|
||||
public void setProcessInstanceId(String processInstanceId) {
|
||||
this.processInstanceId = processInstanceId;
|
||||
}
|
||||
|
||||
public void setContractName(String contractName) {
|
||||
this.contractName = contractName;
|
||||
}
|
||||
|
||||
public String getContractNumber() {
|
||||
return contractNumber;
|
||||
}
|
||||
|
||||
public void setContractNumber(String contractNumber) {
|
||||
this.contractNumber = contractNumber;
|
||||
}
|
||||
|
||||
public LocalDate getSigningDate() {
|
||||
return signingDate;
|
||||
}
|
||||
|
||||
public void setSigningDate(LocalDate signingDate) {
|
||||
this.signingDate = signingDate;
|
||||
}
|
||||
|
||||
public String getmCompanyName() {
|
||||
return mCompanyName;
|
||||
}
|
||||
|
||||
public void setmCompanyName(String mCompanyName) {
|
||||
this.mCompanyName = mCompanyName;
|
||||
}
|
||||
|
||||
public String getmHeadName() {
|
||||
return mHeadName;
|
||||
}
|
||||
|
||||
public void setmHeadName(String mHeadName) {
|
||||
this.mHeadName = mHeadName;
|
||||
}
|
||||
|
||||
public String getoCompanyName() {
|
||||
return oCompanyName;
|
||||
}
|
||||
|
||||
public void setoCompanyName(String oCompanyName) {
|
||||
this.oCompanyName = oCompanyName;
|
||||
}
|
||||
|
||||
public String getoHeadName() {
|
||||
return oHeadName;
|
||||
}
|
||||
|
||||
public void setoHeadName(String oHeadName) {
|
||||
this.oHeadName = oHeadName;
|
||||
}
|
||||
|
||||
public List<UploadUserFile> getFileItems() {
|
||||
return fileItems;
|
||||
}
|
||||
|
||||
public void setFileItems(List<UploadUserFile> fileItems) {
|
||||
this.fileItems = fileItems;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,43 @@
|
||||
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Schema(description = "管理后台 - 合同审批分页 Request VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class BpmOAContractPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "合同类型 | 字典值 bpm_oa_contract_type", example = "1")
|
||||
private Integer contractType;
|
||||
|
||||
@Schema(description = "客户名称,模糊匹配")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "合同名称,模糊匹配")
|
||||
private String contractName;
|
||||
|
||||
@Schema(description = "合同编号")
|
||||
private String contractNo;
|
||||
|
||||
@Schema(description = "审批结果")
|
||||
private Integer result;
|
||||
|
||||
@Schema(description = "合同状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "签约人名称")
|
||||
private String signatoryName;
|
||||
|
||||
@Schema(description = "创建人名称")
|
||||
private String createName;
|
||||
|
||||
@Schema(description = "查询模式")
|
||||
private String relation;
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract;
|
||||
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOABaseRespVO;
|
||||
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOABaseRespVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalDate;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
|
||||
@ -19,31 +18,81 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
|
||||
@Data
|
||||
public class BpmOAContractRespVO extends BpmOABaseRespVO {
|
||||
|
||||
@Schema(description = "发起人用户编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "合同类型 | 字典值 bpm_oa_contract_type", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Integer contractType;
|
||||
|
||||
@Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "合同名称不能为空")
|
||||
private String contractName;
|
||||
|
||||
@Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "合同编号不能为空")
|
||||
private String contractNumber;
|
||||
private String contractNo;
|
||||
|
||||
@Schema(description = "签约日期", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "签约日期不能为空")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate signingDate;
|
||||
private String signingDate;
|
||||
|
||||
@Schema(description = "我方公司名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String mCompanyName;
|
||||
@Schema(description = "客户编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "我方负责人", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String mHeadName;
|
||||
@Schema(description = "客户名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "对方公司名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String oCompanyName;
|
||||
@Schema(description = "客户签约人(联系人ID)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long contactsId;
|
||||
|
||||
@Schema(description = "对方负责人", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String oHeadName;
|
||||
@Schema(description = "客户签约人(联系人)名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String contactsName;
|
||||
|
||||
@Schema(description = "签约公司编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long companyId;
|
||||
|
||||
@Schema(description = "签约公司名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String companyName;
|
||||
|
||||
@Schema(description = "签约人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long signatoryId;
|
||||
|
||||
@Schema(description = "签约人名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String signatoryName;
|
||||
|
||||
@Schema(description = "合同金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal contractMoney;
|
||||
|
||||
@Schema(description = "已收/已付金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal returnMoney;
|
||||
|
||||
@Schema(description = "已开票金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal invoiceMoney;
|
||||
|
||||
@Schema(description = "产品总金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal totalPrice;
|
||||
|
||||
@Schema(description = "整单优惠金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private BigDecimal discountRate;
|
||||
|
||||
@Schema(description = "商机ID", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long businessId;
|
||||
|
||||
@Schema(description = "商机名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String businessName;
|
||||
|
||||
@Schema(description = "合同开始时间", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private String startDate;
|
||||
|
||||
@Schema(description = "合同结束时间", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private String endDate;
|
||||
|
||||
@Schema(description = "合同状态 | 1已签约 2过期", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<UploadUserFile> fileItems;
|
||||
|
||||
@Schema(description = "创建人名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String createName;
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 合同审批 请求Request VO")
|
||||
@Data
|
||||
public class ContractStatisticsRespVO {
|
||||
|
||||
@Schema(description = "用户编号")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "今日新增合同数")
|
||||
private Integer todayAdditions;
|
||||
|
||||
@Schema(description = "昨日新增合同数")
|
||||
private Integer yesterdayAdditions;
|
||||
|
||||
@Schema(description = "较昨日百分比 | 数量")
|
||||
private BigDecimal countPercentage;
|
||||
|
||||
@Schema(description = "今日新增合同金额")
|
||||
private BigDecimal todayAddMoney;
|
||||
|
||||
@Schema(description = "昨日新增合同金额")
|
||||
private BigDecimal yesterdayAddMoney;
|
||||
|
||||
@Schema(description = "较昨日百分比 | 金额")
|
||||
private BigDecimal moneyPercentage;
|
||||
|
||||
@Schema(description = "合同总数")
|
||||
private Integer count;
|
||||
|
||||
@Schema(description = "合同总金额")
|
||||
private BigDecimal money;
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 合同产品关联 Response VO")
|
||||
@Data
|
||||
public class CrmContractProductVO {
|
||||
|
||||
@Schema(description = "合同编号")
|
||||
private Long contractId;
|
||||
|
||||
@Schema(description = "产品编号")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "产品名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "产品属性")
|
||||
private String productAttrUnique;
|
||||
|
||||
@Schema(description = "产品单价")
|
||||
private BigDecimal price;
|
||||
|
||||
@Schema(description = "数量")
|
||||
private Integer nums;
|
||||
|
||||
@Schema(description = "折扣")
|
||||
private BigDecimal discount;
|
||||
|
||||
@Schema(description = "小计")
|
||||
private BigDecimal subtotal;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remarks;
|
||||
}
|
@ -21,8 +21,35 @@ public class BpmOAInvoiceCreateReqVO {
|
||||
@NotNull(message = "计划开票日期不能为空")
|
||||
private LocalDate invoiceDate;
|
||||
|
||||
@Schema(description = "项目编号")
|
||||
private Long projectId;
|
||||
@Schema(description = "关联合同业务编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "合同编号不能为空")
|
||||
private Long contractId;
|
||||
|
||||
@Schema(description = "关联合同流程实例编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String contractInstanceId;
|
||||
|
||||
@Schema(description = "客户编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "开票主体", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "开票主体不能为空")
|
||||
private String invoiceBody;
|
||||
|
||||
@Schema(description = "发票抬头", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "发票抬头不能为空")
|
||||
private String invoiceName;
|
||||
|
||||
@Schema(description = "抬头类型 | 1企业2个人3事业单位", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "抬头类型不能为空")
|
||||
private Integer invoiceIssue;
|
||||
|
||||
@Schema(description = "发票类型 | 1普票 2专票", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "发票类型不能为空")
|
||||
private Integer invoiceType;
|
||||
|
||||
@Schema(description = "统一社会信用代码", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "统一社会信用代码不能为空")
|
||||
private String registerNo;
|
||||
|
||||
@Schema(description = "开票金额", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "开票金额不能为空")
|
||||
@ -32,14 +59,6 @@ public class BpmOAInvoiceCreateReqVO {
|
||||
@NotNull(message = "开票内容不能为空")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "开票单位名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "开票单位名称不能为空")
|
||||
private String unitName;
|
||||
|
||||
@Schema(description = "开票单位纳税人识别号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "开票单位纳税人识别号不能为空")
|
||||
private String unitTin;
|
||||
|
||||
@Schema(description = "开票单位地址")
|
||||
private String unitAddress;
|
||||
|
||||
@ -52,8 +71,11 @@ public class BpmOAInvoiceCreateReqVO {
|
||||
@Schema(description = "开票单位银行账号")
|
||||
private String unitBankNo;
|
||||
|
||||
@Schema(description = "关联合同业务流程编号")
|
||||
private String contractInstanceId;
|
||||
@Schema(description = "开票单位邮箱")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "开票状态", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "流程实例编号")
|
||||
private String processInstanceId;
|
||||
|
@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.invoice;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Schema(description = "管理后台 - 合同审批分页 Request VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class BpmOAInvoicePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "合同名称")
|
||||
private String contractName;
|
||||
|
||||
@Schema(description = "客户名称,模糊匹配")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "审批结果")
|
||||
private Integer result;
|
||||
|
||||
@Schema(description = "开票状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "查询模式")
|
||||
private String relation;
|
||||
}
|
@ -20,8 +20,35 @@ public class BpmOAInvoiceRespVO extends BpmOABaseRespVO {
|
||||
@Schema(description = "计划开票日期", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDate invoiceDate;
|
||||
|
||||
@Schema(description = "项目编号")
|
||||
private Long projectId;
|
||||
@Schema(description = "关联合同业务编号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long contractId;
|
||||
|
||||
@Schema(description = "合同名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String contractName;
|
||||
|
||||
@Schema(description = "关联合同流程实例编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String contractInstanceId;
|
||||
|
||||
@Schema(description = "客户编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "客户名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "开票主体", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String invoiceBody;
|
||||
|
||||
@Schema(description = "发票抬头", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String invoiceName;
|
||||
|
||||
@Schema(description = "抬头类型 | 1企业2个人3事业单位", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Integer invoiceIssue;
|
||||
|
||||
@Schema(description = "发票类型 | 1普票 2专票", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Integer invoiceType;
|
||||
|
||||
@Schema(description = "统一社会信用代码", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String registerNo;
|
||||
|
||||
@Schema(description = "开票金额", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private BigDecimal amount;
|
||||
@ -29,12 +56,6 @@ public class BpmOAInvoiceRespVO extends BpmOABaseRespVO {
|
||||
@Schema(description = "开票内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String content;
|
||||
|
||||
@Schema(description = "开票单位名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String unitName;
|
||||
|
||||
@Schema(description = "开票单位纳税人识别号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String unitTin;
|
||||
|
||||
@Schema(description = "开票单位地址")
|
||||
private String unitAddress;
|
||||
|
||||
@ -47,9 +68,12 @@ public class BpmOAInvoiceRespVO extends BpmOABaseRespVO {
|
||||
@Schema(description = "开票单位银行账号")
|
||||
private String unitBankNo;
|
||||
|
||||
@Schema(description = "关联合同业务流程编号")
|
||||
private String contractInstanceId;
|
||||
@Schema(description = "开票单位邮箱")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "上传文件")
|
||||
@Schema(description = "开票状态", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<UploadUserFile> fileItems ;
|
||||
}
|
||||
|
@ -5,17 +5,25 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
|
||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.BpmOAContractRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.invoice.BpmOAInvoiceRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmHistoryProcessInstanceDO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAContractService;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAInvoiceService;
|
||||
import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService;
|
||||
import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
|
||||
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 com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
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.flowable.task.api.history.HistoricTaskInstance;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -36,6 +44,7 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLogi
|
||||
@RestController
|
||||
@RequestMapping("/bpm/task")
|
||||
@Validated
|
||||
@Slf4j
|
||||
@DataPermission(enable = false)
|
||||
public class BpmTaskController {
|
||||
|
||||
@ -51,9 +60,16 @@ public class BpmTaskController {
|
||||
@Resource
|
||||
private DeptApi deptApi;
|
||||
|
||||
@Resource
|
||||
private BpmOAContractService bpmOAContractService;
|
||||
|
||||
@Resource
|
||||
private BpmOAInvoiceService bpmOAInvoiceService;
|
||||
|
||||
/**
|
||||
* add by yaojun 2024.1.3
|
||||
* 流程审核添加了抄送用户(多用户)的功能
|
||||
*
|
||||
* @param pageReqVO
|
||||
* @return
|
||||
*/
|
||||
@ -213,7 +229,7 @@ public class BpmTaskController {
|
||||
if (CollUtil.isEmpty(userIds)) {
|
||||
return success(userRespDTO);
|
||||
}
|
||||
Map<Long, AdminUserRespDTO> userMap = userApi.getUserMap(userIds.stream().map(Long::parseLong).collect(Collectors.toList()));
|
||||
Map<Long, AdminUserRespDTO> userMap = userApi.getUserMap(userIds.stream().map(Long::parseLong).collect(Collectors.toList()));
|
||||
|
||||
return success(convertList(userIds, id -> userMap.get(Long.valueOf(id))));
|
||||
}
|
||||
@ -236,9 +252,43 @@ public class BpmTaskController {
|
||||
|
||||
@GetMapping("getCurrentToDoProcessInstacePreAndNex-page")
|
||||
@Operation(summary = "获取当前待处理流程实例(带查询条件),上一个流程和下一个流程的实例ID")
|
||||
public CommonResult<Map<String,String>> getCurrentToDoProcessInstacePreAndNex(@RequestParam("processInstanceId") String processInstanceId,@Valid BpmTaskTodoPageReqVO pageVO) {
|
||||
public CommonResult<Map<String, String>> getCurrentToDoProcessInstacePreAndNex(@RequestParam("processInstanceId") String processInstanceId, @Valid BpmTaskTodoPageReqVO pageVO) {
|
||||
return success(taskService.getCurrentToDoProcessInstacePreAndNex(getLoginUserId(), processInstanceId, pageVO));
|
||||
}
|
||||
|
||||
@GetMapping("/get-crm-task")
|
||||
@Operation(summary = "获得CRM审批任务")
|
||||
@Parameter(name = "processDefinitionId", description = "流程定义编号", required = true, example = "1024")
|
||||
@Parameter(name = "isTodo", description = "是否待办", required = true)
|
||||
public CommonResult<PageResult<Map<String, Object>>> getCrmTask(BpmCrmTaskPageReqVO pageReqVO) {
|
||||
|
||||
List<Map<String, Object>> respVOs = new ArrayList<>();
|
||||
|
||||
PageResult<BpmTaskExtDO> tasks = taskService.getCrmTask(getLoginUserId(), pageReqVO);
|
||||
// 获取流程实例编号
|
||||
List<String> processInstanceIds = tasks.getList().stream().map(BpmTaskExtDO::getProcessInstanceId).distinct().collect(Collectors.toList());
|
||||
|
||||
try {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
switch (pageReqVO.getProcessDefinitionId()) {
|
||||
case "oa_contract":
|
||||
List<BpmOAContractRespVO> contractRespVOS = bpmOAContractService.getListByProcessInstanceIds(processInstanceIds);
|
||||
respVOs = contractRespVOS.stream()
|
||||
.map(item -> objectMapper.convertValue(item, new TypeReference<Map<String, Object>>(){}))
|
||||
.collect(Collectors.toList());
|
||||
break;
|
||||
case "oa_invoice":
|
||||
List<BpmOAInvoiceRespVO> invoiceRespVOS = bpmOAInvoiceService.getListByProcessInstanceIds(processInstanceIds);
|
||||
respVOs = invoiceRespVOS.stream()
|
||||
.map(item -> objectMapper.convertValue(item, new TypeReference<Map<String, Object>>(){}))
|
||||
.collect(Collectors.toList());
|
||||
break;
|
||||
}
|
||||
|
||||
return success(new PageResult<>(respVOs, tasks.getTotal()));
|
||||
} catch (Exception e) {
|
||||
log.error("json parse err,json:{}", processInstanceIds, e);
|
||||
return success(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - CRM流程任务的分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class BpmCrmTaskPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "流程定义编号", example = "oa_contract")
|
||||
private String processDefinitionId;
|
||||
|
||||
@Schema(description = "是否是待办", example = "true")
|
||||
private Boolean isTodo;
|
||||
}
|
@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import lombok.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@ -21,13 +22,12 @@ import java.util.List;
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
//@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BpmOAContractDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 出差表单主键
|
||||
* 合同审批表单主键
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
@ -39,6 +39,11 @@ public class BpmOAContractDO extends BaseDO {
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 合同类型 | 字典值 bpm_oa_contract_type
|
||||
*/
|
||||
private Integer contractType;
|
||||
|
||||
/**
|
||||
* 合同名称
|
||||
*/
|
||||
@ -47,7 +52,7 @@ public class BpmOAContractDO extends BaseDO {
|
||||
/**
|
||||
* 合同编号
|
||||
*/
|
||||
private String contractNumber;
|
||||
private String contractNo;
|
||||
|
||||
/**
|
||||
* 签约日期
|
||||
@ -55,28 +60,82 @@ public class BpmOAContractDO extends BaseDO {
|
||||
private LocalDate signingDate;
|
||||
|
||||
/**
|
||||
* 我方公司名称
|
||||
* 客户编号
|
||||
*/
|
||||
private String mCompanyName;
|
||||
private Long customerId;
|
||||
|
||||
/**
|
||||
* 我方负责人
|
||||
* 客户名称
|
||||
*/
|
||||
private String mHeadName;
|
||||
private String customerName;
|
||||
|
||||
/**
|
||||
* 对方公司名称
|
||||
* 客户签约人(联系人ID)
|
||||
*/
|
||||
private String oCompanyName;
|
||||
private Long contactsId;
|
||||
|
||||
/**
|
||||
* 对方负责人
|
||||
* 客户签约人(联系人)名称
|
||||
*/
|
||||
private String oHeadName;
|
||||
private String contactsName;
|
||||
|
||||
/**
|
||||
* 用章的结果
|
||||
*
|
||||
* 签约公司编号
|
||||
*/
|
||||
private Long companyId;
|
||||
|
||||
/**
|
||||
* 签约人用户编号
|
||||
*/
|
||||
private Long signatoryId;
|
||||
|
||||
/**
|
||||
* 合同金额
|
||||
*/
|
||||
private BigDecimal contractMoney;
|
||||
|
||||
/**
|
||||
* 已收/已付金额
|
||||
*/
|
||||
private BigDecimal returnMoney;
|
||||
|
||||
/**
|
||||
* 已开票金额
|
||||
*/
|
||||
private BigDecimal invoiceMoney;
|
||||
|
||||
/**
|
||||
* 产品总金额
|
||||
*/
|
||||
private BigDecimal totalPrice;
|
||||
|
||||
/**
|
||||
* 整单优惠金额
|
||||
*/
|
||||
private BigDecimal discountRate;
|
||||
|
||||
/**
|
||||
* 商机ID
|
||||
*/
|
||||
private Long businessId;
|
||||
|
||||
/**
|
||||
* 合同有效期开始时间
|
||||
*/
|
||||
private LocalDate startDate;
|
||||
|
||||
/**
|
||||
* 合同有效期结束时间
|
||||
*/
|
||||
private LocalDate endDate;
|
||||
|
||||
/**
|
||||
* 合同状态 | 1已签约 2过期
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 审批结果
|
||||
* 枚举 {@link BpmProcessInstanceResultEnum}
|
||||
* 考虑到简单,所以直接复用了 BpmProcessInstanceResultEnum 枚举,也可以自己定义一个枚举哈
|
||||
*/
|
||||
|
@ -44,9 +44,44 @@ public class BpmOAInvoiceDO extends BaseDO {
|
||||
private LocalDate invoiceDate;
|
||||
|
||||
/**
|
||||
* 项目编号
|
||||
* 关联合同业务编号
|
||||
*/
|
||||
private Long projectId;
|
||||
private Long contractId;
|
||||
|
||||
/**
|
||||
* 关联合同业务的流程实例编号
|
||||
*/
|
||||
private String contractInstanceId;
|
||||
|
||||
/**
|
||||
* 客户编号
|
||||
*/
|
||||
private Long customerId;
|
||||
|
||||
/**
|
||||
* 开票主体
|
||||
*/
|
||||
private String invoiceBody;
|
||||
|
||||
/**
|
||||
* 发票抬头
|
||||
*/
|
||||
private String invoiceName;
|
||||
|
||||
/**
|
||||
* 抬头类型 | 1企业2个人3事业单位
|
||||
*/
|
||||
private Integer invoiceIssue;
|
||||
|
||||
/**
|
||||
* 发票类型 | 1普票 2专票
|
||||
*/
|
||||
private Integer invoiceType;
|
||||
|
||||
/**
|
||||
* 统一社会信用代码
|
||||
*/
|
||||
private String registerNo;
|
||||
|
||||
/**
|
||||
* 开票金额
|
||||
@ -58,16 +93,6 @@ public class BpmOAInvoiceDO extends BaseDO {
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 开票单位名称
|
||||
*/
|
||||
private String unitName;
|
||||
|
||||
/**
|
||||
* 开票单位纳税人识别号
|
||||
*/
|
||||
private String unitTin;
|
||||
|
||||
/**
|
||||
* 开票单位地址
|
||||
*/
|
||||
@ -89,9 +114,14 @@ public class BpmOAInvoiceDO extends BaseDO {
|
||||
private String unitBankNo;
|
||||
|
||||
/**
|
||||
* 关联合同业务流程编号
|
||||
* 接收发票邮箱
|
||||
*/
|
||||
private String contractInstanceId;
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 开票状态 | 0未开票 1已开票
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 申请的结果
|
||||
|
@ -1,8 +1,18 @@
|
||||
package cn.iocoder.yudao.module.bpm.dal.mysql.oa;
|
||||
|
||||
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.bpm.controller.admin.oa.vo.contract.BpmOAContractPageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.BpmOAContractRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.ContractStatisticsRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAContractDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 合同审批 Mapper
|
||||
@ -12,4 +22,50 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
*/
|
||||
@Mapper
|
||||
public interface BpmOAContractMapper extends BaseMapperX<BpmOAContractDO> {
|
||||
default PageResult<BpmOAContractRespVO> selectPage(BpmOAContractPageReqVO pageReqVO,
|
||||
Long userId) {
|
||||
|
||||
MPJLambdaWrapperX<BpmOAContractDO> query = new MPJLambdaWrapperX<>();
|
||||
query.selectAll(BpmOAContractDO.class);
|
||||
query.selectAs("u.nickname", BpmOAContractRespVO::getSignatoryName);
|
||||
query.selectAs("u1.nickname", BpmOAContractRespVO::getCreateName);
|
||||
query.selectAs("d.name", BpmOAContractRespVO::getCompanyName);
|
||||
query.leftJoin("system_users u on u.id = t.signatory_id");
|
||||
query.leftJoin("system_users u1 on u1.id = t.creator");
|
||||
query.leftJoin("system_dept d on d.id = t.company_id");
|
||||
query.eqIfPresent(BpmOAContractDO::getContractType, pageReqVO.getContractType());
|
||||
query.likeIfPresent(BpmOAContractDO::getContractName, pageReqVO.getContractName());
|
||||
query.likeIfPresent(BpmOAContractDO::getContractNo, pageReqVO.getContractNo());
|
||||
query.likeIfPresent(BpmOAContractDO::getCustomerName, pageReqVO.getCustomerName());
|
||||
query.eqIfPresent(BpmOAContractDO::getStatus, pageReqVO.getStatus());
|
||||
query.eqIfPresent(BpmOAContractDO::getResult, pageReqVO.getResult());
|
||||
query.apply(Objects.nonNull(pageReqVO.getSignatoryName()),"u.nickname Like CONCAT('%', {0}, '%')", pageReqVO.getSignatoryName());
|
||||
query.apply(Objects.nonNull(pageReqVO.getCreateName()),"u1.nickname Like CONCAT('%', {0}, '%')", pageReqVO.getCreateName());
|
||||
if ("my".equals(pageReqVO.getRelation())) {
|
||||
query.eq(BpmOAContractDO::getUserId, userId);
|
||||
}else if ("sub".equals(pageReqVO.getRelation())){
|
||||
query.innerJoin("(" +
|
||||
"\tSELECT DISTINCT\n" +
|
||||
"\t\tu.id \n" +
|
||||
"\tFROM\n" +
|
||||
"\t\tsystem_users u\n" +
|
||||
"\t\tINNER JOIN system_dept d ON d.leader_user_id = "+ userId +"\n" +
|
||||
"\t\tINNER JOIN system_dept d1 ON d1.flag LIKE CONCAT( '%', d.id, '-' ) \n" +
|
||||
"\t\tOR d1.flag LIKE CONCAT( '%-', d.id, '-%' ) \n" +
|
||||
"\t\tOR d1.flag LIKE CONCAT( '-', d.id, '%' ) \n" +
|
||||
"\tWHERE\n" +
|
||||
"\t\tu.dept_id = d1.id \n" +
|
||||
"\t\tAND u.STATUS = 0 \n" +
|
||||
"\t) subordinate ON subordinate.id = t.user_id");
|
||||
}
|
||||
query.orderByDesc(BpmOAContractDO::getCreateTime);
|
||||
|
||||
return selectJoinPage(pageReqVO, BpmOAContractRespVO.class, query);
|
||||
}
|
||||
|
||||
ContractStatisticsRespVO selectContractStatistics(@Param("userId") Long userId,
|
||||
@Param("relation") String relation);
|
||||
|
||||
List<ContractStatisticsRespVO> selectContractStatisticsListByUserIds(@Param("userIds") List<Long> userIds,
|
||||
@Param("createTime") LocalDateTime[] createTime);
|
||||
}
|
||||
|
@ -1,9 +1,61 @@
|
||||
package cn.iocoder.yudao.module.bpm.dal.mysql.oa;
|
||||
|
||||
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.bpm.controller.admin.oa.vo.invoice.BpmOAInvoicePageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.invoice.BpmOAInvoiceRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAContractDO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAInvoiceDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Mapper
|
||||
public interface BpmOAInvoiceMapper extends BaseMapperX<BpmOAInvoiceDO> {
|
||||
|
||||
default PageResult<BpmOAInvoiceRespVO> selectPage(BpmOAInvoicePageReqVO pageReqVO,
|
||||
Long userId) {
|
||||
|
||||
MPJLambdaWrapperX<BpmOAInvoiceDO> query = new MPJLambdaWrapperX<>();
|
||||
query.selectAll(BpmOAInvoiceDO.class);
|
||||
query.selectAs(BpmOAContractDO::getContractName, BpmOAInvoiceRespVO::getContractName);
|
||||
query.selectAs(BpmOAContractDO::getCustomerName, BpmOAInvoiceRespVO::getCustomerName);
|
||||
query.leftJoin(BpmOAContractDO.class, "c", BpmOAContractDO::getId, BpmOAInvoiceDO::getContractId);
|
||||
query.apply(Objects.nonNull(pageReqVO.getContractName()), "c.contract_name LIKE CONCAT('%', {0}, '%')", pageReqVO.getContractName());
|
||||
query.apply(Objects.nonNull(pageReqVO.getCustomerName()), "c.customer_name LIKE CONCAT('%', {0}, '%')", pageReqVO.getCustomerName());
|
||||
if ("my".equals(pageReqVO.getRelation())) {
|
||||
query.eq(BpmOAContractDO::getUserId, userId);
|
||||
}else if ("sub".equals(pageReqVO.getRelation())){
|
||||
query.innerJoin("(" +
|
||||
"\tSELECT DISTINCT\n" +
|
||||
"\t\tu.id \n" +
|
||||
"\tFROM\n" +
|
||||
"\t\tsystem_users u\n" +
|
||||
"\t\tINNER JOIN system_dept d ON d.leader_user_id = "+ userId +"\n" +
|
||||
"\t\tINNER JOIN system_dept d1 ON d1.flag LIKE CONCAT( '%', d.id, '-' ) \n" +
|
||||
"\t\tOR d1.flag LIKE CONCAT( '%-', d.id, '-%' ) \n" +
|
||||
"\t\tOR d1.flag LIKE CONCAT( '-', d.id, '%' ) \n" +
|
||||
"\tWHERE\n" +
|
||||
"\t\tu.dept_id = d1.id \n" +
|
||||
"\t\tAND u.STATUS = 0 \n" +
|
||||
"\t) subordinate ON subordinate.id = t.user_id");
|
||||
}
|
||||
query.orderByDesc(BpmOAInvoiceDO::getCreateTime);
|
||||
|
||||
return selectJoinPage(pageReqVO, BpmOAInvoiceRespVO.class, query);
|
||||
}
|
||||
|
||||
default List<BpmOAInvoiceRespVO> selectListByProcessInstanceIds(List<String> processInstanceIds) {
|
||||
|
||||
MPJLambdaWrapperX<BpmOAInvoiceDO> query = new MPJLambdaWrapperX<>();
|
||||
query.selectAll(BpmOAInvoiceDO.class);
|
||||
query.selectAs(BpmOAContractDO::getContractName, BpmOAInvoiceRespVO::getContractName);
|
||||
query.selectAs(BpmOAContractDO::getCustomerName, BpmOAInvoiceRespVO::getCustomerName);
|
||||
query.leftJoin(BpmOAContractDO.class, BpmOAContractDO::getId, BpmOAInvoiceDO::getContractId);
|
||||
query.inIfPresent(BpmOAInvoiceDO::getProcessInstanceId, processInstanceIds);
|
||||
|
||||
return selectJoinList(BpmOAInvoiceRespVO.class, query);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package cn.iocoder.yudao.module.bpm.dal.mysql.oa;
|
||||
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOALeaveRpcVO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.leave.BpmOALeaveRpcVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeavePageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOALeaveDO;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
|
@ -1,7 +1,9 @@
|
||||
package cn.iocoder.yudao.module.bpm.dal.mysql.task;
|
||||
|
||||
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.bpm.controller.admin.task.vo.task.BpmCrmTaskPageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
|
||||
@ -11,6 +13,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@ -61,4 +64,15 @@ public interface BpmTaskExtMapper extends BaseMapperX<BpmTaskExtDO> {
|
||||
|
||||
List<Long> selectTodoTaskDept(@Param("reqVO") BpmTaskTodoPageReqVO pageVO,
|
||||
@Param("userId") Long userId);
|
||||
|
||||
default PageResult<BpmTaskExtDO> selectCrmPage(Long userId, BpmCrmTaskPageReqVO pageReqVO) {
|
||||
|
||||
List<Integer> approveOrReject = Arrays.asList(BpmProcessInstanceResultEnum.APPROVE.getResult(), BpmProcessInstanceResultEnum.REJECT.getResult());
|
||||
|
||||
return selectPage(pageReqVO, new LambdaQueryWrapperX<BpmTaskExtDO>()
|
||||
.eq(BpmTaskExtDO::getAssigneeUserId, userId)
|
||||
.likeIfPresent(BpmTaskExtDO::getProcessDefinitionId, pageReqVO.getProcessDefinitionId())
|
||||
.eq(pageReqVO.getIsTodo(), BpmTaskExtDO::getResult, BpmProcessInstanceResultEnum.PROCESS.getResult())
|
||||
.in(!pageReqVO.getIsTodo(), BpmTaskExtDO::getResult, approveOrReject));
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,12 @@
|
||||
package cn.iocoder.yudao.module.bpm.framework.rpc.config;
|
||||
|
||||
import cn.iocoder.yudao.module.hrm.api.crmbusiness.BusinessApi;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcontract.ContractApi;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcustomer.CrmCustomerApi;
|
||||
import cn.iocoder.yudao.module.infra.api.config.ConfigApi;
|
||||
import cn.iocoder.yudao.module.infra.api.file.FileApi;
|
||||
import cn.iocoder.yudao.module.product.api.storeproduct.StoreProductApi;
|
||||
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.StoreProductAttrValueApi;
|
||||
import cn.iocoder.yudao.module.system.api.assetreceive.AssetReceiveApi;
|
||||
import cn.iocoder.yudao.module.system.api.assets.AssetsApi;
|
||||
import cn.iocoder.yudao.module.system.api.assets.AssetsTypeApi;
|
||||
@ -34,7 +39,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
@EnableFeignClients(clients = {FileApi.class, RoleApi.class, DeptApi.class, PostApi.class, AdminUserApi.class, SmsSendApi.class, DictDataApi.class, NotifyMessageSendApi.class,
|
||||
SubscribeMessageSendApi.class, SocialClientApi.class, UsersExtApi.class, AttendanceApi.class, BankApi.class, ConfigApi.class, PositionApi.class, SupplierApi.class, AssetsApi.class,
|
||||
AssetsTypeApi.class, AssetReceiveApi.class, AttendanceApi.class, AttendanceGroupApi.class, WorkOvertimeApi.class, HolidayApi.class,
|
||||
RentalOrderApi.class, RentalDepositRecordApi.class, ProjectApi.class, RentalItemsRecordApi.class,AdminOauthUserOtherInfoApi.class
|
||||
RentalOrderApi.class, RentalDepositRecordApi.class, ProjectApi.class, RentalItemsRecordApi.class,AdminOauthUserOtherInfoApi.class, StoreProductAttrValueApi.class, StoreProductApi.class,
|
||||
ContractApi.class, BusinessApi.class, CrmCustomerApi.class
|
||||
})
|
||||
public class RpcConfiguration {
|
||||
}
|
||||
|
@ -1,15 +1,22 @@
|
||||
package cn.iocoder.yudao.module.bpm.service.oa;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.BpmOAContractVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.BpmOAContractCreateReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.BpmOAContractPageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.BpmOAContractRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.ContractStatisticsRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAContractDO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
public interface BpmOAContractService {
|
||||
|
||||
/**
|
||||
* 创建出差申请
|
||||
* 创建合同申请
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param createReqVO 创建信息
|
||||
@ -18,15 +25,28 @@ public interface BpmOAContractService {
|
||||
Long createContract(Long userId, @Valid BpmOAContractCreateReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 更新出差申请的状态
|
||||
* 更新合同
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updateContract(BpmOAContractDO updateReqVO);
|
||||
|
||||
/**
|
||||
* 修改开票金额
|
||||
* @param contractId 合同编号
|
||||
* @param amount 开票金额
|
||||
*/
|
||||
void updateInvoiceMoney(Long contractId, BigDecimal amount);
|
||||
|
||||
/**
|
||||
* 更新合同申请的状态
|
||||
*
|
||||
* @param id 编号
|
||||
* @param result 结果
|
||||
*/
|
||||
void updateContractResult(Long id, Integer result);
|
||||
void updateContractResult(String processInstanceId, Long id, Integer result);
|
||||
|
||||
/**
|
||||
* 获得出差申请
|
||||
* 获得合同申请
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 出差申请
|
||||
@ -34,7 +54,7 @@ public interface BpmOAContractService {
|
||||
BpmOAContractDO getContract(Long id);
|
||||
|
||||
/**
|
||||
* 获得指定出差申请
|
||||
* 获得指定合同申请
|
||||
* @param processInstanceId 流程实例编号
|
||||
* @return 出差申请
|
||||
*/
|
||||
@ -46,4 +66,42 @@ public interface BpmOAContractService {
|
||||
* @return 合同列表
|
||||
*/
|
||||
List<BpmOAContractDO> getListByDeptId(List<Long> userIds);
|
||||
|
||||
/**
|
||||
* 获得合同分页
|
||||
* @param pageReqVO 分页参数
|
||||
* @return 分页列表
|
||||
*/
|
||||
PageResult<BpmOAContractRespVO> getContractPage(BpmOAContractPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 获得指定流程实例的合同申请列表
|
||||
* @param processInstanceIds 流程实例编号集合
|
||||
* @return 合同列表
|
||||
*/
|
||||
List<BpmOAContractRespVO> getListByProcessInstanceIds(List<String> processInstanceIds);
|
||||
|
||||
/**
|
||||
* 获得合同统计信息
|
||||
* @param userId 用户编号
|
||||
* @param relation 查询类型
|
||||
* @return 统计信息
|
||||
*/
|
||||
ContractStatisticsRespVO getContractStatistics(Long userId, String relation);
|
||||
|
||||
/**
|
||||
* 获得指定用户的合同统计信息列表
|
||||
*
|
||||
* @param userIds 用户编号集合
|
||||
* @param createTime 创建时间
|
||||
* @return 合同统计信息列表
|
||||
*/
|
||||
List<ContractStatisticsRespVO> getContractStatisticsListByUserIds(List<Long> userIds, LocalDateTime[] createTime);
|
||||
|
||||
/**
|
||||
* 获得合同列表
|
||||
* @param respVO 参数列表
|
||||
* @return 合同列表
|
||||
*/
|
||||
List<BpmOAContractDO> getContractList(BpmOAContractVO respVO);
|
||||
}
|
||||
|
@ -1,26 +1,62 @@
|
||||
package cn.iocoder.yudao.module.bpm.service.oa;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
|
||||
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.BpmOAContractCreateReqVO;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
|
||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.BpmOAContractVO;
|
||||
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.*;
|
||||
import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAContractConvert;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAContractDO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAContractMapper;
|
||||
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
||||
import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService;
|
||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcontract.ContractApi;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcontract.dto.CrmContractProductDTO;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcustomer.CrmCustomerApi;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcustomer.dto.CrmCustomerDTO;
|
||||
import cn.iocoder.yudao.module.product.api.storeproduct.StoreProductApi;
|
||||
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.StoreProductAttrValueApi;
|
||||
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.dto.StoreProductAttrValueApiDTO;
|
||||
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.vo.StoreProductAttrValueApiVO;
|
||||
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 com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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.date.DateUtils.SECOND_MILLIS;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_CONTRACT_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PRODUCT_STOCK_LESS;
|
||||
|
||||
/**
|
||||
* OA 合同审批 Service 实现类
|
||||
@ -30,6 +66,7 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_CONTRACT_N
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAContractService{
|
||||
|
||||
/**
|
||||
@ -41,28 +78,79 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
|
||||
private BpmOAContractMapper contractMapper;
|
||||
|
||||
@Resource
|
||||
private BpmProcessInstanceApi processInstanceApi;
|
||||
private BpmProcessInstanceService processInstanceService;
|
||||
|
||||
@Resource
|
||||
private BpmHistoryProcessInstanceService historyProcessInstanceService;
|
||||
|
||||
@Resource
|
||||
private RedissonClient redissonClient;
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Resource
|
||||
private AdminUserApi userApi;
|
||||
|
||||
@Resource
|
||||
private DeptApi deptApi;
|
||||
|
||||
@Resource
|
||||
private StoreProductAttrValueApi storeProductAttrValueApi;
|
||||
|
||||
@Resource
|
||||
private StoreProductApi storeProductApi;
|
||||
|
||||
@Resource
|
||||
private ContractApi contractApi;
|
||||
|
||||
@Resource
|
||||
private CrmCustomerApi customerApi;
|
||||
|
||||
@Override
|
||||
public Long createContract(Long userId, BpmOAContractCreateReqVO createReqVO) {
|
||||
// 新增合同DO
|
||||
BpmOAContractDO contract = BpmOAContractConvert.INSTANCE.convert(createReqVO)
|
||||
.setUserId(userId)
|
||||
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult())
|
||||
.setStatus(1);
|
||||
|
||||
//插入OA 出差申请
|
||||
BpmOAContractDO contract = BpmOAContractConvert.INSTANCE.convert(createReqVO).setUserId(userId)
|
||||
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
|
||||
contract.setMCompanyName(createReqVO.getmCompanyName());
|
||||
contract.setMHeadName(createReqVO.getmHeadName());
|
||||
contract.setOCompanyName(createReqVO.getoCompanyName());
|
||||
contract.setOHeadName(createReqVO.getoHeadName());
|
||||
// 自动生成合同编号
|
||||
// 获取当前日期
|
||||
String now = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||
String key = "bpm_contract_no_" + now;
|
||||
// 获取分布式锁
|
||||
String LOCK_KEY = "lock:rental:order:create";
|
||||
RLock lock = redissonClient.getLock(LOCK_KEY);
|
||||
try {
|
||||
lock.lock();
|
||||
// redis 获取当天订单号
|
||||
String no = stringRedisTemplate.opsForValue().get(key);
|
||||
if (no != null) {
|
||||
no = "HT" + now + String.format("%03d", Integer.parseInt(no) + 1);
|
||||
// redis 缓存订单号
|
||||
stringRedisTemplate.opsForValue().increment(key, 1);
|
||||
}else {
|
||||
no = "HT" + now + String.format("%03d", 1);
|
||||
// redis 缓存订单号
|
||||
stringRedisTemplate.opsForValue().set(key, "1", 1, TimeUnit.DAYS);
|
||||
}
|
||||
// 设置合同编号
|
||||
contract.setContractNo(no);
|
||||
} catch (Exception ex) {
|
||||
log.error("[messageResend][执行异常]", ex);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
//插入OA 合同审批
|
||||
contractMapper.insert(contract) ;
|
||||
|
||||
// 发起 BPM 流程
|
||||
Map<String, Object> processInstanceVariables = new HashMap<>();
|
||||
String processInstanceId = processInstanceApi.createProcessInstance(userId,
|
||||
String processInstanceId = processInstanceService.createProcessInstance(userId,
|
||||
new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY)
|
||||
.setVariables(processInstanceVariables).setBusinessKey(String.valueOf(contract.getId()))).getCheckedData();
|
||||
.setVariables(processInstanceVariables).setBusinessKey(String.valueOf(contract.getId())));
|
||||
|
||||
// 将工作流的编号,更新到 OA 请假单中
|
||||
contractMapper.updateById(new BpmOAContractDO().setId(contract.getId()).setProcessInstanceId(processInstanceId));
|
||||
@ -78,20 +166,74 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
|
||||
if (fileItems != null && !fileItems.isEmpty()) {
|
||||
uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ;
|
||||
}
|
||||
|
||||
// 同步插入关联产品记录
|
||||
createContractProductList(contract.getId(), createReqVO.getContractProducts());
|
||||
|
||||
return contract.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateContractResult(Long id, Integer result) {
|
||||
public void updateContract(BpmOAContractDO updateReqVO) {
|
||||
validateLeaveExists(updateReqVO.getId());
|
||||
|
||||
validateLeaveExists(id);
|
||||
contractMapper.updateById(new BpmOAContractDO().setId(id).setResult(result));
|
||||
//更新合同
|
||||
contractMapper.updateById(updateReqVO);
|
||||
}
|
||||
|
||||
private void validateLeaveExists(Long id) {
|
||||
if (contractMapper.selectById(id) == null) {
|
||||
@Override
|
||||
public void updateInvoiceMoney(Long contractId, BigDecimal amount) {
|
||||
|
||||
contractMapper.update(null, new LambdaUpdateWrapper<BpmOAContractDO>()
|
||||
.setSql("invoice_money = invoice_money - " + amount)
|
||||
.eq(BpmOAContractDO::getId, contractId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateContractResult(String processInstanceId, Long id, Integer result) {
|
||||
|
||||
BpmOAContractDO contract = validateLeaveExists(id);
|
||||
contractMapper.updateById(new BpmOAContractDO().setId(id).setResult(result));
|
||||
|
||||
//审核通过 (最后节点)
|
||||
if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) {
|
||||
|
||||
ProcessInstance instance = processInstanceService.getProcessInstance(processInstanceId);
|
||||
|
||||
if (instance.isEnded()) {
|
||||
|
||||
// 审批通过后,更新客户成交信息
|
||||
customerApi.updateCustomerPurchaseTotal(new CrmCustomerDTO()
|
||||
.setId(contract.getCustomerId())
|
||||
.setDealStatus(ShopCommonEnum.IS_STATUS_1.getValue())
|
||||
.setDealTime(LocalDateTime.now())
|
||||
.setPurchaseTotal(contract.getContractMoney()));
|
||||
}
|
||||
}
|
||||
|
||||
// -- 自己取消
|
||||
// -- 审核拒绝
|
||||
if (BpmProcessInstanceResultEnum.REJECT.getResult().equals(result)
|
||||
|| BpmProcessInstanceResultEnum.CANCEL.getResult().equals(result)
|
||||
|| BpmProcessInstanceResultEnum.BACK.getResult().equals(result)) {
|
||||
|
||||
// 获取合同商品详情
|
||||
List<CrmContractProductDTO> productDTOS = contractApi.getProduct(id).getCheckedData();
|
||||
|
||||
for (CrmContractProductDTO product : productDTOS) {
|
||||
// 回复商品库存
|
||||
this.inProductStock(product.getNums(), product.getProductId(), product.getProductAttrUnique());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BpmOAContractDO validateLeaveExists(Long id) {
|
||||
BpmOAContractDO contractDO = contractMapper.selectById(id);
|
||||
if (contractDO == null) {
|
||||
throw exception(OA_CONTRACT_NOT_EXISTS);
|
||||
}
|
||||
return contractDO;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -115,6 +257,169 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
|
||||
|
||||
return contractMapper.selectList(new LambdaQueryWrapperX<BpmOAContractDO>()
|
||||
.eq(BpmOAContractDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult())
|
||||
.inIfPresent(BpmOAContractDO::getUserId, userIds));
|
||||
.inIfPresent(BpmOAContractDO::getUserId, userIds)
|
||||
.eq(BpmOAContractDO::getContractType, 1)
|
||||
.apply("return_money > invoice_money"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<BpmOAContractRespVO> getContractPage(BpmOAContractPageReqVO pageReqVO) {
|
||||
|
||||
return contractMapper.selectPage(pageReqVO, getLoginUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BpmOAContractRespVO> getListByProcessInstanceIds(List<String> processInstanceIds) {
|
||||
|
||||
List<BpmOAContractDO> bpmOAContractDOS = contractMapper.selectList(new LambdaQueryWrapperX<BpmOAContractDO>()
|
||||
.inIfPresent(BpmOAContractDO::getProcessInstanceId, processInstanceIds));
|
||||
|
||||
List<BpmOAContractRespVO> respVOS = BeanUtils.toBean(bpmOAContractDOS, BpmOAContractRespVO.class);
|
||||
// 获取用户和签约人信息
|
||||
List<Long> userIds = bpmOAContractDOS.stream()
|
||||
.flatMap(item -> Stream.of(item.getUserId(), item.getSignatoryId()))
|
||||
.collect(Collectors.toList());
|
||||
Map<Long, AdminUserRespDTO> userMap = userApi.getUserMap(userIds);
|
||||
|
||||
// 获取公司信息
|
||||
Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(bpmOAContractDOS, BpmOAContractDO::getCompanyId));
|
||||
|
||||
respVOS.forEach(respVO -> {
|
||||
// 设置创建人、签约人名称
|
||||
respVO.setSignatoryName(userMap.get(respVO.getSignatoryId()) != null ? userMap.get(respVO.getSignatoryId()).getNickname() : null);
|
||||
respVO.setCreateName(userMap.get(respVO.getUserId()) != null ? userMap.get(respVO.getUserId()).getNickname() : null);
|
||||
|
||||
// 设置公司名称
|
||||
respVO.setCompanyName(deptMap.get(respVO.getCompanyId()) != null ? deptMap.get(respVO.getCompanyId()).getName() : null);
|
||||
});
|
||||
|
||||
return respVOS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContractStatisticsRespVO getContractStatistics(Long userId, String relation) {
|
||||
|
||||
ContractStatisticsRespVO respVO = contractMapper.selectContractStatistics(userId, relation);
|
||||
|
||||
// 设置数量、金额百分比
|
||||
respVO.setCountPercentage(calculatePercentageChange(respVO.getTodayAdditions(), respVO.getYesterdayAdditions()));
|
||||
respVO.setMoneyPercentage(calculatePercentageChange(respVO.getTodayAddMoney(), respVO.getYesterdayAddMoney()));
|
||||
return respVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ContractStatisticsRespVO> getContractStatisticsListByUserIds(List<Long> userIds, LocalDateTime[] createTime) {
|
||||
|
||||
return contractMapper.selectContractStatisticsListByUserIds(userIds, createTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BpmOAContractDO> getContractList(BpmOAContractVO respVO) {
|
||||
|
||||
Date[] dateArray = new Date[] { respVO.getStarTime(), respVO.getEndTime() };
|
||||
|
||||
return contractMapper.selectList(new LambdaQueryWrapperX<BpmOAContractDO>()
|
||||
.inIfPresent(BpmOAContractDO::getUserId, respVO.getUserId())
|
||||
.eqIfPresent(BpmOAContractDO::getContractType, respVO.getContractType())
|
||||
.betweenIfPresent(BpmOAContractDO::getSigningDate, dateArray)
|
||||
.eq(BpmOAContractDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult()));
|
||||
}
|
||||
|
||||
public static BigDecimal calculatePercentageChange(Object today, Object yesterday) {
|
||||
|
||||
// 转换为 BigDecimal 进行高精度计算
|
||||
BigDecimal bigToday = new BigDecimal(today.toString());
|
||||
BigDecimal bigYesterday = new BigDecimal(yesterday.toString());
|
||||
|
||||
if (bigYesterday.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
// 计算百分比变化
|
||||
BigDecimal difference = bigToday.subtract(bigYesterday); // a - b
|
||||
BigDecimal percentageChange = difference.divide(bigYesterday, 2, RoundingMode.HALF_UP); // (a - b) / b
|
||||
|
||||
// 转为百分比并返回
|
||||
return percentageChange.multiply(new BigDecimal(100)); // (result) * 100
|
||||
}
|
||||
|
||||
private void createContractProductList(Long contractId, List<CrmContractProductVO> list) {
|
||||
List<StoreProductAttrValueApiVO> storeProductAttrValueList = new ArrayList<>();
|
||||
if (CollUtil.isNotEmpty(list)) {
|
||||
List<Long> productIds = list.stream().map(CrmContractProductVO::getProductId).collect(Collectors.toList());
|
||||
List<String> productAttrUnique = list.stream().map(CrmContractProductVO::getProductAttrUnique).collect(Collectors.toList());
|
||||
storeProductAttrValueList = storeProductAttrValueApi.getStoreProductAttrValueList(new StoreProductAttrValueApiDTO()
|
||||
.setProductIds(productIds)
|
||||
.setUniques(productAttrUnique)).getCheckedData();
|
||||
}
|
||||
Map<String, List<StoreProductAttrValueApiVO>> map = storeProductAttrValueList.stream().collect(Collectors.groupingBy(a -> a.getProductId() + "_" + a.getUnique()));
|
||||
list.forEach(o -> {
|
||||
o.setContractId(contractId);
|
||||
//库存处理
|
||||
List<StoreProductAttrValueApiVO> storeProductAttrValueApiVOS = map.get(o.getProductId() + "_" + o.getProductAttrUnique());
|
||||
|
||||
int count = 0;
|
||||
if (CollUtil.isNotEmpty(storeProductAttrValueApiVOS)) {
|
||||
count = storeProductAttrValueApiVOS.stream().mapToInt(StoreProductAttrValueApiVO::getStock).sum();
|
||||
}
|
||||
if (NumberUtil.compare(count, o.getNums()) < 0) {
|
||||
throw exception(new ErrorCode(202408250, "该商品ID:" + o.getProductId() + "库存不足"));
|
||||
}
|
||||
// TODO: 2024/11/21 这里的库存扣件完后 - 如果审批不通过 库存退回
|
||||
this.decProductStock(o.getNums(), o.getProductId(), o.getProductAttrUnique());
|
||||
});
|
||||
|
||||
contractApi.createProduct(BeanUtils.toBean(list, CrmContractProductDTO.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 减少库存
|
||||
*
|
||||
* @param num 数量
|
||||
* @param productId 产品ID
|
||||
* @param unique sku唯一值
|
||||
*/
|
||||
private void decProductStock(int num, Long productId, String unique) {
|
||||
String lockKey = productId + "_" + unique;
|
||||
// -- 分布式锁
|
||||
RLock lock = redissonClient.getLock(lockKey);
|
||||
try {
|
||||
lock.lock(120 * SECOND_MILLIS, TimeUnit.MILLISECONDS);
|
||||
// 执行逻辑
|
||||
int res = 0;
|
||||
res = storeProductAttrValueApi.decStockIncSales(num, productId, unique).getCheckedData();
|
||||
|
||||
if (res == 0) {
|
||||
throw exception(PRODUCT_STOCK_LESS);
|
||||
}
|
||||
|
||||
int product = storeProductApi.decStockIncSales(num, productId).getCheckedData();
|
||||
if (product == 0) {
|
||||
throw exception(PRODUCT_STOCK_LESS);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加库存
|
||||
*
|
||||
* @param num 数量
|
||||
* @param productId 产品ID
|
||||
* @param unique sku唯一值
|
||||
*/
|
||||
private void inProductStock(int num, Long productId, String unique) {
|
||||
String lockKey = productId + "_" + unique;
|
||||
// -- 分布式锁
|
||||
RLock lock = redissonClient.getLock(lockKey);
|
||||
try {
|
||||
lock.lock(120 * SECOND_MILLIS, TimeUnit.MILLISECONDS);
|
||||
// 执行逻辑
|
||||
storeProductAttrValueApi.inStockIncSales(num, productId, unique).getCheckedData();
|
||||
storeProductApi.inStockIncSales(num, productId).getCheckedData();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
package cn.iocoder.yudao.module.bpm.service.oa;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.invoice.BpmOAInvoiceCreateReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.invoice.BpmOAInvoicePageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.invoice.BpmOAInvoiceRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAInvoiceDO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 开票申请 Service 接口
|
||||
@ -44,4 +48,18 @@ public interface BpmOAInvoiceService {
|
||||
* @return 开票申请
|
||||
*/
|
||||
BpmOAInvoiceDO getByProcessInstanceId(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获得开票申请分页列表
|
||||
* @param pageReqVO 分页参数
|
||||
* @return 开票分页
|
||||
*/
|
||||
PageResult<BpmOAInvoiceRespVO> getInvoicePage(BpmOAInvoicePageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 获得开票申请列表
|
||||
* @param processInstanceIds 流程实例编号
|
||||
* @return 开票申请列表
|
||||
*/
|
||||
List<BpmOAInvoiceRespVO> getListByProcessInstanceIds(List<String> processInstanceIds);
|
||||
}
|
||||
|
@ -1,25 +1,36 @@
|
||||
package cn.iocoder.yudao.module.bpm.service.oa;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
|
||||
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.invoice.BpmOAInvoiceCreateReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.invoice.BpmOAInvoicePageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.invoice.BpmOAInvoiceRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAContractDO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAInvoiceDO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAInvoiceMapper;
|
||||
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
||||
import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
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.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_INVOICE_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.SECOND_MILLIS;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* OA 开票申请 Service 实现类
|
||||
@ -45,12 +56,23 @@ public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAIn
|
||||
@Resource
|
||||
private BpmHistoryProcessInstanceService historyProcessInstanceService;
|
||||
|
||||
@Resource
|
||||
private BpmOAContractService contractService;
|
||||
|
||||
@Resource
|
||||
private RedissonClient redissonClient;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createInvoice(Long userId, BpmOAInvoiceCreateReqVO createReqVO) {
|
||||
|
||||
// 校验关联合同 是否还有开票余额
|
||||
validateContractBalance(createReqVO.getContractId(), createReqVO.getAmount());
|
||||
|
||||
//插入OA 开票申请
|
||||
BpmOAInvoiceDO invoice = BeanUtils.toBean(createReqVO, BpmOAInvoiceDO.class)
|
||||
.setUserId(userId)
|
||||
.setStatus(0)
|
||||
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
|
||||
invoiceMapper.insert(invoice) ;
|
||||
|
||||
@ -73,20 +95,75 @@ public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAIn
|
||||
if (fileItems != null && !fileItems.isEmpty()) {
|
||||
uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ;
|
||||
}
|
||||
|
||||
return invoice.getId();
|
||||
}
|
||||
|
||||
private void validateContractBalance(Long contractId, BigDecimal amount) {
|
||||
|
||||
String lockKey = "bpm:invoice:create_" + contractId;
|
||||
// -- 分布式锁
|
||||
RLock lock = redissonClient.getLock(lockKey);
|
||||
try {
|
||||
lock.lock(120 * SECOND_MILLIS, TimeUnit.MILLISECONDS);
|
||||
|
||||
// 获取合同信息
|
||||
BpmOAContractDO contractDO = contractService.getContract(contractId);
|
||||
if (contractDO == null) {
|
||||
throw exception(OA_CONTRACT_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 判断是否还有开票余额
|
||||
BigDecimal balance = contractDO.getReturnMoney().subtract(contractDO.getInvoiceMoney());
|
||||
if (balance.compareTo(amount) <= 0) {
|
||||
throw exception(OA_CONTRACT_INVOICE_AMOUNT_LACK);
|
||||
}
|
||||
|
||||
// 余额足够时 更新合同的开票金额
|
||||
contractService.updateContract(new BpmOAContractDO()
|
||||
.setId(contractDO.getId())
|
||||
.setInvoiceMoney(contractDO.getInvoiceMoney().add(amount)));
|
||||
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInvoiceResult(Long id, Integer result) {
|
||||
|
||||
validateLeaveExists(id);
|
||||
BpmOAInvoiceDO invoiceDO = validateLeaveExists(id);
|
||||
invoiceMapper.updateById(new BpmOAInvoiceDO().setId(id).setResult(result));
|
||||
|
||||
// -- 自己取消
|
||||
// -- 审核拒绝
|
||||
if (BpmProcessInstanceResultEnum.REJECT.getResult().equals(result)
|
||||
|| BpmProcessInstanceResultEnum.CANCEL.getResult().equals(result)
|
||||
|| BpmProcessInstanceResultEnum.BACK.getResult().equals(result)) {
|
||||
|
||||
String lockKey = "bpm:invoice:create_" + invoiceDO.getContractId();
|
||||
// -- 分布式锁
|
||||
RLock lock = redissonClient.getLock(lockKey);
|
||||
try {
|
||||
lock.lock(120 * SECOND_MILLIS, TimeUnit.MILLISECONDS);
|
||||
|
||||
// 取消时,回复合同之前的开票金额
|
||||
contractService.updateInvoiceMoney(invoiceDO.getContractId(), invoiceDO.getAmount());
|
||||
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void validateLeaveExists(Long id) {
|
||||
if (invoiceMapper.selectById(id) == null) {
|
||||
private BpmOAInvoiceDO validateLeaveExists(Long id) {
|
||||
BpmOAInvoiceDO invoice = invoiceMapper.selectById(id);
|
||||
if (invoice == null) {
|
||||
throw exception(OA_INVOICE_NOT_EXISTS);
|
||||
}
|
||||
|
||||
return invoice;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -104,4 +181,16 @@ public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAIn
|
||||
}
|
||||
return bpmOAInvoiceDOS.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<BpmOAInvoiceRespVO> getInvoicePage(BpmOAInvoicePageReqVO pageReqVO) {
|
||||
|
||||
return invoiceMapper.selectPage(pageReqVO, getLoginUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BpmOAInvoiceRespVO> getListByProcessInstanceIds(List<String> processInstanceIds) {
|
||||
|
||||
return invoiceMapper.selectListByProcessInstanceIds(processInstanceIds);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.bpm.service.oa;
|
||||
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOALeaveRpcVO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.leave.BpmOALeaveRpcVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeaveCreateReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeavePageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.CalculateAndVerifyLeaveDTO;
|
||||
|
@ -11,7 +11,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
|
||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOALeaveRpcVO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.leave.BpmOALeaveRpcVO;
|
||||
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
|
||||
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.leave.BpmOALeaveCreateReqVO;
|
||||
|
@ -28,6 +28,6 @@ public class BpmOAContractResultListener extends BpmProcessInstanceResultEventLi
|
||||
@Override
|
||||
protected void onEvent(BpmProcessInstanceResultEvent event) {
|
||||
|
||||
contractService.updateContractResult(Long.parseLong(event.getBusinessKey()), event.getResult());
|
||||
contractService.updateContractResult(event.getId(), Long.parseLong(event.getBusinessKey()), event.getResult());
|
||||
}
|
||||
}
|
||||
|
@ -264,4 +264,12 @@ public interface BpmTaskService {
|
||||
* @return 公司列表
|
||||
*/
|
||||
List<Long> getTodoTaskDept(BpmTaskTodoPageReqVO pageVO, Long userId);
|
||||
|
||||
/**
|
||||
* 获取CRM审批任务
|
||||
* @param userId 当前登录用户编号
|
||||
* @param pageReqVO 分页参数
|
||||
* @return CRM审批任务
|
||||
*/
|
||||
PageResult<BpmTaskExtDO> getCrmTask(Long userId, BpmCrmTaskPageReqVO pageReqVO);
|
||||
}
|
||||
|
@ -1513,5 +1513,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
||||
|
||||
return taskExtMapper.selectTodoTaskDept(pageVO, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<BpmTaskExtDO> getCrmTask(Long userId, BpmCrmTaskPageReqVO pageReqVO) {
|
||||
|
||||
return taskExtMapper.selectCrmPage(userId, pageReqVO);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAContractMapper">
|
||||
|
||||
<!--
|
||||
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
|
||||
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
|
||||
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
|
||||
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
|
||||
-->
|
||||
<select id="selectContractStatistics" resultType="cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.ContractStatisticsRespVO">
|
||||
SELECT
|
||||
COUNT( CASE WHEN DATE( a.create_time ) = CURDATE() THEN 1 END ) AS todayAdditions,
|
||||
COALESCE ( SUM( CASE WHEN DATE( a.create_time ) = CURDATE() THEN a.contract_money END ), 0 ) AS todayAddMoney,
|
||||
COUNT( CASE WHEN DATE( a.create_time ) = CURDATE() - INTERVAL 1 DAY THEN 1 END ) AS yesterdayAdditions,
|
||||
COALESCE ( SUM( CASE WHEN DATE( a.create_time ) = CURDATE() - INTERVAL 1 DAY THEN a.contract_money END ), 0 ) AS yesterdayAddMoney
|
||||
FROM
|
||||
bpm_oa_contract a
|
||||
<if test="relation == 'sub'">
|
||||
INNER JOIN (
|
||||
SELECT DISTINCT
|
||||
u.id
|
||||
FROM
|
||||
system_users u
|
||||
INNER JOIN system_dept d ON d.leader_user_id = #{userId}
|
||||
INNER JOIN system_dept d1 ON d1.flag LIKE CONCAT( '%', d.id, '-' )
|
||||
OR d1.flag LIKE CONCAT( '%-', d.id, '-%' )
|
||||
OR d1.flag LIKE CONCAT( '-', d.id, '%' )
|
||||
WHERE
|
||||
u.dept_id = d1.id
|
||||
AND u.STATUS = 0
|
||||
) subordinate ON subordinate.id = a.user_id
|
||||
</if>
|
||||
WHERE
|
||||
a.result = 2
|
||||
<if test="relation == 'my'">
|
||||
AND a.user_id = #{userId}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="selectContractStatisticsListByUserIds" resultType="cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.contract.ContractStatisticsRespVO">
|
||||
SELECT
|
||||
user_id AS userId,
|
||||
COUNT(1) AS count,
|
||||
SUM(contract_money) AS money
|
||||
FROM
|
||||
bpm_oa_contract
|
||||
WHERE
|
||||
deleted = 0
|
||||
AND result = 2
|
||||
AND user_id IN
|
||||
<foreach item="userId" collection="userIds" separator="," open="(" close=")" index="">
|
||||
#{userId}
|
||||
</foreach>
|
||||
<if test="createTime != null and createTime.length > 0">
|
||||
<if test="createTime[0] != null">
|
||||
and create_time >= #{createTime[0]}
|
||||
</if>
|
||||
<if test="createTime[1] != null">
|
||||
and create_time <= #{createTime[1]}
|
||||
</if>
|
||||
</if>
|
||||
GROUP BY user_id
|
||||
</select>
|
||||
</mapper>
|
@ -9,7 +9,7 @@
|
||||
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
|
||||
-->
|
||||
|
||||
<select id="getLeaveListByTime" resultType="cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOALeaveRpcVO">
|
||||
<select id="getLeaveListByTime" resultType="cn.iocoder.yudao.module.bpm.api.oa.vo.leave.BpmOALeaveRpcVO">
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
|
@ -0,0 +1,23 @@
|
||||
package cn.iocoder.yudao.module.hrm.api.crmbusiness;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmbusiness.dto.CrmBusinessDTO;
|
||||
import cn.iocoder.yudao.module.hrm.enums.ApiConstants;
|
||||
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.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||
@Tag(name = "RPC 服务 - 流程实例")
|
||||
public interface BusinessApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/crm/business";
|
||||
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "获得商机信息")
|
||||
@Parameter(name = "id", description = "ID", required = true)
|
||||
CommonResult<CrmBusinessDTO> getBusiness(@RequestParam("id") Long id);
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package cn.iocoder.yudao.module.hrm.api.crmbusiness.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 商机新增/修改 Request VO")
|
||||
@Data
|
||||
public class CrmBusinessDTO {
|
||||
|
||||
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "20239")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "客户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "16784")
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "客户")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "销售阶段", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "阶段推进时间")
|
||||
private LocalDateTime statusTime;
|
||||
|
||||
@Schema(description = "0洽淡中,1成交2失败3无效", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Integer isEnd;
|
||||
|
||||
@Schema(description = "下次联系时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime nextTime;
|
||||
|
||||
@Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "商机金额", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private BigDecimal money;
|
||||
|
||||
@Schema(description = "产品总金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "30725")
|
||||
private BigDecimal totalPrice;
|
||||
|
||||
@Schema(description = "预计成交日期")
|
||||
private LocalDateTime dealTime;
|
||||
|
||||
@Schema(description = "整单折扣", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private BigDecimal discountRate;
|
||||
|
||||
@Schema(description = "备注", example = "随便")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "负责人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "24317")
|
||||
private Long ownerUserId;
|
||||
|
||||
|
||||
@Schema(description = "添加时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "负责人")
|
||||
private String ownUserName;
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.module.hrm.api.crmcontract;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcontract.dto.CrmContractProductDTO;
|
||||
import cn.iocoder.yudao.module.hrm.enums.ApiConstants;
|
||||
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.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||
@Tag(name = "RPC 服务 - 流程实例")
|
||||
public interface ContractApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/crm/contract";
|
||||
|
||||
@PostMapping(PREFIX + "/create")
|
||||
@Operation(summary = "创建合同商品信息")
|
||||
CommonResult<Boolean> createProduct(@RequestBody List<CrmContractProductDTO> createReqVO);
|
||||
|
||||
@GetMapping(PREFIX + "/get-product")
|
||||
@Operation(summary = "获得合同商品信息")
|
||||
@Parameter(name = "contractId", description = "合同ID", required = true)
|
||||
CommonResult<List<CrmContractProductDTO>> getProduct(@RequestParam("contractId") Long contractId);
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package cn.iocoder.yudao.module.hrm.api.crmcontract.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 合同产品关联 DTO")
|
||||
@Data
|
||||
public class CrmContractProductDTO {
|
||||
|
||||
@Schema(description = "合同编号")
|
||||
private Long contractId;
|
||||
|
||||
@Schema(description = "产品编号")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "产品名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "产品属性")
|
||||
private String productAttrUnique;
|
||||
|
||||
@Schema(description = "产品单价")
|
||||
private BigDecimal price;
|
||||
|
||||
@Schema(description = "数量")
|
||||
private Integer nums;
|
||||
|
||||
@Schema(description = "折扣")
|
||||
private BigDecimal discount;
|
||||
|
||||
@Schema(description = "小计")
|
||||
private BigDecimal subtotal;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remarks;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cn.iocoder.yudao.module.hrm.api.crmcustomer;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcustomer.dto.CrmCustomerDTO;
|
||||
import cn.iocoder.yudao.module.hrm.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||
@Tag(name = "RPC 服务 - 流程实例")
|
||||
public interface CrmCustomerApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/crm/customer";
|
||||
|
||||
@PostMapping(PREFIX + "/update")
|
||||
@Operation(summary = "更新客户信息")
|
||||
CommonResult<Boolean> updateCustomerPurchaseTotal(@RequestBody CrmCustomerDTO updateReqVO);
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
package cn.iocoder.yudao.module.hrm.api.crmcustomer.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
|
||||
@Schema(description = "管理后台 - 客户新增/修改 Request VO")
|
||||
@Data
|
||||
public class CrmCustomerDTO {
|
||||
|
||||
@Schema(description = "是否转移记录 1-是 2-否")
|
||||
private Integer isTransfer;
|
||||
|
||||
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "12015")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
|
||||
@NotEmpty(message = "客户名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "手机", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
// @NotEmpty(message = "手机不能为空")
|
||||
private String mobile;
|
||||
|
||||
@Schema(description = "电话", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
//@NotEmpty(message = "电话不能为空")
|
||||
private String telephone;
|
||||
|
||||
@Schema(description = "成交状态0未成交1成交", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
// @NotNull(message = "成交状态0未成交1成交不能为空")
|
||||
private Integer dealStatus;
|
||||
|
||||
@Schema(description = "成交时间")
|
||||
private LocalDateTime dealTime;
|
||||
|
||||
@Schema(description = "1锁定")
|
||||
private Boolean isLock;
|
||||
|
||||
@Schema(description = "客户级别ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
//@NotNull(message = "客户级别ID不能为空")
|
||||
private Integer level;
|
||||
|
||||
@Schema(description = "客户行业ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
//@NotNull(message = "客户行业ID不能为空")
|
||||
private Integer industry;
|
||||
|
||||
@Schema(description = " 客户标签")
|
||||
private String tags;
|
||||
|
||||
@Schema(description = "客户来源ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
//@NotNull(message = "客户来源ID不能为空")
|
||||
private Integer source;
|
||||
|
||||
@Schema(description = "备注", example = "你说的对")
|
||||
private String remark;
|
||||
|
||||
|
||||
@Schema(description = "省份id")
|
||||
private Integer province;
|
||||
|
||||
@Schema(description = "城市ID")
|
||||
private Integer city;
|
||||
|
||||
@Schema(description = "区域ID")
|
||||
private Integer area;
|
||||
|
||||
/**
|
||||
* 地址组合字符串
|
||||
*/
|
||||
private String addressStr;
|
||||
|
||||
@Schema(description = "详细地址", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
//@NotEmpty(message = "详细地址不能为空")
|
||||
private String detailAddress;
|
||||
|
||||
@Schema(description = "地理位置经度")
|
||||
private Double lng;
|
||||
|
||||
@Schema(description = "地理位置维度")
|
||||
private Double lat;
|
||||
|
||||
@Schema(description = "下次联系时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
//@NotNull(message = "下次联系时间不能为空")
|
||||
private LocalDateTime nextTime;
|
||||
|
||||
@Schema(description = "最后跟进时间")
|
||||
private LocalDateTime followTime;
|
||||
|
||||
@Schema(description = "领取时间")
|
||||
private LocalDateTime collectTime;
|
||||
|
||||
@Schema(description = "微信")
|
||||
private String weixin;
|
||||
|
||||
@Schema(description = "QQ")
|
||||
private String qq;
|
||||
|
||||
@Schema(description = "消费总额")
|
||||
private BigDecimal purchaseTotal;
|
||||
|
||||
@Schema(description = "消费次数")
|
||||
private Integer purchaseTimes;
|
||||
|
||||
@Schema(description = "跟进状态", example = "1")
|
||||
private Integer followStatus;
|
||||
|
||||
|
||||
|
||||
}
|
@ -119,6 +119,12 @@
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-file</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-module-bpm-api</artifactId>
|
||||
<version>2.0.0-jdk8-snapshot</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
|
@ -155,6 +155,12 @@
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-file</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-module-bpm-api</artifactId>
|
||||
<version>2.0.0-jdk8-snapshot</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
|
@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.module.crm.api.crmbusiness;
|
||||
|
||||
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.crmbusiness.vo.CrmBusinessRespVO;
|
||||
import cn.iocoder.yudao.module.crm.service.crmbusiness.CrmBusinessService;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmbusiness.BusinessApi;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmbusiness.dto.CrmBusinessDTO;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* Flowable CRM Api 实现类
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
public class BusinessApiImpl implements BusinessApi {
|
||||
|
||||
@Resource
|
||||
private CrmBusinessService businessService;
|
||||
|
||||
@Override
|
||||
public CommonResult<CrmBusinessDTO> getBusiness(Long id) {
|
||||
CrmBusinessRespVO businessDO = businessService.getBusiness(id);
|
||||
return success(BeanUtils.toBean(businessDO, CrmBusinessDTO.class));
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package cn.iocoder.yudao.module.crm.api.crmcontract;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractProductDO;
|
||||
import cn.iocoder.yudao.module.crm.service.crmcontract.CrmContractService;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcontract.ContractApi;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcontract.dto.CrmContractProductDTO;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* Flowable CRM Api 实现类
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
public class ContractApiImpl implements ContractApi {
|
||||
|
||||
@Resource
|
||||
private CrmContractService crmContractService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> createProduct(List<CrmContractProductDTO> createReqVO) {
|
||||
|
||||
crmContractService.createProduct(BeanUtils.toBean(createReqVO, CrmContractProductDO.class));
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<CrmContractProductDTO>> getProduct(Long contractId) {
|
||||
List<CrmContractProductDO> contractProductDOS = crmContractService.getContractProductListByContractId(contractId);
|
||||
return success(BeanUtils.toBean(contractProductDOS, CrmContractProductDTO.class));
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.module.crm.api.crmcustomer;
|
||||
|
||||
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.crmcustomer.vo.CrmCustomerSaveReqVO;
|
||||
import cn.iocoder.yudao.module.crm.service.crmcustomer.CrmCustomerService;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcustomer.CrmCustomerApi;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcustomer.dto.CrmCustomerDTO;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* Flowable CRM Api 实现类
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
public class CrmCustomerApiImpl implements CrmCustomerApi {
|
||||
|
||||
@Resource
|
||||
private CrmCustomerService customerService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> updateCustomerPurchaseTotal(CrmCustomerDTO updateReqVO) {
|
||||
customerService.updateCustomerPurchaseTotal(BeanUtils.toBean(updateReqVO, CrmCustomerSaveReqVO.class));
|
||||
return success(true);
|
||||
}
|
||||
}
|
@ -66,9 +66,9 @@ public class CrmAchievementController {
|
||||
@GetMapping("/depts")
|
||||
@Operation(summary = "获得部门业绩目标")
|
||||
@PreAuthorize("@ss.hasPermission('crm:achievement:query')")
|
||||
public CommonResult<List<DeptAchieveRespVO>> getDeptsAchievement(@RequestParam(name = "type", required = false) Integer type,
|
||||
public CommonResult<List<DeptAchieveRespVO>> getDeptsAchievement(@RequestParam(name = "config", required = false) Integer config,
|
||||
@RequestParam(name = "year", required = false) Integer year) {
|
||||
List<DeptAchieveRespVO> deptAchieveRespVOS = achievementService.getDeptAchieve(type, year);
|
||||
List<DeptAchieveRespVO> deptAchieveRespVOS = achievementService.getDeptAchieve(config, year);
|
||||
return success(deptAchieveRespVOS);
|
||||
}
|
||||
|
||||
@ -86,6 +86,4 @@ public class CrmAchievementController {
|
||||
@RequestParam(name = "year", required = false) Integer year) {
|
||||
return success(achievementService.getCount(type, year, month));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -60,8 +60,4 @@ public class CustomerController {
|
||||
public CommonResult<PageResult<UserRecordVO>> getRecord(@Valid AchievementPageReqVO pageReqVO) {
|
||||
return success(customerService.getRecord(pageReqVO));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
package cn.iocoder.yudao.module.crm.controller.admin.crmclues.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 线索统计 RespVO")
|
||||
@Data
|
||||
public class CrmCluesStatisticsRespVO {
|
||||
|
||||
@Schema(description = "负责人用户编号")
|
||||
private Long ownerUserId;
|
||||
|
||||
@Schema(description = "线索总数量")
|
||||
private Integer count;
|
||||
|
||||
@Schema(description = "转客数量")
|
||||
private Integer successCount;
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 客户统计 Response VO")
|
||||
@Data
|
||||
public class CustomerStatisticRespVO {
|
||||
|
||||
@Schema(description = "负责人编号")
|
||||
private Long ownerUserId;
|
||||
|
||||
@Schema(description = "客户数量")
|
||||
private Integer count;
|
||||
|
||||
@Schema(description = "成交数量")
|
||||
private Integer DealsCount;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 跟进统计 Response VO")
|
||||
@Data
|
||||
public class RecordStatisticsRespVO {
|
||||
|
||||
@Schema(description = "跟进人")
|
||||
private String creator;
|
||||
|
||||
@Schema(description = "跟进总数量")
|
||||
private Integer count;
|
||||
|
||||
@Schema(description = "客户跟进数量")
|
||||
private Integer customerCount;
|
||||
|
||||
@Schema(description = "商机跟进数量")
|
||||
private Integer businessCount;
|
||||
|
||||
@Schema(description = "线索跟进数量")
|
||||
private Integer cluesCount;
|
||||
}
|
@ -3,10 +3,15 @@ package cn.iocoder.yudao.module.crm.dal.mysql.crmachievement;
|
||||
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.controller.admin.crmachievement.vo.DeptAchieveSaveVO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmachievement.CrmAchievementDO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmachievement.vo.CrmAchievementPageReqVO;
|
||||
import cn.iocoder.yudao.module.hrm.enums.FlowStepEnum;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 业绩目标 Mapper
|
||||
*
|
||||
@ -39,4 +44,21 @@ public interface CrmAchievementMapper extends BaseMapperX<CrmAchievementDO> {
|
||||
.orderByDesc(CrmAchievementDO::getId));
|
||||
}
|
||||
|
||||
default List<CrmAchievementDO> selectAchievementList(Integer type, Integer year, List<Long> typeIds) {
|
||||
|
||||
return selectList(new LambdaQueryWrapper<CrmAchievementDO>()
|
||||
.eq(CrmAchievementDO::getType, FlowStepEnum.TYPE_3.getValue())
|
||||
.eq(CrmAchievementDO::getConfig, type)
|
||||
.in(CrmAchievementDO::getTypeId, typeIds)
|
||||
.eq(CrmAchievementDO::getYear, year));
|
||||
}
|
||||
|
||||
default List<CrmAchievementDO> selectAchievementList(DeptAchieveSaveVO createReqVO, List<Long> typeIds) {
|
||||
|
||||
return selectList(new LambdaQueryWrapperX<CrmAchievementDO>()
|
||||
.eq(CrmAchievementDO::getType, createReqVO.getAchievementRespVO().getType())
|
||||
.eq(CrmAchievementDO::getConfig, createReqVO.getAchievementRespVO().getConfig())
|
||||
.eq(CrmAchievementDO::getYear, createReqVO.getAchievementRespVO().getYear())
|
||||
.inIfPresent(CrmAchievementDO::getTypeId, typeIds));
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,13 @@ package cn.iocoder.yudao.module.crm.dal.mysql.crmclues;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmclues.vo.CrmCluesPageReqVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmclues.vo.CrmCluesRespVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmclues.vo.CrmCluesStatisticsRespVO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmclues.CrmCluesDO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -21,4 +23,7 @@ public interface CrmCluesMapper extends BaseMapperX<CrmCluesDO> {
|
||||
IPage<CrmCluesRespVO> selectPageList(@Param("page") IPage mpPage, @Param("dto") CrmCluesPageReqVO pageReqVO, @Param("ids") List<Long> ids);
|
||||
|
||||
IPage<CrmCluesRespVO> selectPageList2(@Param("page") IPage mpPage, @Param("dto") CrmCluesPageReqVO pageReqVO);
|
||||
|
||||
List<CrmCluesStatisticsRespVO> selectStatisticsByUserIds(@Param("ownerUserIds") List<Long> ownerUserIds,
|
||||
@Param("createTime") LocalDateTime[] createTime);
|
||||
}
|
||||
|
@ -4,17 +4,13 @@ package cn.iocoder.yudao.module.crm.dal.mysql.crmcontract;
|
||||
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.security.core.util.SecurityFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.ContractVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.CrmContractPageReqVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.CrmContractRespVO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -56,9 +52,6 @@ public interface CrmContractMapper extends BaseMapperX<CrmContractDO> {
|
||||
.orderByDesc(CrmContractDO::getId));
|
||||
}
|
||||
|
||||
@Select("select any_value(t.id) as id,COUNT(t.id) AS count,SUM(t.money) AS money,t1.nickname AS nickname from crm_contract t " +
|
||||
"LEFT JOIN system_users t1 ON (t1.id = t.order_admin_id) " +
|
||||
"where t.deleted=0 GROUP BY t.order_admin_id ORDER BY any_value(money) DESC limit 10")
|
||||
List<ContractVO> selectContractTop();
|
||||
|
||||
}
|
||||
|
@ -5,12 +5,13 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CrmCustomerPageReqVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CrmCustomerRespVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CustomerStatisticRespVO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -41,4 +42,6 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
|
||||
}
|
||||
|
||||
IPage<CrmCustomerRespVO> selectPageList(@Param("page") IPage page, @Param("dto") CrmCustomerPageReqVO pageReqVO, @Param("ids") List<Long> ids);
|
||||
|
||||
List<CustomerStatisticRespVO> selectStatistic(@Param("userIds") List<Long> userIds, @Param("createTime") LocalDateTime[] createTime);
|
||||
}
|
||||
|
@ -4,9 +4,12 @@ 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.controller.admin.crmrecord.vo.CrmRecordPageReqVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.RecordStatisticsRespVO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecord.CrmRecordDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -28,4 +31,5 @@ public interface CrmRecordMapper extends BaseMapperX<CrmRecordDO> {
|
||||
.orderByDesc(CrmRecordDO::getId));
|
||||
}
|
||||
|
||||
List<RecordStatisticsRespVO> selectStatistics(@Param("userIds") List<Long> userIds, @Param("createTime") LocalDateTime[] createTime);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.crm.framework.rpc.config;
|
||||
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi;
|
||||
import cn.iocoder.yudao.module.product.api.storeproduct.StoreProductApi;
|
||||
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.StoreProductAttrValueApi;
|
||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||
@ -12,6 +13,7 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableFeignClients(clients = {DeptApi.class, DictDataApi.class, AdminUserApi.class, StoreProductApi.class, StoreProductAttrValueApi.class, SmsSendApi.class, MailSendApi.class, NoticeApi.class})
|
||||
@EnableFeignClients(clients = {DeptApi.class, DictDataApi.class, AdminUserApi.class, StoreProductApi.class, StoreProductAttrValueApi.class, SmsSendApi.class, MailSendApi.class, NoticeApi.class,
|
||||
BpmOAContractApi.class})
|
||||
public class RpcConfiguration {
|
||||
}
|
||||
|
@ -56,11 +56,11 @@ public interface CrmAchievementService {
|
||||
/**
|
||||
* 获取部门业绩
|
||||
*
|
||||
* @param type
|
||||
* @param config
|
||||
* @param year
|
||||
* @return
|
||||
*/
|
||||
List<DeptAchieveRespVO> getDeptAchieve(Integer type, Integer year);
|
||||
List<DeptAchieveRespVO> getDeptAchieve(Integer config, Integer year);
|
||||
|
||||
/**
|
||||
* 获取业绩完成度
|
||||
|
@ -1,31 +1,32 @@
|
||||
package cn.iocoder.yudao.module.crm.service.crmachievement;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.DeptTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.BpmOAContractDTO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.BpmOAContractVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmachievement.vo.*;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmachievement.CrmAchievementDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontractreceivables.CrmContractReceivablesDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmachievement.CrmAchievementMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontract.CrmContractMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontractreceivables.CrmContractReceivablesMapper;
|
||||
import cn.iocoder.yudao.module.hrm.enums.ContractStatusEnum;
|
||||
import cn.iocoder.yudao.module.hrm.enums.FlowStepEnum;
|
||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptApiDTO;
|
||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptApiVO;
|
||||
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.AdminUserApiDTO;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserApiVO;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserPageApiDTO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
@ -35,6 +36,8 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.convertMap;
|
||||
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.ACHIEVEMENT_NOT_EXISTS;
|
||||
|
||||
|
||||
@ -50,7 +53,7 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
|
||||
@Resource
|
||||
private CrmAchievementMapper achievementMapper;
|
||||
@Resource
|
||||
private DeptApi deptService;
|
||||
private DeptApi deptApi;
|
||||
@Resource
|
||||
private CrmContractMapper contractMapper;
|
||||
@Resource
|
||||
@ -58,28 +61,53 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@Resource
|
||||
private BpmOAContractApi contractApi;
|
||||
|
||||
|
||||
@Override
|
||||
public void createAchievement(DeptAchieveSaveVO createReqVO) {
|
||||
|
||||
//计算年目标
|
||||
List<BigDecimal> bigDecimals = Arrays.asList(
|
||||
createReqVO.getAchievementRespVO().getJanuary(), createReqVO.getAchievementRespVO().getFebruary(),
|
||||
createReqVO.getAchievementRespVO().getMarch(), createReqVO.getAchievementRespVO().getApril(),
|
||||
createReqVO.getAchievementRespVO().getMay(), createReqVO.getAchievementRespVO().getJune(),
|
||||
createReqVO.getAchievementRespVO().getJuly(), createReqVO.getAchievementRespVO().getAugust(),
|
||||
createReqVO.getAchievementRespVO().getSeptember(), createReqVO.getAchievementRespVO().getOctober(),
|
||||
createReqVO.getAchievementRespVO().getNovember(), createReqVO.getAchievementRespVO().getDecember()
|
||||
);
|
||||
BigDecimal yearTarget = bigDecimals.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
createReqVO.getAchievementRespVO().setYeartarget(yearTarget);
|
||||
|
||||
if (createReqVO.getId() == 0) {
|
||||
|
||||
List<CrmAchievementDO> achievements;
|
||||
//批量
|
||||
if (FlowStepEnum.TYPE_3.getValue().equals(createReqVO.getAchievementRespVO().getType())) {
|
||||
List<DeptApiVO> list = deptService.getDeptList(
|
||||
new DeptApiDTO().setStatus(CommonStatusEnum.ENABLE.getStatus())).getCheckedData();
|
||||
list.forEach(dept -> {
|
||||
createReqVO.setId(dept.getId());
|
||||
createReqVO.setName(dept.getName());
|
||||
saveAchievement(createReqVO);
|
||||
});
|
||||
// 获取所有营销部门列表
|
||||
List<DeptRespDTO> list = deptApi.getDeptListByType(DeptTypeEnum.SALE_DEPT.getValue()).getCheckedData();
|
||||
// 获取 插入/更新信息列表
|
||||
achievements = list.stream().map(item -> {
|
||||
CrmAchievementDO achievement = BeanUtils.toBean(createReqVO.getAchievementRespVO(), CrmAchievementDO.class);
|
||||
achievement.setTypeId(item.getId());
|
||||
achievement.setName(item.getName());
|
||||
return achievement;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
} else {
|
||||
List<AdminUserApiVO> list = adminUserApi.getUserList(new AdminUserApiDTO().setStatus(CommonStatusEnum.ENABLE.getStatus())).getCheckedData();
|
||||
list.forEach(user -> {
|
||||
createReqVO.setId(user.getId());
|
||||
createReqVO.setName(user.getNickname());
|
||||
saveAchievement(createReqVO);
|
||||
});
|
||||
List<AdminUserRespDTO> list = adminUserApi.getUserListAll(1, null, CommonStatusEnum.ENABLE.getStatus(), "sale").getCheckedData();
|
||||
// 获取 插入/更新信息列表
|
||||
achievements = list.stream().map(item -> {
|
||||
CrmAchievementDO achievement = BeanUtils.toBean(createReqVO.getAchievementRespVO(), CrmAchievementDO.class);
|
||||
achievement.setTypeId(item.getId());
|
||||
achievement.setName(item.getNickname());
|
||||
return achievement;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// 批量插入操作
|
||||
saveAchievementBatch(createReqVO, achievements);
|
||||
} else {
|
||||
//单个操作
|
||||
if (FlowStepEnum.TYPE_3.getValue().equals(createReqVO.getAchievementRespVO().getType())) {
|
||||
@ -89,8 +117,6 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
|
||||
}
|
||||
saveAchievement(createReqVO);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,29 +129,48 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
|
||||
CrmAchievementDO achievement = BeanUtils.toBean(createReqVO.getAchievementRespVO(), CrmAchievementDO.class);
|
||||
achievement.setTypeId(createReqVO.getId());
|
||||
achievement.setName(createReqVO.getName());
|
||||
LambdaQueryWrapper<CrmAchievementDO> wrapper = new LambdaQueryWrapper<>();
|
||||
LambdaQueryWrapperX<CrmAchievementDO> wrapper = new LambdaQueryWrapperX<>();
|
||||
wrapper.eq(CrmAchievementDO::getType, achievement.getType())
|
||||
.eq(CrmAchievementDO::getTypeId, achievement.getTypeId())
|
||||
.eq(CrmAchievementDO::getConfig, achievement.getConfig())
|
||||
.eq(CrmAchievementDO::getYear, achievement.getYear());
|
||||
CrmAchievementDO achievementOld = achievementMapper.selectOne(wrapper);
|
||||
|
||||
if (achievementOld == null) {
|
||||
achievementMapper.insert(achievement);
|
||||
} else {
|
||||
achievement.setId(achievementOld.getId());
|
||||
achievementMapper.updateById(achievement);
|
||||
}
|
||||
}
|
||||
|
||||
//更新年目标
|
||||
List<BigDecimal> bigDecimals = Arrays.asList(
|
||||
achievement.getJanuary(), achievement.getFebruary(), achievement.getMarch(), achievement.getApril(),
|
||||
achievement.getMay(), achievement.getJune(), achievement.getJuly(), achievement.getAugust(),
|
||||
achievement.getSeptember(), achievement.getOctober(), achievement.getNovember(), achievement.getDecember()
|
||||
);
|
||||
BigDecimal yearTarget = bigDecimals.stream()
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
CrmAchievementDO achievementDO = CrmAchievementDO.builder().yeartarget(yearTarget).id(achievement.getId()).build();
|
||||
achievementMapper.updateById(achievementDO);
|
||||
/**
|
||||
* 批量插入操作
|
||||
* @param createReqVO 更新信息
|
||||
* @param achievements 更新信息
|
||||
*/
|
||||
private void saveAchievementBatch(DeptAchieveSaveVO createReqVO, List<CrmAchievementDO> achievements) {
|
||||
|
||||
if (CollectionUtil.isNotEmpty(achievements)) {
|
||||
|
||||
List<Long> typeIds = convertList(achievements, CrmAchievementDO::getId);
|
||||
// 判断业绩数据是否已存在
|
||||
List<CrmAchievementDO> achievementOld = achievementMapper.selectAchievementList(createReqVO, typeIds);
|
||||
if (CollectionUtil.isEmpty(achievementOld)) {
|
||||
|
||||
achievementMapper.insertBatch(achievements);
|
||||
}else {
|
||||
|
||||
// 获取之前业绩数据Map
|
||||
Map<Long, CrmAchievementDO> oldMap = convertMap(achievementOld, CrmAchievementDO::getTypeId);
|
||||
// 设置ID
|
||||
achievements.forEach(item -> {
|
||||
item.setId(oldMap.get(item.getTypeId()).getId());
|
||||
});
|
||||
|
||||
achievementMapper.updateBatch(achievements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -158,62 +203,63 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
|
||||
|
||||
@Override
|
||||
public PageResult<UserAchieveRespVO> getAchievementPage(CrmAchievementPageReqVO pageReqVO) {
|
||||
|
||||
// 设置用户查询条件
|
||||
AdminUserPageApiDTO userPageReqVO = new AdminUserPageApiDTO();
|
||||
userPageReqVO.setPageNo(pageReqVO.getPageNo());
|
||||
userPageReqVO.setPageSize(pageReqVO.getPageSize());
|
||||
PageResult<AdminUserApiVO> pageResult = adminUserApi.getUserPage(userPageReqVO).getCheckedData();
|
||||
PageResult<UserAchieveRespVO> pageResult1 = BeanUtils.toBean(pageResult, UserAchieveRespVO.class);
|
||||
List<Long> typeIds = new ArrayList<>();
|
||||
for (UserAchieveRespVO vo : pageResult1.getList()) {
|
||||
typeIds.add(vo.getId());
|
||||
userPageReqVO.setNickname(pageReqVO.getName());
|
||||
userPageReqVO.setRoleCodes("sale"); // 设置查询用户的角色类型
|
||||
|
||||
// 查询用户分页列表
|
||||
PageResult<AdminUserApiVO> pageResult = adminUserApi.getUserPageByRole(userPageReqVO).getCheckedData();
|
||||
PageResult<UserAchieveRespVO> userPage = BeanUtils.toBean(pageResult, UserAchieveRespVO.class);
|
||||
if (CollectionUtil.isNotEmpty(pageResult.getList())) {
|
||||
|
||||
// 查询用户的 业绩信息
|
||||
List<Long> typeIds = convertList(userPage.getList(), UserAchieveRespVO::getId);
|
||||
List<CrmAchievementDO> crmAchievementDOS = achievementMapper.selectList(new LambdaQueryWrapperX<CrmAchievementDO>()
|
||||
.eq(CrmAchievementDO::getType, FlowStepEnum.TYPE_2.getValue())
|
||||
.eq(CrmAchievementDO::getConfig, pageReqVO.getConfig())
|
||||
.in(CrmAchievementDO::getTypeId, typeIds)
|
||||
.eq(CrmAchievementDO::getYear, pageReqVO.getYear())
|
||||
);
|
||||
// 获得业绩信息Map
|
||||
Map<Long, CrmAchievementDO> achievementMap = convertMap(crmAchievementDOS, CrmAchievementDO::getTypeId);
|
||||
|
||||
userPage.getList().forEach(item -> {
|
||||
|
||||
CrmAchievementDO crmAchievementDO = achievementMap.get(item.getId());
|
||||
if (crmAchievementDO == null) {
|
||||
crmAchievementDO = CrmAchievementDO.builder()
|
||||
.january(BigDecimal.ZERO).february(BigDecimal.ZERO).march(BigDecimal.ZERO)
|
||||
.april(BigDecimal.ZERO).may(BigDecimal.ZERO).june(BigDecimal.ZERO)
|
||||
.july(BigDecimal.ZERO).august(BigDecimal.ZERO).september(BigDecimal.ZERO)
|
||||
.october(BigDecimal.ZERO).november(BigDecimal.ZERO).december(BigDecimal.ZERO)
|
||||
.yeartarget(BigDecimal.ZERO)
|
||||
.build();
|
||||
}
|
||||
|
||||
item.setAchievementRespVO(BeanUtils.toBean(crmAchievementDO, CrmAchievementRespVO.class));
|
||||
});
|
||||
}
|
||||
typeIds = typeIds.stream().distinct().collect(Collectors.toList());
|
||||
List<CrmAchievementDO> crmAchievementDOS = achievementMapper.selectList(new LambdaQueryWrapper<CrmAchievementDO>()
|
||||
.eq(CrmAchievementDO::getType, FlowStepEnum.TYPE_2.getValue())
|
||||
.eq(CrmAchievementDO::getConfig, pageReqVO.getConfig())
|
||||
.in(CrmAchievementDO::getTypeId, typeIds)
|
||||
.eq(CrmAchievementDO::getYear, pageReqVO.getYear())
|
||||
);
|
||||
|
||||
Map<Long, List<CrmAchievementDO>> map = crmAchievementDOS.stream().collect(Collectors.groupingBy(CrmAchievementDO::getTypeId));
|
||||
|
||||
pageResult1.getList().forEach(v -> {
|
||||
List<CrmAchievementDO> doList = map.get(v.getId());
|
||||
CrmAchievementDO crmAchievementDO = null;
|
||||
if (CollUtil.isNotEmpty(doList)) {
|
||||
crmAchievementDO = doList.get(0);
|
||||
}
|
||||
if (crmAchievementDO == null) {
|
||||
crmAchievementDO = CrmAchievementDO.builder()
|
||||
.january(BigDecimal.ZERO).february(BigDecimal.ZERO).march(BigDecimal.ZERO)
|
||||
.april(BigDecimal.ZERO).may(BigDecimal.ZERO).june(BigDecimal.ZERO)
|
||||
.july(BigDecimal.ZERO).august(BigDecimal.ZERO).september(BigDecimal.ZERO)
|
||||
.october(BigDecimal.ZERO).november(BigDecimal.ZERO).december(BigDecimal.ZERO)
|
||||
.yeartarget(BigDecimal.ZERO)
|
||||
.build();
|
||||
}
|
||||
v.setAchievementRespVO(BeanUtils.toBean(crmAchievementDO, CrmAchievementRespVO.class));
|
||||
});
|
||||
return pageResult1;
|
||||
return userPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeptAchieveRespVO> getDeptAchieve(Integer type, Integer year) {
|
||||
List<DeptApiVO> list = deptService.getDeptList(
|
||||
new DeptApiDTO().setStatus(CommonStatusEnum.ENABLE.getStatus())).getCheckedData();
|
||||
List<DeptAchieveRespVO> achieveRespVOS = BeanUtils.toBean(list, DeptAchieveRespVO.class);
|
||||
List<Long> typeIds = new ArrayList<>();
|
||||
for (DeptAchieveRespVO vo : achieveRespVOS) {
|
||||
typeIds.add(vo.getId());
|
||||
}
|
||||
typeIds = typeIds.stream().distinct().collect(Collectors.toList());
|
||||
List<CrmAchievementDO> crmAchievementDOS = achievementMapper.selectList(new LambdaQueryWrapper<CrmAchievementDO>()
|
||||
.eq(CrmAchievementDO::getType, FlowStepEnum.TYPE_3.getValue())
|
||||
.eq(CrmAchievementDO::getConfig, type)
|
||||
.in(CrmAchievementDO::getTypeId, typeIds)
|
||||
.eq(CrmAchievementDO::getYear, year)
|
||||
);
|
||||
public List<DeptAchieveRespVO> getDeptAchieve(Integer config, Integer year) {
|
||||
|
||||
// 获取销售部门列表
|
||||
List<DeptRespDTO> list = deptApi.getDeptListByType(DeptTypeEnum.SALE_DEPT.getValue()).getCheckedData();
|
||||
// 获取部门编号列表
|
||||
List<Long> typeIds = list.stream().map(DeptRespDTO::getId).distinct().collect(Collectors.toList());
|
||||
|
||||
// 获取部门业绩列表
|
||||
List<CrmAchievementDO> crmAchievementDOS = achievementMapper.selectAchievementList(config, year, typeIds);
|
||||
Map<Long, List<CrmAchievementDO>> map = crmAchievementDOS.stream().collect(Collectors.groupingBy(CrmAchievementDO::getTypeId));
|
||||
|
||||
List<DeptAchieveRespVO> achieveRespVOS = BeanUtils.toBean(list, DeptAchieveRespVO.class);
|
||||
achieveRespVOS.forEach(vo -> {
|
||||
List<CrmAchievementDO> doList = map.get(vo.getId());
|
||||
CrmAchievementDO crmAchievementDO = null;
|
||||
@ -236,8 +282,11 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
|
||||
|
||||
@Override
|
||||
public AchieveCountRespVO getCount(Integer type, Integer year, Integer month) {
|
||||
|
||||
// 获取当前登录用户编号
|
||||
List<Long> userIds = new ArrayList<>();
|
||||
Long typeId = SecurityFrameworkUtils.getLoginUserId();
|
||||
|
||||
if (FlowStepEnum.TYPE_2.getValue().equals(type)) {
|
||||
userIds.add(typeId);
|
||||
} else {
|
||||
@ -265,43 +314,47 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
|
||||
endTime = DateUtil.endOfMonth(calendar.getTime());
|
||||
}
|
||||
|
||||
//合同目标
|
||||
CrmAchievementDO crmAchievementDO = achievementMapper.selectOne(new LambdaQueryWrapperX<CrmAchievementDO>()
|
||||
List<CrmAchievementDO> achievementDOS = achievementMapper.selectList(new LambdaQueryWrapperX<CrmAchievementDO>()
|
||||
.eq(CrmAchievementDO::getType, type)
|
||||
.eq(CrmAchievementDO::getTypeId, typeId)
|
||||
.eqIfPresent(CrmAchievementDO::getConfig, ShopCommonEnum.ACH_1.getValue())
|
||||
.eqIfPresent(CrmAchievementDO::getYear, year));
|
||||
//回款目标
|
||||
CrmAchievementDO crmAchievementDO2 = achievementMapper.selectOne(new LambdaQueryWrapperX<CrmAchievementDO>()
|
||||
.eq(CrmAchievementDO::getType, type)
|
||||
.eq(CrmAchievementDO::getTypeId, typeId)
|
||||
.eqIfPresent(CrmAchievementDO::getConfig, ShopCommonEnum.ACH_2.getValue())
|
||||
.eqIfPresent(CrmAchievementDO::getYear, year));
|
||||
Map<Integer, CrmAchievementDO> achievementMap = convertMap(achievementDOS, CrmAchievementDO::getConfig);
|
||||
// 合同目标
|
||||
CrmAchievementDO crmAchievementDO = achievementMap.get(ShopCommonEnum.ACH_1.getValue());
|
||||
// 回款目标
|
||||
CrmAchievementDO crmAchievementDO2 = achievementMap.get(ShopCommonEnum.ACH_2.getValue());
|
||||
|
||||
// 获取合同信息
|
||||
List<BpmOAContractDTO> contractDTOS = contractApi.getContractList(new BpmOAContractVO()
|
||||
.setContractType(BpmOAContractVO.SALE_CONTRACT)
|
||||
.setUserId(userIds)
|
||||
.setStarTime(starTime)
|
||||
.setEndTime(endTime)).getCheckedData();
|
||||
|
||||
List<CrmContractDO> crmContractDOS = contractMapper.selectList(new LambdaQueryWrapper<CrmContractDO>()
|
||||
.in(CrmContractDO::getOwnerUserId, userIds)
|
||||
.eq(CrmContractDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
|
||||
.between(CrmContractDO::getOrderTime, starTime, endTime));
|
||||
// List<CrmContractDO> crmContractDOS = contractMapper.selectList(new LambdaQueryWrapperX<CrmContractDO>()
|
||||
// .in(CrmContractDO::getOwnerUserId, userIds)
|
||||
// .eq(CrmContractDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
|
||||
// .between(CrmContractDO::getOrderTime, starTime, endTime));
|
||||
BigDecimal contractSuccessMoney = BigDecimal.ZERO;
|
||||
if (!crmContractDOS.isEmpty()) {
|
||||
contractSuccessMoney = crmContractDOS
|
||||
.stream()
|
||||
.map(CrmContractDO::getMoney)
|
||||
if (CollectionUtil.isNotEmpty(contractDTOS)) {
|
||||
// 累加合同金额
|
||||
contractSuccessMoney = contractDTOS.stream()
|
||||
.map(BpmOAContractDTO::getContractMoney)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
}
|
||||
List<CrmContractReceivablesDO> crmContractReceivablesDOS = contractReceivablesMapper
|
||||
.selectList(new LambdaQueryWrapper<CrmContractReceivablesDO>()
|
||||
.in(CrmContractReceivablesDO::getOwnerUserId, userIds)
|
||||
.eq(CrmContractReceivablesDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
|
||||
.between(CrmContractReceivablesDO::getReturnTime, starTime, endTime));
|
||||
|
||||
// List<CrmContractReceivablesDO> crmContractReceivablesDOS = contractReceivablesMapper
|
||||
// .selectList(new LambdaQueryWrapper<CrmContractReceivablesDO>()
|
||||
// .in(CrmContractReceivablesDO::getOwnerUserId, userIds)
|
||||
// .eq(CrmContractReceivablesDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
|
||||
// .between(CrmContractReceivablesDO::getReturnTime, starTime, endTime));
|
||||
BigDecimal receivablesSuccessMoney = BigDecimal.ZERO;
|
||||
if (!crmContractReceivablesDOS.isEmpty()) {
|
||||
receivablesSuccessMoney = crmContractReceivablesDOS
|
||||
.stream()
|
||||
.map(CrmContractReceivablesDO::getMoney)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
}
|
||||
// if (!crmContractReceivablesDOS.isEmpty()) {
|
||||
// receivablesSuccessMoney = crmContractReceivablesDOS
|
||||
// .stream()
|
||||
// .map(CrmContractReceivablesDO::getMoney)
|
||||
// .reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
// }
|
||||
|
||||
BigDecimal contractMoney = BigDecimal.ZERO;
|
||||
BigDecimal receivablesMoney = BigDecimal.ZERO;
|
||||
@ -412,8 +465,6 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
|
||||
receivablesMoney = crmAchievementDO2.getDecember();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (contractMoney.compareTo(BigDecimal.ZERO) > 0) {
|
||||
contractPer = NumberUtil.round(NumberUtil.div(contractSuccessMoney, contractMoney), 2)
|
||||
|
@ -9,7 +9,10 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.ContractStatisticsDTO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.*;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmclues.vo.CrmCluesStatisticsRespVO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmachievement.CrmAchievementDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmclues.CrmCluesDO;
|
||||
@ -22,7 +25,7 @@ import cn.iocoder.yudao.module.crm.dal.mysql.crmclues.CrmCluesMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontract.CrmContractMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontractreceivables.CrmContractReceivablesMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmcustomer.CrmCustomerMapper;
|
||||
import cn.iocoder.yudao.module.hrm.enums.CluesStatusEnum;
|
||||
import cn.iocoder.yudao.module.crm.service.crmclues.CrmCluesService;
|
||||
import cn.iocoder.yudao.module.hrm.enums.ContractStatusEnum;
|
||||
import cn.iocoder.yudao.module.hrm.enums.FlowStepEnum;
|
||||
import cn.iocoder.yudao.module.hrm.enums.RelationEnum;
|
||||
@ -39,12 +42,12 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
|
||||
/**
|
||||
* 业绩目标 Service 实现类
|
||||
*
|
||||
@ -71,55 +74,75 @@ public class AchievementServiceImpl implements AchievementService {
|
||||
@Resource
|
||||
private CrmCluesMapper crmCluesMapper;
|
||||
|
||||
@Resource
|
||||
private BpmOAContractApi contractApi;
|
||||
|
||||
@Resource
|
||||
private CrmCluesService cluesService;
|
||||
|
||||
|
||||
@Override
|
||||
public PageResult<UserAchieveVO> getAchievementPage(AchievementPageReqVO pageReqVO) {
|
||||
AdminUserPageApiDTO dto = new AdminUserPageApiDTO();
|
||||
dto.setUsername(pageReqVO.getName());
|
||||
dto.setNickname(pageReqVO.getName());
|
||||
dto.setPageNo(pageReqVO.getPageNo());
|
||||
dto.setPageSize(pageReqVO.getPageSize());
|
||||
PageResult<AdminUserApiVO> pageResult = adminUserApi.getUserPage(dto).getCheckedData();
|
||||
dto.setRoleCodes("sale"); // 设置查询用户的角色类型
|
||||
|
||||
// 获取销售角色 分页列表
|
||||
PageResult<AdminUserApiVO> pageResult = adminUserApi.getUserPageByRole(dto).getCheckedData();
|
||||
PageResult<UserAchieveVO> pageResult1 = BeanUtils.toBean(pageResult, UserAchieveVO.class);
|
||||
pageResult1.getList().forEach(v -> {
|
||||
LambdaQueryWrapperX<CrmContractDO> wrapperX = new LambdaQueryWrapperX<>();
|
||||
wrapperX.eq(CrmContractDO::getOwnerUserId, v.getId())
|
||||
.eq(CrmContractDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
|
||||
.betweenIfPresent(CrmContractDO::getCreateTime, pageReqVO.getCreateTime());
|
||||
v.setContractCount(contractMapper.selectCount(wrapperX));
|
||||
List<CrmContractDO> crmContractDOS = contractMapper.selectList(wrapperX);
|
||||
BigDecimal contractMoney = crmContractDOS
|
||||
.stream()
|
||||
.map(CrmContractDO::getMoney)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
v.setContractMoney(contractMoney);
|
||||
List<CrmContractReceivablesDO> crmContractReceivablesDOS = contractReceivablesMapper
|
||||
.selectList(new LambdaQueryWrapperX<CrmContractReceivablesDO>()
|
||||
.eq(CrmContractReceivablesDO::getOwnerUserId, v.getId())
|
||||
.eq(CrmContractReceivablesDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
|
||||
.betweenIfPresent(CrmContractReceivablesDO::getCreateTime, pageReqVO.getCreateTime()));
|
||||
BigDecimal receivablesMoney = crmContractReceivablesDOS
|
||||
.stream()
|
||||
.map(CrmContractReceivablesDO::getMoney)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
v.setReceivablesMoney(receivablesMoney);
|
||||
|
||||
LambdaQueryWrapperX<CrmCluesDO> wrapperX2 = new LambdaQueryWrapperX<>();
|
||||
wrapperX2.eq(CrmCluesDO::getOwnerUserId, v.getId())
|
||||
.betweenIfPresent(CrmCluesDO::getCreateTime, pageReqVO.getCreateTime());
|
||||
Long cluesCount = crmCluesMapper.selectCount(wrapperX2);
|
||||
v.setCluesCount(cluesCount);
|
||||
if (CollUtil.isNotEmpty(pageResult1.getList())) {
|
||||
|
||||
wrapperX2.eq(CrmCluesDO::getStatus, CluesStatusEnum.STATUS_1.getValue());
|
||||
Long cluesToCustomerCount = crmCluesMapper.selectCount(wrapperX2);
|
||||
v.setCluesToCustomerCount(cluesToCustomerCount);
|
||||
String per = "0";
|
||||
if (cluesCount > 0) {
|
||||
per = NumberUtil.round(NumberUtil.div(cluesToCustomerCount, cluesCount), 2)
|
||||
.multiply(new BigDecimal("100")).toString();
|
||||
}
|
||||
v.setCluesToCustomerPer(per);
|
||||
// 获取所有用户编号列表
|
||||
List<Long> userIds = convertList(pageResult1.getList(), UserAchieveVO::getId);
|
||||
|
||||
});
|
||||
// 获取所有用户的合同统计列表
|
||||
List<ContractStatisticsDTO> contractStatisticsDTOS = contractApi.getContractStatistics(userIds, pageReqVO.getCreateTime()).getCheckedData();
|
||||
Map<Long, ContractStatisticsDTO> contractMap = convertMap(contractStatisticsDTOS, ContractStatisticsDTO::getUserId);
|
||||
|
||||
// 获取所有用户的线索统计列表
|
||||
List<CrmCluesStatisticsRespVO> cluesStatisticsRespVOS = cluesService.getCluesStatisticsByUserIds(userIds, pageReqVO.getCreateTime());
|
||||
Map<Long, CrmCluesStatisticsRespVO> clusesMap = convertMap(cluesStatisticsRespVOS, CrmCluesStatisticsRespVO::getOwnerUserId);
|
||||
|
||||
pageResult1.getList().forEach(v -> {
|
||||
|
||||
String per = "0";
|
||||
if (contractMap.get(v.getId()) == null) {
|
||||
// 设置合同数量
|
||||
v.setContractCount(0L);
|
||||
// 设置合同金额
|
||||
v.setContractMoney(BigDecimal.ZERO);
|
||||
// 设置回款金额
|
||||
v.setReceivablesMoney(BigDecimal.ZERO);
|
||||
// 设置线索数量
|
||||
v.setCluesCount(0L);
|
||||
// 设置转客数量
|
||||
v.setCluesToCustomerCount(0L);
|
||||
v.setCluesToCustomerPer(per);
|
||||
}else {
|
||||
|
||||
// 设置合同数量
|
||||
v.setContractCount(Long.valueOf(contractMap.get(v.getId()).getCount()));
|
||||
// 设置合同金额
|
||||
v.setContractMoney(contractMap.get(v.getId()).getMoney());
|
||||
// 设置回款金额
|
||||
v.setReceivablesMoney(BigDecimal.ZERO);
|
||||
// 设置线索数量
|
||||
v.setCluesCount(Long.valueOf(clusesMap.get(v.getId()).getCount()));
|
||||
// 设置转客数量
|
||||
v.setCluesToCustomerCount(Long.valueOf(clusesMap.get(v.getId()).getSuccessCount()));
|
||||
// 设置转客比率
|
||||
if (v.getCluesCount() > 0) {
|
||||
per = NumberUtil.round(NumberUtil.div(v.getCluesToCustomerCount(), v.getCluesCount()), 2)
|
||||
.multiply(new BigDecimal("100")).toString();
|
||||
}
|
||||
v.setCluesToCustomerPer(per);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
return pageResult1;
|
||||
}
|
||||
|
@ -6,6 +6,10 @@ import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.AchievementPa
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.CustomerLevelVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.UserRecordVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.UserVolumeVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CustomerStatisticRespVO;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 客户分析 Service 接口
|
||||
@ -45,5 +49,11 @@ public interface CustomerService {
|
||||
*/
|
||||
PageResult<UserRecordVO> getRecord(AchievementPageReqVO pageReqVO);
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定用户的客户统计信息列表
|
||||
* @param userIds 用户id集合
|
||||
* @param createTime 创建时间
|
||||
* @return 客户统计信息
|
||||
*/
|
||||
List<CustomerStatisticRespVO> getCustomerStatistic(List<Long> userIds, LocalDateTime[] createTime);
|
||||
}
|
||||
|
@ -1,23 +1,24 @@
|
||||
package cn.iocoder.yudao.module.crm.service.crmanalysis;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.AchievementPageReqVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.CustomerLevelVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.UserRecordVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.UserVolumeVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CustomerStatisticRespVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.RecordStatisticsRespVO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecord.CrmRecordDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmachievement.CrmAchievementMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmclues.CrmCluesMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontract.CrmContractMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontractreceivables.CrmContractReceivablesMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmcustomer.CrmCustomerMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecord.CrmRecordMapper;
|
||||
import cn.iocoder.yudao.module.hrm.enums.TypesEnum;
|
||||
import cn.iocoder.yudao.module.crm.service.crmrecord.CrmRecordService;
|
||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
|
||||
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
|
||||
@ -30,10 +31,15 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
|
||||
/**
|
||||
* 客户分析 Service 实现类
|
||||
*
|
||||
@ -43,25 +49,17 @@ import java.util.stream.Collectors;
|
||||
@Validated
|
||||
public class CustomerServiceImpl implements CustomerService {
|
||||
|
||||
@Resource
|
||||
private CrmAchievementMapper achievementMapper;
|
||||
@Resource
|
||||
private DeptApi deptApi;
|
||||
@Resource
|
||||
private DictDataApi dictDataApi;
|
||||
@Resource
|
||||
private CrmContractMapper contractMapper;
|
||||
@Resource
|
||||
private CrmContractReceivablesMapper contractReceivablesMapper;
|
||||
@Resource
|
||||
private CrmCluesMapper crmCluesMapper;
|
||||
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@Resource
|
||||
private CrmCustomerMapper customerMapper;
|
||||
|
||||
@Resource
|
||||
private CrmRecordMapper crmRecordMapper;
|
||||
private CrmRecordService recordService;
|
||||
|
||||
@Override
|
||||
public CustomerLevelVO getCustomerLevel() {
|
||||
@ -127,31 +125,41 @@ public class CustomerServiceImpl implements CustomerService {
|
||||
|
||||
@Override
|
||||
public PageResult<UserVolumeVO> getCustomerVolume(AchievementPageReqVO pageReqVO) {
|
||||
|
||||
AdminUserPageApiDTO dto = new AdminUserPageApiDTO();
|
||||
dto.setUsername(pageReqVO.getName());
|
||||
dto.setNickname(pageReqVO.getName());
|
||||
dto.setPageNo(pageReqVO.getPageNo());
|
||||
dto.setPageSize(pageReqVO.getPageSize());
|
||||
PageResult<AdminUserApiVO> pageResult = adminUserApi.getUserPage(dto).getCheckedData();
|
||||
dto.setRoleCodes("sale"); // 设置查询用户的角色类型
|
||||
|
||||
PageResult<AdminUserApiVO> pageResult = adminUserApi.getUserPageByRole(dto).getCheckedData();
|
||||
PageResult<UserVolumeVO> pageResult1 = BeanUtils.toBean(pageResult, UserVolumeVO.class);
|
||||
pageResult1.getList().forEach(v -> {
|
||||
LambdaQueryWrapperX<CrmCustomerDO> wrapperX = new LambdaQueryWrapperX<>();
|
||||
wrapperX.eq(CrmCustomerDO::getOwnerUserId, v.getId())
|
||||
.betweenIfPresent(CrmCustomerDO::getCreateTime, pageReqVO.getCreateTime());
|
||||
Long customerCount = customerMapper.selectCount(wrapperX);
|
||||
wrapperX.eq(CrmCustomerDO::getDealStatus, ShopCommonEnum.IS_STATUS_1.getValue());
|
||||
Long successCount = customerMapper.selectCount(wrapperX);
|
||||
if (CollectionUtil.isNotEmpty(pageResult1.getList())) {
|
||||
|
||||
v.setCustomerCount(customerCount);
|
||||
v.setSuccessCount(successCount);
|
||||
List<Long> userIds = convertList(pageResult1.getList(), UserVolumeVO::getId);
|
||||
// 获取所有用户的客户统计列表
|
||||
List<CustomerStatisticRespVO> statisticRespVOS = this.getCustomerStatistic(userIds, pageReqVO.getCreateTime());
|
||||
Map<Long, CustomerStatisticRespVO> customerMap = convertMap(statisticRespVOS, CustomerStatisticRespVO::getOwnerUserId);
|
||||
|
||||
String per = "0";
|
||||
if (customerCount > 0) {
|
||||
per = NumberUtil.round(NumberUtil.div(successCount, customerCount), 2)
|
||||
.multiply(new BigDecimal("100")).toString();
|
||||
}
|
||||
v.setSuccessPer(per);
|
||||
pageResult1.getList().forEach(v -> {
|
||||
|
||||
});
|
||||
String per = "0";
|
||||
if (customerMap.get(v.getId()) == null) {
|
||||
v.setCustomerCount(0L);
|
||||
v.setSuccessCount(0L);
|
||||
v.setSuccessPer(per);
|
||||
}else {
|
||||
v.setCustomerCount(Long.valueOf(customerMap.get(v.getId()).getCount()));
|
||||
v.setSuccessCount(Long.valueOf(customerMap.get(v.getId()).getDealsCount()));
|
||||
|
||||
if (v.getCustomerCount() > 0) {
|
||||
per = NumberUtil.round(NumberUtil.div(v.getSuccessCount(), v.getCustomerCount()), 2)
|
||||
.multiply(new BigDecimal("100")).toString();
|
||||
}
|
||||
v.setSuccessPer(per);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return pageResult1;
|
||||
}
|
||||
@ -162,30 +170,48 @@ public class CustomerServiceImpl implements CustomerService {
|
||||
dto.setUsername(pageReqVO.getName());
|
||||
dto.setPageNo(pageReqVO.getPageNo());
|
||||
dto.setPageSize(pageReqVO.getPageSize());
|
||||
PageResult<AdminUserApiVO> pageResult = adminUserApi.getUserPage(dto).getCheckedData();
|
||||
dto.setRoleCodes("sale"); // 设置查询用户的角色类型
|
||||
|
||||
PageResult<AdminUserApiVO> pageResult = adminUserApi.getUserPageByRole(dto).getCheckedData();
|
||||
PageResult<UserRecordVO> pageResult1 = BeanUtils.toBean(pageResult, UserRecordVO.class);
|
||||
pageResult1.getList().forEach(v -> {
|
||||
LambdaQueryWrapperX<CrmRecordDO> wrapperX = new LambdaQueryWrapperX<>();
|
||||
wrapperX.eq(CrmRecordDO::getCreator, v.getId())
|
||||
.betweenIfPresent(CrmRecordDO::getCreateTime, pageReqVO.getCreateTime());
|
||||
Long totalCount = crmRecordMapper.selectCount(wrapperX);
|
||||
if (CollectionUtil.isNotEmpty(pageResult1.getList())) {
|
||||
|
||||
wrapperX.eq(CrmRecordDO::getTypes, TypesEnum.CUSTOMER.getValue());
|
||||
Long customerCount = crmRecordMapper.selectCount(wrapperX);
|
||||
// 获取所有用户跟进统计列表
|
||||
List<Long> userIds = convertList(pageResult1.getList(), UserRecordVO::getId);
|
||||
List<RecordStatisticsRespVO> respVOS = recordService.getRecordStatistics(userIds, pageReqVO.getCreateTime());
|
||||
Map<String, RecordStatisticsRespVO> recordMap = convertMap(respVOS, RecordStatisticsRespVO::getCreator);
|
||||
|
||||
wrapperX.eq(CrmRecordDO::getTypes, TypesEnum.BUSINESS.getValue());
|
||||
Long businessCount = crmRecordMapper.selectCount(wrapperX);
|
||||
pageResult1.getList().forEach(v -> {
|
||||
|
||||
wrapperX.eq(CrmRecordDO::getTypes, TypesEnum.CLUES.getValue());
|
||||
Long cluesCount = crmRecordMapper.selectCount(wrapperX);
|
||||
|
||||
v.setTotalCount(totalCount);
|
||||
v.setCustomerCount(customerCount);
|
||||
v.setBusinessCount(businessCount);
|
||||
v.setCluesCount(cluesCount);
|
||||
|
||||
});
|
||||
RecordStatisticsRespVO respVO = recordMap.get(v.getId().toString());
|
||||
if (respVO == null) {
|
||||
// 设置跟进总数量
|
||||
v.setTotalCount(0L);
|
||||
// 设置跟进客户数量
|
||||
v.setCustomerCount(0L);
|
||||
// 设置跟进商机数量
|
||||
v.setBusinessCount(0L);
|
||||
// 设置跟进线索数量
|
||||
v.setCluesCount(0L);
|
||||
}else {
|
||||
// 设置跟进总数量
|
||||
v.setTotalCount(Long.valueOf(respVO.getCount()));
|
||||
// 设置跟进客户数量
|
||||
v.setCustomerCount(Long.valueOf(respVO.getCustomerCount()));
|
||||
// 设置跟进商机数量
|
||||
v.setBusinessCount(Long.valueOf(respVO.getBusinessCount()));
|
||||
// 设置跟进线索数量
|
||||
v.setCluesCount(Long.valueOf(respVO.getCluesCount()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return pageResult1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CustomerStatisticRespVO> getCustomerStatistic(List<Long> userIds, LocalDateTime[] createTime) {
|
||||
|
||||
return customerMapper.selectStatistic(userIds, createTime);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CustomerImpor
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmclues.CrmCluesDO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -88,5 +89,10 @@ public interface CrmCluesService {
|
||||
*/
|
||||
void transfer(CrmCluesTransferVO transferVO);
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定用户的线索统计信息
|
||||
* @param ownerUserIds 用户ID
|
||||
* @return 线索统计信息列表
|
||||
*/
|
||||
List<CrmCluesStatisticsRespVO> getCluesStatisticsByUserIds(List<Long> ownerUserIds, LocalDateTime[] createTime);
|
||||
}
|
||||
|
@ -268,4 +268,10 @@ public class CrmCluesServiceImpl implements CrmCluesService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CrmCluesStatisticsRespVO> getCluesStatisticsByUserIds(List<Long> ownerUserIds, LocalDateTime[] createTime) {
|
||||
|
||||
return cluesMapper.selectStatisticsByUserIds(ownerUserIds, createTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
package cn.iocoder.yudao.module.crm.service.crmcontract;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.*;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.CheckInfoVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.CrmContractPageReqVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.CrmContractRespVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.CrmContractSaveReqVO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractProductDO;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -74,4 +77,10 @@ public interface CrmContractService {
|
||||
*/
|
||||
void check(CheckInfoVO checkInfoVO);
|
||||
|
||||
/**
|
||||
* 创建合同产品
|
||||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
*/
|
||||
void createProduct(List<CrmContractProductDO> createReqVO);
|
||||
}
|
||||
|
@ -390,6 +390,12 @@ public class CrmContractServiceImpl implements CrmContractService {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createProduct(List<CrmContractProductDO> createReqVO) {
|
||||
|
||||
contractProductMapper.insertBatch(createReqVO);
|
||||
}
|
||||
|
||||
private void createContractProductList(Long contractId, List<CrmContractProductDO> list) {
|
||||
List<StoreProductAttrValueApiVO> storeProductAttrValueList = new ArrayList<>();
|
||||
if (CollUtil.isNotEmpty(list)) {
|
||||
|
@ -29,6 +29,13 @@ public interface CrmCustomerService {
|
||||
*/
|
||||
void updateCustomer(@Valid CrmCustomerSaveReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 更新客户成交信息
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updateCustomerPurchaseTotal(@Valid CrmCustomerSaveReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 删除客户
|
||||
*
|
||||
|
@ -8,7 +8,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcontractreceivables.vo.CrmContractReceivablesRespVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.*;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractDO;
|
||||
@ -116,7 +115,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateCustomer(CrmCustomerSaveReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
validateCustomerExists(updateReqVO.getId());
|
||||
CrmCustomerDO customerDO = validateCustomerExists(updateReqVO.getId());
|
||||
// 更新
|
||||
CrmCustomerDO updateObj = BeanUtils.toBean(updateReqVO, CrmCustomerDO.class);
|
||||
customerMapper.updateById(updateObj);
|
||||
@ -125,6 +124,26 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
||||
crmOperatelogService.createLog("修改客户", updateReqVO.getId(), 0L, 0L);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateCustomerPurchaseTotal(CrmCustomerSaveReqVO updateReqVO) {
|
||||
|
||||
// 校验存在
|
||||
CrmCustomerDO customerDO = validateCustomerExists(updateReqVO.getId());
|
||||
|
||||
// 更新
|
||||
updateReqVO.setPurchaseTimes(customerDO.getPurchaseTimes() + 1);
|
||||
updateReqVO.setPurchaseTotal(customerDO.getPurchaseTotal().add(updateReqVO.getPurchaseTotal()));
|
||||
CrmCustomerDO updateObj = BeanUtils.toBean(updateReqVO, CrmCustomerDO.class);
|
||||
|
||||
customerMapper.updateById(updateObj);
|
||||
|
||||
//插入日志
|
||||
crmOperatelogService.createLog("修改客户", updateReqVO.getId(), 0L, 0L);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteCustomer(Long id) {
|
||||
@ -197,10 +216,12 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
||||
crmOperatelogService.createLog("公海领取客户", id, 0L, 0L);
|
||||
}
|
||||
|
||||
private void validateCustomerExists(Long id) {
|
||||
if (customerMapper.selectById(id) == null) {
|
||||
private CrmCustomerDO validateCustomerExists(Long id) {
|
||||
CrmCustomerDO customerDO = customerMapper.selectById(id);
|
||||
if (customerDO == null) {
|
||||
throw exception(CUSTOMER_NOT_EXISTS);
|
||||
}
|
||||
return customerDO;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,10 @@
|
||||
package cn.iocoder.yudao.module.crm.service.crmcustomercontacts;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomercontacts.vo.*;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomercontacts.vo.CrmCustomerContactsPageReqVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomercontacts.vo.CrmCustomerContactsRespVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomercontacts.vo.CrmCustomerContactsSaveReqVO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
@ -48,5 +51,4 @@ public interface CrmCustomerContactsService {
|
||||
* @return 联系人分页
|
||||
*/
|
||||
PageResult<CrmCustomerContactsRespVO> getCustomerContactsPage(CrmCustomerContactsPageReqVO pageReqVO);
|
||||
|
||||
}
|
||||
|
@ -95,5 +95,4 @@ public class CrmCustomerContactsServiceImpl implements CrmCustomerContactsServic
|
||||
IPage<CrmCustomerContactsRespVO> pageResult = customerContactsMapper.selectPageList(mpPage, pageReqVO, ids);
|
||||
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,12 +5,12 @@ import cn.hutool.core.util.NumberUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
|
||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.ContractStatisticsDTO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmindex.vo.BrieCountVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmindex.vo.CrmIndexRespVO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmclues.CrmCluesDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontractreceivables.CrmContractReceivablesDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomercontacts.CrmCustomerContactsDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecord.CrmRecordDO;
|
||||
@ -26,7 +26,6 @@ import cn.iocoder.yudao.module.system.api.notice.NoticeApi;
|
||||
import cn.iocoder.yudao.module.system.api.notice.dto.NoticeDTO;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
@ -64,6 +63,9 @@ public class CrmIndexServiceImpl implements CrmIndexService {
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@Resource
|
||||
private BpmOAContractApi bpmOAContractApi;
|
||||
|
||||
|
||||
@Override
|
||||
public CrmIndexRespVO getIndexCount(String relation) {
|
||||
@ -180,65 +182,81 @@ public class CrmIndexServiceImpl implements CrmIndexService {
|
||||
.multiply(new BigDecimal("100")).toString();
|
||||
}
|
||||
|
||||
Long count05 = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
|
||||
.in(!ids.isEmpty(), CrmContractDO::getOwnerUserId, ids)
|
||||
.between(CrmContractDO::getCreateTime, todayStart, todayEnd));
|
||||
Long count005 = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
|
||||
.in(!ids.isEmpty(), CrmContractDO::getOwnerUserId, ids)
|
||||
.between(CrmContractDO::getCreateTime, yesterdayStart, yesterdayEnd));
|
||||
String per005 = "0";
|
||||
if (count005 > 0) {
|
||||
per005 = NumberUtil.div(NumberUtil.sub(count05, count005), count005, 2)
|
||||
.multiply(new BigDecimal("100")).toString();
|
||||
}
|
||||
// 获取今日合同新增数量
|
||||
ContractStatisticsDTO contractStatisticsDTO = bpmOAContractApi.getContractCount(relation).getCheckedData();
|
||||
// 设置今日新增数量
|
||||
Long count05 = Long.valueOf(contractStatisticsDTO.getTodayAdditions());
|
||||
// 设置昨日新增数量
|
||||
Long count005 = Long.valueOf(contractStatisticsDTO.getYesterdayAdditions());
|
||||
// 设置较昨日比率
|
||||
String per005 = contractStatisticsDTO.getCountPercentage().toString();
|
||||
// 设置今日新增金额
|
||||
BigDecimal count06 = contractStatisticsDTO.getTodayAddMoney();
|
||||
// 设置昨日新增金额
|
||||
BigDecimal count006 = contractStatisticsDTO.getYesterdayAddMoney();
|
||||
// 设置较昨日比率
|
||||
String per006 = contractStatisticsDTO.getMoneyPercentage().toString();
|
||||
|
||||
QueryWrapper<CrmContractDO> queryWrapper06 = new QueryWrapper<>();
|
||||
queryWrapper06.select("sum(money) as count06");
|
||||
queryWrapper06.eq("to_days(create_time)", "to_days(now())");
|
||||
queryWrapper06.in(!ids.isEmpty(), "owner_user_id", ids);
|
||||
CrmContractDO crmContractDO = contractMapper.selectOne(queryWrapper06);
|
||||
BigDecimal count06 = BigDecimal.ZERO;
|
||||
if (crmContractDO != null) {
|
||||
count06 = crmContractDO.getCount06();
|
||||
}
|
||||
// Long count05 = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
|
||||
// .in(!ids.isEmpty(), CrmContractDO::getOwnerUserId, ids)
|
||||
// .between(CrmContractDO::getCreateTime, todayStart, todayEnd));
|
||||
// Long count005 = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
|
||||
// .in(!ids.isEmpty(), CrmContractDO::getOwnerUserId, ids)
|
||||
// .between(CrmContractDO::getCreateTime, yesterdayStart, yesterdayEnd));
|
||||
// String per005 = "0";
|
||||
// if (count005 > 0) {
|
||||
// per005 = NumberUtil.div(NumberUtil.sub(count05, count005), count005, 2)
|
||||
// .multiply(new BigDecimal("100")).toString();
|
||||
// }
|
||||
|
||||
QueryWrapper<CrmContractDO> queryWrapper006 = new QueryWrapper<>();
|
||||
queryWrapper006.select("sum(money) as count006");
|
||||
queryWrapper006.eq("to_days(now())-to_days(create_time)", 1);
|
||||
queryWrapper006.in(!ids.isEmpty(), "owner_user_id", ids);
|
||||
CrmContractDO crmContractDO006 = contractMapper.selectOne(queryWrapper006);
|
||||
BigDecimal count006 = BigDecimal.ZERO;
|
||||
if (crmContractDO006 != null) {
|
||||
count006 = crmContractDO006.getCount006();
|
||||
}
|
||||
String per006 = "0";
|
||||
if (count006.compareTo(BigDecimal.ZERO) > 0) {
|
||||
per006 = NumberUtil.div(NumberUtil.sub(count06, count006), count006, 2)
|
||||
.multiply(new BigDecimal("100")).toString();
|
||||
}
|
||||
// QueryWrapper<CrmContractDO> queryWrapper06 = new QueryWrapper<>();
|
||||
// queryWrapper06.select("sum(money) as count06");
|
||||
// queryWrapper06.eq("to_days(create_time)", "to_days(now())");
|
||||
// queryWrapper06.in(!ids.isEmpty(), "owner_user_id", ids);
|
||||
// CrmContractDO crmContractDO = contractMapper.selectOne(queryWrapper06);
|
||||
// BigDecimal count06 = BigDecimal.ZERO;
|
||||
// if (crmContractDO != null) {
|
||||
// count06 = crmContractDO.getCount06();
|
||||
// }
|
||||
//
|
||||
// QueryWrapper<CrmContractDO> queryWrapper006 = new QueryWrapper<>();
|
||||
// queryWrapper006.select("sum(money) as count006");
|
||||
// queryWrapper006.eq("to_days(now())-to_days(create_time)", 1);
|
||||
// queryWrapper006.in(!ids.isEmpty(), "owner_user_id", ids);
|
||||
// CrmContractDO crmContractDO006 = contractMapper.selectOne(queryWrapper006);
|
||||
// BigDecimal count006 = BigDecimal.ZERO;
|
||||
// if (crmContractDO006 != null) {
|
||||
// count006 = crmContractDO006.getCount006();
|
||||
// }
|
||||
// String per006 = "0";
|
||||
// if (count006.compareTo(BigDecimal.ZERO) > 0) {
|
||||
// per006 = NumberUtil.div(NumberUtil.sub(count06, count006), count006, 2)
|
||||
// .multiply(new BigDecimal("100")).toString();
|
||||
// }
|
||||
|
||||
|
||||
QueryWrapper<CrmContractReceivablesDO> queryWrapper07 = new QueryWrapper<>();
|
||||
queryWrapper07.select("sum(money) as count07");
|
||||
queryWrapper07.eq("to_days(create_time)", "to_days(now())");
|
||||
CrmContractReceivablesDO crmContractReceivablesDO = contractReceivablesMapper.selectOne(queryWrapper07);
|
||||
// QueryWrapper<CrmContractReceivablesDO> queryWrapper07 = new QueryWrapper<>();
|
||||
// queryWrapper07.select("sum(money) as count07");
|
||||
// queryWrapper07.eq("to_days(create_time)", "to_days(now())");
|
||||
// CrmContractReceivablesDO crmContractReceivablesDO = contractReceivablesMapper.selectOne(queryWrapper07);
|
||||
BigDecimal count07 = BigDecimal.ZERO;
|
||||
if (crmContractDO != null) {
|
||||
count07 = crmContractReceivablesDO.getCount07();
|
||||
}
|
||||
QueryWrapper<CrmContractReceivablesDO> queryWrapper007 = new QueryWrapper<>();
|
||||
queryWrapper007.select("sum(money) as count007");
|
||||
queryWrapper007.eq("to_days(now())-to_days(create_time)", 1);
|
||||
CrmContractReceivablesDO crmContractReceivablesDO007 = contractReceivablesMapper.selectOne(queryWrapper007);
|
||||
// if (crmContractDO != null) {
|
||||
// count07 = crmContractReceivablesDO.getCount07();
|
||||
// }
|
||||
// QueryWrapper<CrmContractReceivablesDO> queryWrapper007 = new QueryWrapper<>();
|
||||
// queryWrapper007.select("sum(money) as count007");
|
||||
// queryWrapper007.eq("to_days(now())-to_days(create_time)", 1);
|
||||
// CrmContractReceivablesDO crmContractReceivablesDO007 = contractReceivablesMapper.selectOne(queryWrapper007);
|
||||
BigDecimal count007 = BigDecimal.ZERO;
|
||||
if (crmContractReceivablesDO007 != null) {
|
||||
count007 = crmContractReceivablesDO007.getCount007();
|
||||
}
|
||||
// if (crmContractReceivablesDO007 != null) {
|
||||
// count007 = crmContractReceivablesDO007.getCount007();
|
||||
// }
|
||||
String per007 = "0";
|
||||
if (count007.compareTo(BigDecimal.ZERO) > 0) {
|
||||
per007 = NumberUtil.div(NumberUtil.sub(count07, count007), count007, 2)
|
||||
.multiply(new BigDecimal("100")).toString();
|
||||
}
|
||||
// if (count007.compareTo(BigDecimal.ZERO) > 0) {
|
||||
// per007 = NumberUtil.div(NumberUtil.sub(count07, count007), count007, 2)
|
||||
// .multiply(new BigDecimal("100")).toString();
|
||||
// }
|
||||
|
||||
|
||||
Long count08 = customerContactsMapper.selectCount(new LambdaQueryWrapper<CrmCustomerContactsDO>()
|
||||
.in(!ids.isEmpty(), CrmCustomerContactsDO::getOwnerUserId, ids)
|
||||
|
@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.crm.service.crminvoice;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
@ -25,7 +24,6 @@ import cn.iocoder.yudao.module.crm.dal.mysql.crmflowlog.CrmFlowLogMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crminvoice.CrmInvoiceMapper;
|
||||
import cn.iocoder.yudao.module.hrm.enums.*;
|
||||
import cn.iocoder.yudao.module.system.api.mail.MailSendApi;
|
||||
import cn.iocoder.yudao.module.system.api.mail.dto.MailSendSingleReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -38,9 +36,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
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.hrm.enums.ErrorCodeConstants.*;
|
||||
@ -71,8 +67,6 @@ public class CrmInvoiceServiceImpl implements CrmInvoiceService {
|
||||
private RedissonClient redissonClient;
|
||||
@Resource
|
||||
private CrmFlowLogMapper crmFlowLogMapper;
|
||||
@Resource
|
||||
private MailSendApi mailSendApi;
|
||||
|
||||
private static final String LOCK_KEY = "invoice:check:lock";
|
||||
|
||||
@ -301,13 +295,13 @@ public class CrmInvoiceServiceImpl implements CrmInvoiceService {
|
||||
crmContractDO.setInvoiceMoney(money);
|
||||
contractMapper.updateById(crmContractDO);
|
||||
|
||||
//发送邮件
|
||||
if(StrUtil.isNotEmpty(updateObj.getFiles()) && StrUtil.isNotEmpty(updateObj.getEmail())){
|
||||
Map<String, Object> templateParams = new HashMap<>();
|
||||
templateParams.put("files",updateObj.getFiles());
|
||||
mailSendApi.sendSingleMail(new MailSendSingleReqDTO()
|
||||
.setMail(updateObj.getEmail()).setUserId(updateObj.getCustomerId()).setUserType(UserTypeEnum.CUSTOMER.getValue())
|
||||
.setTemplateCode("invoice-send").setTemplateParams(templateParams));
|
||||
}
|
||||
// //发送邮件
|
||||
// if(StrUtil.isNotEmpty(updateObj.getFiles()) && StrUtil.isNotEmpty(updateObj.getEmail())){
|
||||
// Map<String, Object> templateParams = new HashMap<>();
|
||||
// templateParams.put("files",updateObj.getFiles());
|
||||
// mailSendApi.sendSingleMail(new MailSendSingleReqDTO()
|
||||
// .setMail(updateObj.getEmail()).setUserId(updateObj.getCustomerId()).setUserType(UserTypeEnum.CUSTOMER.getValue())
|
||||
// .setTemplateCode("invoice-send").setTemplateParams(templateParams));
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.*;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecord.CrmRecordDO;
|
||||
import javax.validation.Valid;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 跟进记录 Service 接口
|
||||
@ -50,4 +52,12 @@ public interface CrmRecordService {
|
||||
*/
|
||||
PageResult<CrmRecordRespVO> getRecordPage(CrmRecordPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 获得跟进统计
|
||||
* @param userIds 跟进人用户编号
|
||||
* @param createTime 创建时间
|
||||
* @return 跟进统计列表
|
||||
*/
|
||||
List<RecordStatisticsRespVO> getRecordStatistics(List<Long> userIds, LocalDateTime[] createTime);
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.CrmRecordPageReqVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.CrmRecordRespVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.CrmRecordSaveReqVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.RecordStatisticsRespVO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmclues.CrmCluesDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
|
||||
@ -155,4 +156,10 @@ public class CrmRecordServiceImpl implements CrmRecordService {
|
||||
return pageResult1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RecordStatisticsRespVO> getRecordStatistics(List<Long> userIds, LocalDateTime[] createTime) {
|
||||
|
||||
return recordMapper.selectStatistics(userIds, createTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -88,4 +88,28 @@
|
||||
</where>
|
||||
order by a.id desc
|
||||
</select>
|
||||
|
||||
<select id="selectStatisticsByUserIds" resultType="cn.iocoder.yudao.module.crm.controller.admin.crmclues.vo.CrmCluesStatisticsRespVO">
|
||||
SELECT
|
||||
owner_user_id AS ownerUserId,
|
||||
COUNT(1) AS count,
|
||||
COUNT( CASE WHEN status = 1 THEN 1 END ) AS successCount
|
||||
FROM
|
||||
crm_clues
|
||||
WHERE
|
||||
deleted = 0
|
||||
AND owner_user_id IN
|
||||
<foreach item="ownerUserId" collection="ownerUserIds" separator="," open="(" close=")" index="">
|
||||
#{ownerUserId}
|
||||
</foreach>
|
||||
<if test="createTime != null and createTime.length > 0">
|
||||
<if test="createTime[0] != null">
|
||||
AND create_time >= #{createTime[0]}
|
||||
</if>
|
||||
<if test="createTime[1] != null">
|
||||
AND create_time <= #{createTime[1]}
|
||||
</if>
|
||||
</if>
|
||||
GROUP BY owner_user_id
|
||||
</select>
|
||||
</mapper>
|
||||
|
@ -60,4 +60,25 @@
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="selectContractTop" resultType="cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.ContractVO">
|
||||
SELECT
|
||||
t.user_id AS id,
|
||||
COUNT( t.id ) AS count,
|
||||
SUM( t.contract_money ) AS money,
|
||||
u.nickname AS nickname
|
||||
FROM
|
||||
bpm_oa_contract t
|
||||
LEFT JOIN system_users u ON ( u.id = t.user_id )
|
||||
AND u.deleted = 0
|
||||
WHERE
|
||||
t.deleted = 0
|
||||
AND t.result = 2
|
||||
AND t.contract_type = 1
|
||||
GROUP BY
|
||||
t.user_id
|
||||
ORDER BY
|
||||
money DESC
|
||||
LIMIT 10
|
||||
</select>
|
||||
</mapper>
|
||||
|
@ -50,4 +50,28 @@
|
||||
</where>
|
||||
order by a.id desc
|
||||
</select>
|
||||
|
||||
<select id="selectStatistic" resultType="cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CustomerStatisticRespVO">
|
||||
SELECT
|
||||
owner_user_id AS ownerUserId,
|
||||
COUNT(1) AS count,
|
||||
COUNT( CASE WHEN deal_status = 1 THEN 1 END ) AS DealsCount
|
||||
FROM
|
||||
crm_customer
|
||||
WHERE
|
||||
deleted = 0
|
||||
AND owner_user_id IN
|
||||
<foreach item="userId" collection="userIds" separator="," open="(" close=")" index="">
|
||||
#{userId}
|
||||
</foreach>
|
||||
<if test="createTime != null and createTime.length > 0">
|
||||
<if test="createTime[0] != null">
|
||||
AND create_time >= #{createTime[0]}
|
||||
</if>
|
||||
<if test="createTime[1] != null">
|
||||
AND create_time <= #{createTime[1]}
|
||||
</if>
|
||||
</if>
|
||||
GROUP BY owner_user_id
|
||||
</select>
|
||||
</mapper>
|
||||
|
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.iocoder.yudao.module.crm.dal.mysql.crmrecord.CrmRecordMapper">
|
||||
|
||||
<!--
|
||||
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
|
||||
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
|
||||
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
|
||||
文档可见:https://www.yixiang.co/MyBatis/x-plugins/
|
||||
-->
|
||||
|
||||
<select id="selectStatistics" resultType="cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.RecordStatisticsRespVO">
|
||||
SELECT
|
||||
creator AS creator,
|
||||
COUNT(1) AS count,
|
||||
SUM(CASE WHEN types = 'business' THEN 1 ELSE 0 END) AS businessCount,
|
||||
SUM(CASE WHEN types = 'customer' THEN 1 ELSE 0 END) AS customerCount,
|
||||
SUM(CASE WHEN types = 'clues' THEN 1 ELSE 0 END) AS cluesCount
|
||||
FROM
|
||||
crm_record
|
||||
WHERE
|
||||
deleted = 0
|
||||
AND creator IN
|
||||
<foreach item="userId" collection="userIds" separator="," open="(" close=")" index="">
|
||||
#{userId}
|
||||
</foreach>
|
||||
<if test="createTime != null and createTime.length > 0">
|
||||
<if test="createTime[0] != null">
|
||||
AND create_time >= #{createTime[0]}
|
||||
</if>
|
||||
<if test="createTime[1] != null">
|
||||
AND create_time <= #{createTime[1]}
|
||||
</if>
|
||||
</if>
|
||||
GROUP BY creator
|
||||
</select>
|
||||
</mapper>
|
@ -1,19 +1,13 @@
|
||||
package cn.iocoder.yudao.module.product.api.storeproduct;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.dto.StoreProductAttrValueApiDTO;
|
||||
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.vo.StoreProductAttrValueApiVO;
|
||||
import cn.iocoder.yudao.module.product.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||
@Tag(name = "RPC 服务 - 商品属性值 API")
|
||||
public interface StoreProductApi {
|
||||
@ -21,10 +15,15 @@ public interface StoreProductApi {
|
||||
String PREFIX = ApiConstants.PREFIX + "/storeProduct";
|
||||
|
||||
@GetMapping(PREFIX + "/decStockIncSales")
|
||||
@Schema(description = "正常商品 加库存 减销量")
|
||||
@Schema(description = "正常商品库存 减库存 加销量")
|
||||
CommonResult<Integer> decStockIncSales(@RequestParam(name = "num") Integer num,
|
||||
@RequestParam(name = "productId") Long productId);
|
||||
|
||||
@GetMapping(PREFIX + "/inStockIncSales")
|
||||
@Schema(description = "正常商品库存 加库存 减销量")
|
||||
CommonResult<Integer> inStockIncSales(@RequestParam(name = "num") Integer num,
|
||||
@RequestParam(name = "productId") Long productId);
|
||||
|
||||
@GetMapping(PREFIX + "/selectCount")
|
||||
@Schema(description = "获取数量")
|
||||
CommonResult<Long> selectCount();
|
||||
|
@ -25,9 +25,15 @@ public interface StoreProductAttrValueApi {
|
||||
CommonResult<List<StoreProductAttrValueApiVO>> getStoreProductAttrValueList(@RequestBody StoreProductAttrValueApiDTO dto);
|
||||
|
||||
@GetMapping(PREFIX + "/decStockIncSales")
|
||||
@Schema(description = "正常商品 加库存 减销量")
|
||||
@Schema(description = "普通商品 减库存 加销量")
|
||||
CommonResult<Integer> decStockIncSales(@RequestParam(name = "num") Integer num,
|
||||
@RequestParam(name = "productId") Long productId,
|
||||
@RequestParam(name = "unique") String unique);
|
||||
|
||||
@GetMapping(PREFIX + "/inStockIncSales")
|
||||
@Schema(description = "普通商品 加库存 减销量")
|
||||
CommonResult<Integer> inStockIncSales(@RequestParam(name = "num") Integer num,
|
||||
@RequestParam(name = "productId") Long productId,
|
||||
@RequestParam(name = "unique") String unique);
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* 商品 SPU API 接口实现类
|
||||
*
|
||||
@ -22,12 +24,17 @@ public class StoreProductApiImpl implements StoreProductApi {
|
||||
|
||||
@Override
|
||||
public CommonResult<Integer> decStockIncSales(Integer num, Long productId) {
|
||||
return CommonResult.success(storeProductService.decStockIncSales(num, productId));
|
||||
return success(storeProductService.decStockIncSales(num, productId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Integer> inStockIncSales(Integer num, Long productId) {
|
||||
return success(storeProductService.inStockIncSales(num, productId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> selectCount() {
|
||||
return CommonResult.success(storeProductService.count());
|
||||
return success(storeProductService.count());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,19 +1,20 @@
|
||||
package cn.iocoder.yudao.module.product.api.storeproductattrvalue;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.dto.StoreProductAttrValueApiDTO;
|
||||
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.vo.StoreProductAttrValueApiVO;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.storeproductattrvalue.StoreProductAttrValueDO;
|
||||
import cn.iocoder.yudao.module.product.service.storeproductattrvalue.StoreProductAttrValueService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* 商品 SPU API 接口实现类
|
||||
*
|
||||
@ -29,17 +30,22 @@ public class StoreProductAttrValueApiImpl implements StoreProductAttrValueApi {
|
||||
|
||||
@Override
|
||||
public CommonResult<List<StoreProductAttrValueApiVO>> getStoreProductAttrValueList(StoreProductAttrValueApiDTO dto) {
|
||||
List<StoreProductAttrValueDO> list = storeProductAttrValueService.list(new LambdaQueryWrapper<StoreProductAttrValueDO>()
|
||||
.in(CollUtil.isNotEmpty(dto.getProductIds()), StoreProductAttrValueDO::getProductId, dto.getProductIds())
|
||||
.in(CollUtil.isNotEmpty(dto.getUniques()), StoreProductAttrValueDO::getUnique, dto.getUniques())
|
||||
List<StoreProductAttrValueDO> list = storeProductAttrValueService.list(new LambdaQueryWrapperX<StoreProductAttrValueDO>()
|
||||
.inIfPresent(StoreProductAttrValueDO::getProductId, dto.getProductIds())
|
||||
.inIfPresent(StoreProductAttrValueDO::getUnique, dto.getUniques())
|
||||
);
|
||||
List<StoreProductAttrValueApiVO> result = BeanUtil.copyToList(list, StoreProductAttrValueApiVO.class);
|
||||
return CommonResult.success(result);
|
||||
return success(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Integer> decStockIncSales(Integer num, Long productId, String unique) {
|
||||
return CommonResult.success(storeProductAttrValueService.decStockIncSales(num, productId, unique));
|
||||
return success(storeProductAttrValueService.decStockIncSales(num, productId, unique));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Integer> inStockIncSales(Integer num, Long productId, String unique) {
|
||||
return success(storeProductAttrValueService.inStockIncSales(num, productId, unique));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public interface StoreProductAttrValueMapper extends BaseMapperX<StoreProductAtt
|
||||
@Param("unique") String unique);
|
||||
|
||||
/**
|
||||
* 正常商品 加库存 减销量
|
||||
* 普通商品 加库存 减销量
|
||||
*
|
||||
* @param num
|
||||
* @param productId
|
||||
|
@ -109,4 +109,12 @@ public interface StoreProductService extends IService<StoreProductDO> {
|
||||
* @return
|
||||
*/
|
||||
int decStockIncSales(Integer num, Long productId);
|
||||
|
||||
/**
|
||||
* 正常商品库存 加库存 减销量
|
||||
* @param num 数量
|
||||
* @param productId 产品编号
|
||||
* @return
|
||||
*/
|
||||
Integer inStockIncSales(Integer num, Long productId);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user