Compare commits
5 Commits
24ab5dd06a
...
f0ab7b7b9d
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f0ab7b7b9d | ||
![]() |
f9b0c8cf7d | ||
![]() |
1c07abebb0 | ||
![]() |
af22e311ec | ||
![]() |
be9085e3ac |
@ -0,0 +1,37 @@
|
||||
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.receipt.BpmOAReceiptDTO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptVO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
|
||||
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 BpmOAReceiptApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/oa/receipt";
|
||||
|
||||
@GetMapping(PREFIX + "/get-receipt-count")
|
||||
@Operation(summary = "获得当日回款统计 | 新增金额")
|
||||
CommonResult<ReceiptStatisticsDTO> getReceiptCount(@RequestParam("relation") String relation);
|
||||
|
||||
@PostMapping(PREFIX + "/getList")
|
||||
@Operation(summary = "获得回款列表")
|
||||
CommonResult<List<BpmOAReceiptDTO>> getReceiptList(@RequestBody BpmOAReceiptVO respVO);
|
||||
|
||||
@GetMapping(PREFIX + "/get-receipt-statistics")
|
||||
@Operation(summary = "获得指定用户的回款统计信息")
|
||||
CommonResult<List<ReceiptStatisticsDTO>> getContractStatistics(@RequestParam("userId") List<Long> userIds,
|
||||
@RequestParam(name = "createTime", required = false) LocalDateTime[] createTime);
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo.receipt;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author 符溶馨
|
||||
*/
|
||||
@Schema(description = "管理后台 - 退款申请 请求Request VO")
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class BpmOAReceiptDTO {
|
||||
|
||||
@Schema(description = "主键")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "客户ID")
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "客户名称")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "合同ID")
|
||||
private Long contractId;
|
||||
|
||||
@Schema(description = "合同编号")
|
||||
private String contractNo;
|
||||
|
||||
@Schema(description = "合同名称")
|
||||
private String contractName;
|
||||
|
||||
@Schema(description = "回款日期")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate returnTime;
|
||||
|
||||
@Schema(description = "回款金额")
|
||||
private BigDecimal money;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String createName;
|
||||
|
||||
@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,21 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo.receipt;
|
||||
|
||||
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 BpmOAReceiptVO {
|
||||
|
||||
@Schema(description = "用户编号")
|
||||
private List<Long> userId;
|
||||
|
||||
@Schema(description = "开始时间")
|
||||
private Date starTime;
|
||||
|
||||
@Schema(description = "结束时间")
|
||||
private Date endTime;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.oa.vo.receipt;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 合同审批 请求Request VO")
|
||||
@Data
|
||||
public class ReceiptStatisticsDTO {
|
||||
|
||||
@Schema(description = "用户编号")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "今日新增回款金额")
|
||||
private BigDecimal todayAddMoney;
|
||||
|
||||
@Schema(description = "昨日新增回款金额")
|
||||
private BigDecimal yesterdayAddMoney;
|
||||
|
||||
@Schema(description = "较昨日百分比 | 金额")
|
||||
private BigDecimal moneyPercentage;
|
||||
|
||||
@Schema(description = "回款总金额")
|
||||
private BigDecimal money;
|
||||
}
|
@ -61,6 +61,7 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode OA_PROJECT_NOT_EXISTS = new ErrorCode(1_009_001_124, "项目申请不存在");
|
||||
ErrorCode OA_CONTRACT_INVOICE_AMOUNT_LACK = new ErrorCode(1_009_001_125, "该合同的开票余额不足!");
|
||||
ErrorCode OA_PAYMENT_NOT_EXISTS = new ErrorCode(1_009_001_126, "付款申请不存在");
|
||||
ErrorCode OA_RECEIPT_NOT_EXISTS = new ErrorCode(1_009_001_127, "回款申请不存在");
|
||||
|
||||
// ========== 流程模型 1-009-002-000 ==========
|
||||
ErrorCode MODEL_KEY_EXISTS = new ErrorCode(1_009_002_000, "已经存在流程标识为【{}】的流程");
|
||||
|
@ -0,0 +1,48 @@
|
||||
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.receipt.BpmOAReceiptDTO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptVO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.ReceiptStatisticsVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReceiptDO;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReceiptService;
|
||||
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 BpmOAReceiptApiImpl implements BpmOAReceiptApi{
|
||||
|
||||
@Resource
|
||||
private BpmOAReceiptService receiptService;
|
||||
|
||||
@Override
|
||||
public CommonResult<ReceiptStatisticsDTO> getReceiptCount(String relation) {
|
||||
ReceiptStatisticsVO respVO = receiptService.getStatistics(getLoginUserId(), relation);
|
||||
return success(BeanUtils.toBean(respVO, ReceiptStatisticsDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<BpmOAReceiptDTO>> getReceiptList(BpmOAReceiptVO respVO) {
|
||||
List<BpmOAReceiptDO> receiptDO = receiptService.getReceiptList(respVO);
|
||||
return success(BeanUtils.toBean(receiptDO, BpmOAReceiptDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<ReceiptStatisticsDTO>> getContractStatistics(List<Long> userIds, LocalDateTime[] createTime) {
|
||||
List<ReceiptStatisticsDTO> respVOS = receiptService.getReceiptStatisticsListByUserIds(userIds, createTime);
|
||||
return success(BeanUtils.toBean(respVOS, ReceiptStatisticsDTO.class));
|
||||
}
|
||||
}
|
@ -159,5 +159,14 @@ public class BpmOAContractController {
|
||||
return success(respVO);
|
||||
}
|
||||
|
||||
@GetMapping("/getContractByCustomerId")
|
||||
@Operation(summary = "获得指定客户的合同列表")
|
||||
@Parameter(name = "customerId", description = "客户编号", required = true)
|
||||
public CommonResult<List<BpmOAContractRespVO>> getListByCustomerId(@RequestParam("customerId") Long customerId) {
|
||||
|
||||
List<BpmOAContractDO> respVOs = contractService.getListByCustomerId(customerId);
|
||||
|
||||
return success(BeanUtils.toBean(respVOs, BpmOAContractRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.system.api.project.dto.ProjectDTO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@ -63,7 +64,7 @@ public class BpmOAProcureController {
|
||||
public CommonResult<BpmOAProcureRespVO> getOaProcure(@RequestParam("id") Long id) {
|
||||
BpmOAProcureDO oaProcure = bpmOaProcureService.getOaProcure(id);
|
||||
BpmOAProcureRespVO respVO = BpmOAProcureConvert.INSTANCE.convert(oaProcure);
|
||||
if (respVO != null && respVO.getProjectNo() != null) {
|
||||
if (respVO != null && Strings.isNotEmpty(respVO.getProjectNo())) {
|
||||
ProjectDTO projectDTO = projectApi.getProject(respVO.getProjectNo()).getCheckedData();
|
||||
respVO.setProjectName(projectDTO.getName());
|
||||
}
|
||||
@ -86,7 +87,7 @@ public class BpmOAProcureController {
|
||||
|
||||
BpmOAProcureDO oaProcure = bpmOaProcureService.getByProcessInstanceId(processInstanceId);
|
||||
BpmOAProcureRespVO respVO = BpmOAProcureConvert.INSTANCE.convert(oaProcure);
|
||||
if (respVO != null && respVO.getProjectNo() != null) {
|
||||
if (respVO != null && Strings.isNotEmpty(respVO.getProjectNo())) {
|
||||
ProjectDTO projectDTO = projectApi.getProject(respVO.getProjectNo()).getCheckedData();
|
||||
respVO.setProjectName(projectDTO.getName());
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
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.receipt.BpmOAReceiptCreateReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptPageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAContractDO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReceiptDO;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAContractService;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReceiptService;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcustomer.CrmCustomerApi;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcustomer.dto.CrmCustomerDTO;
|
||||
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.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
/**
|
||||
* OA 回款申请 Controller
|
||||
*
|
||||
* @author 符溶馨
|
||||
|
||||
*/
|
||||
@Tag(name = "管理后台 - OA 回款申请")
|
||||
@RestController
|
||||
@RequestMapping("/bpm/oa/receipt")
|
||||
@Validated
|
||||
public class BpmOAReceiptController {
|
||||
|
||||
@Resource
|
||||
private BpmOAReceiptService receiptService;
|
||||
|
||||
@Resource
|
||||
private CrmCustomerApi customerApi;
|
||||
|
||||
@Resource
|
||||
private BpmOAContractService contractService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建请求申请")
|
||||
public CommonResult<Long> createReceipt(@Valid @RequestBody BpmOAReceiptCreateReqVO createReqVO) {
|
||||
|
||||
return success(receiptService.createReceipt(getLoginUserId(), createReqVO));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得回款申请")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
public CommonResult<BpmOAReceiptRespVO> getReceipt(@RequestParam("id") Long id) {
|
||||
|
||||
BpmOAReceiptDO receipt = receiptService.getReceipt(id);
|
||||
BpmOAReceiptRespVO respVO = BeanUtils.toBean(receipt, BpmOAReceiptRespVO.class);
|
||||
if (respVO != null) {
|
||||
|
||||
// 获取客户信息
|
||||
CrmCustomerDTO crmCustomerDTO = customerApi.getCustomer(receipt.getCustomerId()).getCheckedData();
|
||||
// 获取合同信息
|
||||
BpmOAContractDO contractDO = contractService.getContract(receipt.getContractId());
|
||||
|
||||
// 设置客户名称
|
||||
respVO.setCustomerName(crmCustomerDTO != null ? crmCustomerDTO.getName() : null);
|
||||
// 设置合同名称
|
||||
respVO.setContractName(contractDO != null ? contractDO.getContractName() : null);
|
||||
}
|
||||
|
||||
return success(respVO);
|
||||
}
|
||||
|
||||
@GetMapping("/getByProcessInstanceId")
|
||||
@Operation(summary = "获得回款申请")
|
||||
@Parameter(name = "processInstanceId", description = "流程实例编号", required = true, example = "1024")
|
||||
public CommonResult<BpmOAReceiptRespVO> getByProcessInstanceId(@RequestParam("processInstanceId") String processInstanceId) {
|
||||
|
||||
BpmOAReceiptDO receipt = receiptService.getByProcessInstanceId(processInstanceId);
|
||||
BpmOAReceiptRespVO respVO = BeanUtils.toBean(receipt, BpmOAReceiptRespVO.class);
|
||||
if (respVO != null) {
|
||||
|
||||
// 获取客户信息
|
||||
CrmCustomerDTO crmCustomerDTO = customerApi.getCustomer(receipt.getCustomerId()).getCheckedData();
|
||||
// 获取合同信息
|
||||
BpmOAContractDO contractDO = contractService.getContract(receipt.getContractId());
|
||||
|
||||
// 设置客户名称
|
||||
respVO.setCustomerName(crmCustomerDTO != null ? crmCustomerDTO.getName() : null);
|
||||
// 设置合同名称
|
||||
respVO.setContractName(contractDO != null ? contractDO.getContractName() : null);
|
||||
}
|
||||
|
||||
return success(respVO);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得回款分页列表")
|
||||
public CommonResult<PageResult<BpmOAReceiptRespVO>> getPage(@Valid BpmOAReceiptPageReqVO pageReqVO) {
|
||||
|
||||
return success(receiptService.getReceiptPage(pageReqVO));
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt;
|
||||
|
||||
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 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
|
||||
@EqualsAndHashCode()
|
||||
@ToString(callSuper = true)
|
||||
public class BpmOAReceiptCreateReqVO {
|
||||
|
||||
@Schema(description = "客户ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "客户ID不能为空")
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "合同ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "合同ID不能为空")
|
||||
private Long contractId;
|
||||
|
||||
@Schema(description = "回款日期", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate returnTime;
|
||||
|
||||
@Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "回款金额不能为空")
|
||||
private BigDecimal money;
|
||||
|
||||
@Schema(description = "备注", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String remark;
|
||||
|
||||
@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,31 @@
|
||||
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt;
|
||||
|
||||
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 BpmOAReceiptPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "客户名称,模糊匹配")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "合同名称,模糊匹配")
|
||||
private String contractName;
|
||||
|
||||
@Schema(description = "审批结果")
|
||||
private Integer result;
|
||||
|
||||
@Schema(description = "创建人名称")
|
||||
private String createName;
|
||||
|
||||
@Schema(description = "查询模式")
|
||||
private String relation;
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt;
|
||||
|
||||
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 lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author 符溶馨
|
||||
*/
|
||||
@Schema(description = "管理后台 - 退款申请 请求Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class BpmOAReceiptRespVO extends BpmOABaseRespVO {
|
||||
|
||||
@Schema(description = "客户ID")
|
||||
private Long customerId;
|
||||
|
||||
@Schema(description = "客户名称")
|
||||
private String customerName;
|
||||
|
||||
@Schema(description = "合同ID")
|
||||
private Long contractId;
|
||||
|
||||
@Schema(description = "合同编号")
|
||||
private String contractNo;
|
||||
|
||||
@Schema(description = "合同名称")
|
||||
private String contractName;
|
||||
|
||||
@Schema(description = "回款日期")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
|
||||
private LocalDate returnTime;
|
||||
|
||||
@Schema(description = "回款金额")
|
||||
private BigDecimal money;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String createName;
|
||||
|
||||
@Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<UploadUserFile> fileItems;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 合同审批 请求Request VO")
|
||||
@Data
|
||||
public class ReceiptStatisticsVO {
|
||||
|
||||
@Schema(description = "用户编号")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "今日新增回款金额")
|
||||
private BigDecimal todayAddMoney;
|
||||
|
||||
@Schema(description = "昨日新增回款金额")
|
||||
private BigDecimal yesterdayAddMoney;
|
||||
|
||||
@Schema(description = "较昨日百分比 | 金额")
|
||||
private BigDecimal moneyPercentage;
|
||||
|
||||
@Schema(description = "回款总金额")
|
||||
private BigDecimal money;
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package cn.iocoder.yudao.module.bpm.dal.dataobject.oa;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
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;
|
||||
|
||||
/**
|
||||
* OA 回款申请 DO
|
||||
*
|
||||
* @author 符溶馨
|
||||
*/
|
||||
@TableName(value ="bpm_oa_receipt", autoResultMap = true)
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BpmOAReceiptDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 出差表单主键
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 申请人的用户编号
|
||||
* 关联 AdminUserDO 的 id 属性
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 客户ID
|
||||
*/
|
||||
private Long customerId;
|
||||
|
||||
/**
|
||||
* 合同ID
|
||||
*/
|
||||
private Long contractId;
|
||||
|
||||
/**
|
||||
* 回款日期
|
||||
*/
|
||||
private LocalDate returnTime;
|
||||
|
||||
/**
|
||||
* 回款金额
|
||||
*/
|
||||
private BigDecimal money;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 结果
|
||||
* 枚举 {@link BpmProcessInstanceResultEnum}
|
||||
* 考虑到简单,所以直接复用了 BpmProcessInstanceResultEnum 枚举,也可以自己定义一个枚举哈
|
||||
*/
|
||||
private Integer result;
|
||||
|
||||
/**
|
||||
* 对应的流程编号
|
||||
* 关联 ProcessInstance 的 id 属性
|
||||
*/
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 附件基本信息
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<UploadUserFile> fileItems ;
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
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.api.oa.vo.receipt.ReceiptStatisticsDTO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptPageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.ReceiptStatisticsVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAContractDO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReceiptDO;
|
||||
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
|
||||
public interface BpmOAReceiptMapper extends BaseMapperX<BpmOAReceiptDO> {
|
||||
default PageResult<BpmOAReceiptRespVO> selectReceiptPage(BpmOAReceiptPageReqVO pageReqVO, Long userId) {
|
||||
|
||||
MPJLambdaWrapperX<BpmOAReceiptDO> query = new MPJLambdaWrapperX<>();
|
||||
query.selectAll(BpmOAReceiptDO.class);
|
||||
query.selectAs(BpmOAContractDO::getContractName, BpmOAReceiptRespVO::getContractName);
|
||||
query.selectAs(BpmOAContractDO::getCustomerName, BpmOAReceiptRespVO::getCustomerName);
|
||||
query.selectAs(BpmOAContractDO::getContractNo, BpmOAReceiptRespVO::getContractNo);
|
||||
query.selectAs("u.nickname", BpmOAReceiptRespVO::getCreateName);
|
||||
query.leftJoin(BpmOAContractDO.class, "c", BpmOAContractDO::getId, BpmOAReceiptDO::getContractId);
|
||||
query.leftJoin("system_users u on u.id = t.creator");
|
||||
query.eqIfPresent(BpmOAReceiptDO::getResult, pageReqVO.getResult());
|
||||
query.apply(Objects.nonNull(pageReqVO.getCustomerName()), "c.customer_name LIKE CONCAT('%', {0}, '%')", pageReqVO.getCustomerName());
|
||||
query.apply(Objects.nonNull(pageReqVO.getContractName()), "c.contract_name LIKE CONCAT('%', {0}, '%')", pageReqVO.getContractName());
|
||||
query.apply(Objects.nonNull(pageReqVO.getCreateName()),"u.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(BpmOAReceiptDO::getCreateTime);
|
||||
|
||||
return selectJoinPage(pageReqVO, BpmOAReceiptRespVO.class, query);
|
||||
}
|
||||
|
||||
ReceiptStatisticsVO selectStatistics(@Param("userId") Long userId,
|
||||
@Param("relation") String relation);
|
||||
|
||||
List<ReceiptStatisticsDTO> selectReceiptStatisticsListByUserIds(@Param("userIds") List<Long> userIds,
|
||||
@Param("createTime") LocalDateTime[] createTime);
|
||||
}
|
@ -104,4 +104,11 @@ public interface BpmOAContractService {
|
||||
* @return 合同列表
|
||||
*/
|
||||
List<BpmOAContractDO> getContractList(BpmOAContractVO respVO);
|
||||
|
||||
/**
|
||||
* 获得指定客户合同列表
|
||||
* @param customerId 客户编号
|
||||
* @return 合同列表
|
||||
*/
|
||||
List<BpmOAContractDO> getListByCustomerId(Long customerId);
|
||||
}
|
||||
|
@ -325,6 +325,14 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
|
||||
.eq(BpmOAContractDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BpmOAContractDO> getListByCustomerId(Long customerId) {
|
||||
|
||||
return contractMapper.selectList(new LambdaQueryWrapperX<BpmOAContractDO>()
|
||||
.eq(BpmOAContractDO::getCustomerId, customerId)
|
||||
.eq(BpmOAContractDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult()));
|
||||
}
|
||||
|
||||
public static BigDecimal calculatePercentageChange(Object today, Object yesterday) {
|
||||
|
||||
// 转换为 BigDecimal 进行高精度计算
|
||||
|
@ -0,0 +1,79 @@
|
||||
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.receipt.BpmOAReceiptVO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptCreateReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptPageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.ReceiptStatisticsVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReceiptDO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
public interface BpmOAReceiptService {
|
||||
|
||||
/**
|
||||
* 创建回款申请
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
*/
|
||||
Long createReceipt(Long userId, @Valid BpmOAReceiptCreateReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 更新回款申请的状态
|
||||
*
|
||||
* @param id 编号
|
||||
* @param result 结果
|
||||
*/
|
||||
void updateReceiptResult(String processInstanceId, Long id, Integer result);
|
||||
|
||||
/**
|
||||
* 获得回款申请
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 退款申请
|
||||
*/
|
||||
BpmOAReceiptDO getReceipt(Long id);
|
||||
|
||||
/**
|
||||
* 获得指定的回款申请
|
||||
* @param processInstanceId 流程实例编号
|
||||
* @return 退款申请
|
||||
*/
|
||||
BpmOAReceiptDO getByProcessInstanceId(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获得回款申请分页列表
|
||||
* @param pageReqVO 分页信息
|
||||
* @return 分页列表
|
||||
*/
|
||||
PageResult<BpmOAReceiptRespVO> getReceiptPage(BpmOAReceiptPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 获得回款统计信息
|
||||
* @param userId 用户编号
|
||||
* @param relation 查询类型
|
||||
* @return 回款统计信息
|
||||
*/
|
||||
ReceiptStatisticsVO getStatistics(Long userId, String relation);
|
||||
|
||||
/**
|
||||
* 获得回款列表
|
||||
* @param respVO 参数信息
|
||||
* @return 回款信息列表
|
||||
*/
|
||||
List<BpmOAReceiptDO> getReceiptList(BpmOAReceiptVO respVO);
|
||||
|
||||
/**
|
||||
* 获得指定用户回款统计信息
|
||||
* @param userIds 用户编号
|
||||
* @param createTime 创建时间
|
||||
* @return 回款统计信息
|
||||
*/
|
||||
List<ReceiptStatisticsDTO> getReceiptStatisticsListByUserIds(List<Long> userIds, LocalDateTime[] createTime);
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
package cn.iocoder.yudao.module.bpm.service.oa;
|
||||
|
||||
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.receipt.BpmOAReceiptVO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
|
||||
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.receipt.BpmOAReceiptCreateReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptPageReqVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptRespVO;
|
||||
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.ReceiptStatisticsVO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReceiptDO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAReceiptMapper;
|
||||
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 org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
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.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_RECEIPT_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* OA 回款申请 Service 实现类
|
||||
*
|
||||
* @author 符溶馨
|
||||
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOAReceiptService{
|
||||
|
||||
/**
|
||||
* OA 退款对应的流程定义 KEY
|
||||
*/
|
||||
public static final String PROCESS_KEY = "oa_receipt_2";
|
||||
|
||||
@Resource
|
||||
private BpmOAReceiptMapper receiptMapper;
|
||||
|
||||
@Resource
|
||||
private BpmProcessInstanceApi processInstanceApi;
|
||||
|
||||
@Resource
|
||||
private BpmHistoryProcessInstanceService historyProcessInstanceService;
|
||||
|
||||
@Resource
|
||||
private BpmProcessInstanceService bpmProcessInstanceService;
|
||||
|
||||
@Override
|
||||
public Long createReceipt(Long userId, BpmOAReceiptCreateReqVO createReqVO) {
|
||||
|
||||
//插入OA 回款申请
|
||||
BpmOAReceiptDO receipt = BeanUtils.toBean(createReqVO, BpmOAReceiptDO.class)
|
||||
.setUserId(userId)
|
||||
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
|
||||
receiptMapper.insert(receipt) ;
|
||||
|
||||
// 发起 BPM 流程
|
||||
Map<String, Object> processInstanceVariables = new HashMap<>();
|
||||
String processInstanceId = processInstanceApi.createProcessInstance(userId,
|
||||
new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY)
|
||||
.setVariables(processInstanceVariables).setBusinessKey(String.valueOf(receipt.getId()))).getCheckedData();
|
||||
|
||||
// 将工作流的编号,更新到 OA 回款申请单中
|
||||
receiptMapper.updateById(new BpmOAReceiptDO().setId(receipt.getId()).setProcessInstanceId(processInstanceId));
|
||||
|
||||
// 判断是否为重新发起的流程
|
||||
if (createReqVO.getProcessInstanceId() != null && createReqVO.getResult() == 3) {
|
||||
|
||||
historyProcessInstanceService.createHistoryProcessInstance(processInstanceId, createReqVO.getProcessInstanceId());
|
||||
}
|
||||
|
||||
List<UploadUserFile> fileItems = createReqVO.getFileItems() ;
|
||||
//这里的逻辑,如果fileItems不为空,且有数据,那么说明是上传了附件的,则需要更工作流文件表对应的实例Id
|
||||
if (fileItems != null && !fileItems.isEmpty()) {
|
||||
uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ;
|
||||
}
|
||||
|
||||
return receipt.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateReceiptResult(String processInstanceId, Long id, Integer result) {
|
||||
|
||||
BpmOAReceiptDO receiptDO = validateLeaveExists(id);
|
||||
//审核通过 (最后节点)
|
||||
if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) {
|
||||
|
||||
ProcessInstance instance = bpmProcessInstanceService.getProcessInstance(processInstanceId);
|
||||
|
||||
if (instance.isEnded()) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
receiptMapper.updateById(new BpmOAReceiptDO().setId(id).setResult(result));
|
||||
}
|
||||
|
||||
private BpmOAReceiptDO validateLeaveExists(Long id) {
|
||||
BpmOAReceiptDO receiptDO = receiptMapper.selectById(id);
|
||||
if (receiptDO == null) {
|
||||
throw exception(OA_RECEIPT_NOT_EXISTS);
|
||||
}
|
||||
return receiptDO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BpmOAReceiptDO getReceipt(Long id) {
|
||||
|
||||
return receiptMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BpmOAReceiptDO getByProcessInstanceId(String processInstanceId) {
|
||||
|
||||
return receiptMapper.selectOne(BpmOAReceiptDO::getProcessInstanceId, processInstanceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<BpmOAReceiptRespVO> getReceiptPage(BpmOAReceiptPageReqVO pageReqVO) {
|
||||
|
||||
return receiptMapper.selectReceiptPage(pageReqVO, getLoginUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReceiptStatisticsVO getStatistics(Long userId, String relation) {
|
||||
ReceiptStatisticsVO respVO = receiptMapper.selectStatistics(userId, relation);
|
||||
|
||||
// 设置数量、金额百分比
|
||||
respVO.setMoneyPercentage(calculatePercentageChange(respVO.getTodayAddMoney(), respVO.getYesterdayAddMoney()));
|
||||
return respVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BpmOAReceiptDO> getReceiptList(BpmOAReceiptVO respVO) {
|
||||
|
||||
return receiptMapper.selectList(new LambdaQueryWrapperX<BpmOAReceiptDO>()
|
||||
.inIfPresent(BpmOAReceiptDO::getUserId, respVO.getUserId())
|
||||
.eq(BpmOAReceiptDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult())
|
||||
.betweenIfPresent(BpmOAReceiptDO::getReturnTime, respVO.getStarTime(), respVO.getEndTime()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ReceiptStatisticsDTO> getReceiptStatisticsListByUserIds(List<Long> userIds, LocalDateTime[] createTime) {
|
||||
|
||||
return receiptMapper.selectReceiptStatisticsListByUserIds(userIds, createTime);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@ import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
@ -203,7 +204,7 @@ public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARef
|
||||
public List<BpmOARefundDO> getListByOrderNo(List<String> orderNos) {
|
||||
return refundMapper.selectList(new LambdaQueryWrapperX<BpmOARefundDO>()
|
||||
.inIfPresent(BpmOARefundDO::getOrderNo, orderNos)
|
||||
.eq(BpmOARefundDO::getStatus, 0));
|
||||
.eq(Objects.nonNull(orderNos) ,BpmOARefundDO::getStatus, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,32 @@
|
||||
package cn.iocoder.yudao.module.bpm.service.oa.listener;
|
||||
|
||||
import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEvent;
|
||||
import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventListener;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReceiptService;
|
||||
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReceiptServiceImpl;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* OA 回款单的结果的监听器实现类
|
||||
*
|
||||
* @author 符溶馨
|
||||
*/
|
||||
@Component
|
||||
public class BpmOAReceiptResultListener extends BpmProcessInstanceResultEventListener {
|
||||
|
||||
@Resource
|
||||
private BpmOAReceiptService receiptService;
|
||||
|
||||
@Override
|
||||
protected String getProcessDefinitionKey() {
|
||||
|
||||
return BpmOAReceiptServiceImpl.PROCESS_KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvent(BpmProcessInstanceResultEvent event) {
|
||||
receiptService.updateReceiptResult(event.getId(), Long.parseLong(event.getBusinessKey()), event.getResult());
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,62 @@
|
||||
<?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.BpmOAReceiptMapper">
|
||||
|
||||
<!--
|
||||
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
|
||||
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
|
||||
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
|
||||
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
|
||||
-->
|
||||
<select id="selectStatistics" resultType="cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.ReceiptStatisticsVO">
|
||||
SELECT
|
||||
COALESCE ( SUM( CASE WHEN DATE( a.create_time ) = CURDATE() THEN a.money END ), 0 ) AS todayAddMoney,
|
||||
COALESCE ( SUM( CASE WHEN DATE( a.create_time ) = CURDATE() - INTERVAL 1 DAY THEN a.money END ), 0 ) AS yesterdayAddMoney
|
||||
FROM
|
||||
bpm_oa_receipt 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="selectReceiptStatisticsListByUserIds" resultType="cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO">
|
||||
SELECT
|
||||
user_id AS userId,
|
||||
SUM(money) AS money
|
||||
FROM
|
||||
bpm_oa_receipt
|
||||
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>
|
@ -4,10 +4,13 @@ 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.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;
|
||||
|
||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||
@Tag(name = "RPC 服务 - 流程实例")
|
||||
@ -18,4 +21,9 @@ public interface CrmCustomerApi {
|
||||
@PostMapping(PREFIX + "/update")
|
||||
@Operation(summary = "更新客户信息")
|
||||
CommonResult<Boolean> updateCustomerPurchaseTotal(@RequestBody CrmCustomerDTO updateReqVO);
|
||||
|
||||
@GetMapping(PREFIX + "/get")
|
||||
@Operation(summary = "获得客户信息")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
CommonResult<CrmCustomerDTO> getCustomer(@RequestParam("id") Long id);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ 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.dal.dataobject.crmcustomer.CrmCustomerDO;
|
||||
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;
|
||||
@ -28,4 +29,10 @@ public class CrmCustomerApiImpl implements CrmCustomerApi {
|
||||
customerService.updateCustomerPurchaseTotal(BeanUtils.toBean(updateReqVO, CrmCustomerSaveReqVO.class));
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<CrmCustomerDTO> getCustomer(Long id) {
|
||||
CrmCustomerDO customerDO = customerService.getCustomer(id);
|
||||
return success(BeanUtils.toBean(customerDO, CrmCustomerDTO.class));
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontractreceivables.CrmCont
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -46,9 +45,5 @@ public interface CrmContractReceivablesMapper extends BaseMapperX<CrmContractRec
|
||||
.orderByDesc(CrmContractReceivablesDO::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_receivables 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> selectReceivablesTop();
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.crm.framework.rpc.config;
|
||||
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReceiptApi;
|
||||
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;
|
||||
@ -13,7 +14,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,
|
||||
BpmOAContractApi.class})
|
||||
@EnableFeignClients(clients = { DeptApi.class, DictDataApi.class, AdminUserApi.class, StoreProductApi.class, StoreProductAttrValueApi.class, SmsSendApi.class, MailSendApi.class, NoticeApi.class,
|
||||
BpmOAContractApi.class, BpmOAReceiptApi.class})
|
||||
public class RpcConfiguration {
|
||||
}
|
||||
|
@ -12,13 +12,14 @@ 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.BpmOAReceiptApi;
|
||||
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.receipt.BpmOAReceiptDTO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptVO;
|
||||
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.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.FlowStepEnum;
|
||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
|
||||
@ -54,16 +55,16 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
|
||||
private CrmAchievementMapper achievementMapper;
|
||||
@Resource
|
||||
private DeptApi deptApi;
|
||||
@Resource
|
||||
private CrmContractMapper contractMapper;
|
||||
@Resource
|
||||
private CrmContractReceivablesMapper contractReceivablesMapper;
|
||||
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@Resource
|
||||
private BpmOAContractApi contractApi;
|
||||
|
||||
@Resource
|
||||
private BpmOAReceiptApi receiptApi;
|
||||
|
||||
|
||||
@Override
|
||||
public void createAchievement(DeptAchieveSaveVO createReqVO) {
|
||||
@ -331,10 +332,6 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
|
||||
.setStarTime(starTime)
|
||||
.setEndTime(endTime)).getCheckedData();
|
||||
|
||||
// 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 (CollectionUtil.isNotEmpty(contractDTOS)) {
|
||||
// 累加合同金额
|
||||
@ -343,18 +340,24 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
}
|
||||
|
||||
// 获取回款信息
|
||||
List<BpmOAReceiptDTO> receiptDTOS = receiptApi.getReceiptList(new BpmOAReceiptVO()
|
||||
.setUserId(userIds)
|
||||
.setStarTime(starTime)
|
||||
.setEndTime(endTime)).getCheckedData();
|
||||
|
||||
// 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 (CollectionUtil.isNotEmpty(receiptDTOS)) {
|
||||
receivablesSuccessMoney = receiptDTOS
|
||||
.stream()
|
||||
.map(BpmOAReceiptDTO::getMoney)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
}
|
||||
|
||||
BigDecimal contractMoney = BigDecimal.ZERO;
|
||||
BigDecimal receivablesMoney = BigDecimal.ZERO;
|
||||
|
@ -10,7 +10,9 @@ 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.BpmOAReceiptApi;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.ContractStatisticsDTO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
|
||||
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;
|
||||
@ -80,6 +82,9 @@ public class AchievementServiceImpl implements AchievementService {
|
||||
@Resource
|
||||
private CrmCluesService cluesService;
|
||||
|
||||
@Resource
|
||||
private BpmOAReceiptApi receiptApi;
|
||||
|
||||
|
||||
@Override
|
||||
public PageResult<UserAchieveVO> getAchievementPage(AchievementPageReqVO pageReqVO) {
|
||||
@ -102,6 +107,10 @@ public class AchievementServiceImpl implements AchievementService {
|
||||
List<ContractStatisticsDTO> contractStatisticsDTOS = contractApi.getContractStatistics(userIds, pageReqVO.getCreateTime()).getCheckedData();
|
||||
Map<Long, ContractStatisticsDTO> contractMap = convertMap(contractStatisticsDTOS, ContractStatisticsDTO::getUserId);
|
||||
|
||||
// 获取所有用户的回款统计列表
|
||||
List<ReceiptStatisticsDTO> receiptStatisticsDTOS = receiptApi.getContractStatistics(userIds, pageReqVO.getCreateTime()).getCheckedData();
|
||||
Map<Long, ReceiptStatisticsDTO> receiptMap = convertMap(receiptStatisticsDTOS, ReceiptStatisticsDTO::getUserId);
|
||||
|
||||
// 获取所有用户的线索统计列表
|
||||
List<CrmCluesStatisticsRespVO> cluesStatisticsRespVOS = cluesService.getCluesStatisticsByUserIds(userIds, pageReqVO.getCreateTime());
|
||||
Map<Long, CrmCluesStatisticsRespVO> clusesMap = convertMap(cluesStatisticsRespVOS, CrmCluesStatisticsRespVO::getOwnerUserId);
|
||||
@ -109,38 +118,22 @@ public class AchievementServiceImpl implements AchievementService {
|
||||
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);
|
||||
// 设置合同数量
|
||||
v.setContractCount(contractMap.get(v.getId()) != null ? Long.valueOf(contractMap.get(v.getId()).getCount()) : 0L);
|
||||
// 设置合同金额
|
||||
v.setContractMoney(contractMap.get(v.getId()) != null ? contractMap.get(v.getId()).getMoney() : BigDecimal.ZERO);
|
||||
// 设置回款金额
|
||||
v.setReceivablesMoney(receiptMap.get(v.getId()) != null ? receiptMap.get(v.getId()).getMoney() : BigDecimal.ZERO);
|
||||
// 设置线索数量
|
||||
v.setCluesCount(clusesMap.get(v.getId()) != null ? Long.valueOf(clusesMap.get(v.getId()).getCount()) : 0L);
|
||||
// 设置转客数量
|
||||
v.setCluesToCustomerCount(clusesMap.get(v.getId()) != null ? Long.valueOf(clusesMap.get(v.getId()).getSuccessCount()) : 0L);
|
||||
// 设置转客比率
|
||||
if (v.getCluesCount() > 0) {
|
||||
per = NumberUtil.round(NumberUtil.div(v.getCluesToCustomerCount(), v.getCluesCount()), 2)
|
||||
.multiply(new BigDecimal("100")).toString();
|
||||
}
|
||||
|
||||
v.setCluesToCustomerPer(per);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,9 @@ 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.BpmOAReceiptApi;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.ContractStatisticsDTO;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
|
||||
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;
|
||||
@ -16,8 +18,6 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomercontacts.CrmCustome
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecord.CrmRecordDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmbusiness.CrmBusinessMapper;
|
||||
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.crmcustomercontacts.CrmCustomerContactsMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecord.CrmRecordMapper;
|
||||
@ -50,10 +50,7 @@ public class CrmIndexServiceImpl implements CrmIndexService {
|
||||
private CrmCustomerMapper customerMapper;
|
||||
@Resource
|
||||
private CrmCluesMapper crmCluesMapper;
|
||||
@Resource
|
||||
private CrmContractMapper contractMapper;
|
||||
@Resource
|
||||
private CrmContractReceivablesMapper contractReceivablesMapper;
|
||||
|
||||
@Resource
|
||||
private CrmRecordMapper crmRecordMapper;
|
||||
@Resource
|
||||
@ -66,6 +63,9 @@ public class CrmIndexServiceImpl implements CrmIndexService {
|
||||
@Resource
|
||||
private BpmOAContractApi bpmOAContractApi;
|
||||
|
||||
@Resource
|
||||
private BpmOAReceiptApi receiptApi;
|
||||
|
||||
|
||||
@Override
|
||||
public CrmIndexRespVO getIndexCount(String relation) {
|
||||
@ -112,7 +112,6 @@ public class CrmIndexServiceImpl implements CrmIndexService {
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 统计当天
|
||||
*
|
||||
@ -197,66 +196,14 @@ public class CrmIndexServiceImpl implements CrmIndexService {
|
||||
// 设置较昨日比率
|
||||
String per006 = contractStatisticsDTO.getMoneyPercentage().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();
|
||||
// }
|
||||
|
||||
// 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);
|
||||
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);
|
||||
BigDecimal count007 = BigDecimal.ZERO;
|
||||
// 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();
|
||||
// }
|
||||
|
||||
// 获取今日回款新增金额
|
||||
ReceiptStatisticsDTO receiptStatisticsDTO = receiptApi.getReceiptCount(relation).getCheckedData();
|
||||
// 设置今日新增金额
|
||||
BigDecimal count07 = receiptStatisticsDTO.getTodayAddMoney();
|
||||
// 设置昨日新增金额
|
||||
BigDecimal count007 = receiptStatisticsDTO.getYesterdayAddMoney();
|
||||
// 设置较昨日比率
|
||||
String per007 = receiptStatisticsDTO.getMoneyPercentage().toString();
|
||||
|
||||
Long count08 = customerContactsMapper.selectCount(new LambdaQueryWrapper<CrmCustomerContactsDO>()
|
||||
.in(!ids.isEmpty(), CrmCustomerContactsDO::getOwnerUserId, ids)
|
||||
|
@ -50,9 +50,29 @@
|
||||
<if test="dto.creatorName != null and dto.creatorName != ''">
|
||||
and d.nickname like concat('%', #{dto.creatorName}, '%')
|
||||
</if>
|
||||
<if test="dto.getIsCheck() != null">
|
||||
<if test="dto.getIsCheck()">
|
||||
AND FIND_IN_SET ('${dto.loginAdminId}',a.flow_admin_id)
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="selectReceivablesTop" resultType="cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.ContractVO">
|
||||
SELECT
|
||||
t.user_id AS id,
|
||||
COUNT( t.id ) AS count,
|
||||
SUM( t.money ) AS money,
|
||||
u.nickname AS nickname
|
||||
FROM
|
||||
bpm_oa_receipt t
|
||||
LEFT JOIN system_users u ON ( u.id = t.user_id )
|
||||
AND u.deleted = 0
|
||||
WHERE
|
||||
t.deleted = 0
|
||||
AND t.result = 2
|
||||
GROUP BY
|
||||
t.user_id
|
||||
ORDER BY
|
||||
money DESC
|
||||
LIMIT 10
|
||||
</select>
|
||||
</mapper>
|
||||
|
@ -280,6 +280,8 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode RENTAL_ITEMS_NUMBER_EXCESS = new ErrorCode(1_013_001_005, "归还数量不能大于剩余租借数量!");
|
||||
ErrorCode RENTAL_RECEIVED_AMOUNT_EXCESS = new ErrorCode(1_013_001_006, "收款金额不能大于押金金额!");
|
||||
ErrorCode RENTAL_REFUND_AMOUNT_EXCESS = new ErrorCode(1_013_001_007, "退款金额不能大于收款金额!");
|
||||
ErrorCode RENTAL_ITEMS_NOT_REFUND = new ErrorCode(1_013_001_008, "物品还未全部退还,不能全额退款!");
|
||||
ErrorCode RENTAL_ORDER_CUSTOMER_EXISTS = new ErrorCode(1_013_001_009, "该客户已存在租赁订单!");
|
||||
|
||||
// ========== 项目管理相关 1-014-001-001 ==========
|
||||
ErrorCode PROJECT_NOT_EXISTS = new ErrorCode(1_014_001_001, "项目不存在!");
|
||||
|
@ -111,18 +111,22 @@ public class RentalOrderController {
|
||||
.filter(item -> Objects.equals(item.getStatus(), RentalOrderDO.WAITING_FOR_REFUND))
|
||||
.map(RentalOrderRespVO::getOrderNo)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 获取订单号对应的退款申请
|
||||
Map<String, BpmOARefundDTO> refundMap = refundApi.getListByOrderNo(orderNos).getCheckedData();
|
||||
|
||||
if (CollectionUtil.isNotEmpty(refundMap)) {
|
||||
// 设置对应的订单号中的 申请退款和扣款金额
|
||||
pageResult.getList().forEach(item -> {
|
||||
if (refundMap.get(item.getOrderNo()) != null) {
|
||||
item.setApplyRefundAmount(refundMap.get(item.getOrderNo()).getRefundAmount());
|
||||
item.setApplyChargebacksAmount(refundMap.get(item.getOrderNo()).getChargebacksAmount());
|
||||
}
|
||||
});
|
||||
}
|
||||
// 设置对应的订单号中的 申请退款和扣款金额
|
||||
pageResult.getList().forEach(item -> {
|
||||
|
||||
|
||||
// 设置剩余押金
|
||||
item.setRemainingDeposit(item.getReceivedAmount().subtract(item.getRefundAmount().add(item.getChargebacksAmount())));
|
||||
|
||||
if (CollectionUtil.isNotEmpty(refundMap) && refundMap.get(item.getOrderNo()) != null) {
|
||||
item.setApplyRefundAmount(refundMap.get(item.getOrderNo()).getRefundAmount());
|
||||
item.setApplyChargebacksAmount(refundMap.get(item.getOrderNo()).getChargebacksAmount());
|
||||
}
|
||||
});
|
||||
|
||||
return success(pageResult);
|
||||
}
|
||||
|
@ -34,6 +34,9 @@ public class RentalOrderRespVO {
|
||||
@Schema(description = "押金金额")
|
||||
private BigDecimal depositAmount;
|
||||
|
||||
@Schema(description = "剩余押金")
|
||||
private BigDecimal remainingDeposit;
|
||||
|
||||
@Schema(description = "已收金额")
|
||||
private BigDecimal receivedAmount;
|
||||
|
||||
|
@ -27,8 +27,8 @@ public interface RentalOrderMapper extends BaseMapperX<RentalOrderDO> {
|
||||
MPJLambdaWrapperX<RentalOrderDO> queryWrapper = new MPJLambdaWrapperX<>();
|
||||
queryWrapper.selectAll(RentalOrderDO.class);
|
||||
queryWrapper.selectAs(RentalCustomerDO::getName, RentalOrderRespVO::getCustomerName);
|
||||
queryWrapper.selectAs("SUM( CASE WHEN deposit.type = 1 THEN deposit.amount END )", RentalOrderRespVO::getReceivedAmount);
|
||||
queryWrapper.selectAs("SUM( CASE WHEN deposit.type = 2 THEN deposit.amount END )", RentalOrderRespVO::getRefundAmount);
|
||||
queryWrapper.selectAs("COALESCE( SUM( CASE WHEN deposit.type = 1 THEN deposit.amount END ), 0 )", RentalOrderRespVO::getReceivedAmount);
|
||||
queryWrapper.selectAs("COALESCE( SUM( CASE WHEN deposit.type = 2 THEN deposit.amount END ), 0 )", RentalOrderRespVO::getRefundAmount);
|
||||
queryWrapper.selectAs(AdminUserDO::getNickname, RentalOrderRespVO::getCreatorName);
|
||||
queryWrapper.leftJoin(RentalDepositRecordDO.class, "deposit", RentalDepositRecordDO::getOrderNo, RentalOrderDO::getOrderNo);
|
||||
queryWrapper.leftJoin(AdminUserDO.class, AdminUserDO::getId, RentalOrderDO::getCreator);
|
||||
|
@ -5,6 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.bpm.api.oa.BpmOARefundApi;
|
||||
import cn.iocoder.yudao.module.infra.api.file.FileApi;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsCountReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO;
|
||||
@ -46,6 +48,12 @@ public class RentalDepositRecordServiceImpl implements RentalDepositRecordServic
|
||||
@Resource
|
||||
private BpmOARefundApi refundApi;
|
||||
|
||||
@Resource
|
||||
private RentalCustomerService customerService;
|
||||
|
||||
@Resource
|
||||
private RentalItemsRecordService itemsRecordService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createRentalDepositRecord(RentalDepositRecordSaveReqVO createReqVO) {
|
||||
@ -58,6 +66,8 @@ public class RentalDepositRecordServiceImpl implements RentalDepositRecordServic
|
||||
// 已收金额 - 退款金额
|
||||
BigDecimal amount = reqVO.getReceivedAmount().subtract(reqVO.getRefundAmount());
|
||||
|
||||
// 客户剩余押金 金额
|
||||
BigDecimal customerDepositAmount = amount;
|
||||
switch (createReqVO.getType()) {
|
||||
case 1:
|
||||
// 押金收款
|
||||
@ -65,6 +75,7 @@ public class RentalDepositRecordServiceImpl implements RentalDepositRecordServic
|
||||
if (amount.add(createReqVO.getAmount()).compareTo(depositAmount) > 0) {
|
||||
throw exception(RENTAL_RECEIVED_AMOUNT_EXCESS);
|
||||
}
|
||||
customerDepositAmount = amount.add(createReqVO.getAmount());
|
||||
break;
|
||||
case 2:
|
||||
RentalOrderDO updateOrder = new RentalOrderDO();
|
||||
@ -74,6 +85,13 @@ public class RentalDepositRecordServiceImpl implements RentalDepositRecordServic
|
||||
if (amount.compareTo(refundAmount) < 0) {
|
||||
throw exception(RENTAL_REFUND_AMOUNT_EXCESS);
|
||||
} else if (amount.compareTo(refundAmount) == 0) { // 判断当前退款金额 是否等于 实际已收的金额 - 扣款金额时
|
||||
// 获取租赁物品信息
|
||||
List<RentalItemsCountReqVO> itemList = itemsRecordService.getRentalItemsCount(createReqVO.getOrderNo(), false);
|
||||
// 判断租赁物品是否已经归还完毕
|
||||
boolean isReturned = itemList.stream().allMatch(item -> item.getNumber() == 0);
|
||||
if (!isReturned) {
|
||||
throw exception(RENTAL_ITEMS_NOT_REFUND);
|
||||
}
|
||||
// 更新订单状态为 已退款
|
||||
updateOrder.setOrderNo(createReqVO.getOrderNo());
|
||||
updateOrder.setStatus(RentalOrderDO.REFUNDED);
|
||||
@ -82,6 +100,7 @@ public class RentalDepositRecordServiceImpl implements RentalDepositRecordServic
|
||||
updateOrder.setOrderNo(createReqVO.getOrderNo());
|
||||
updateOrder.setStatus(RentalOrderDO.ON_LEASE);
|
||||
}
|
||||
customerDepositAmount = customerDepositAmount.subtract(refundAmount);
|
||||
// 同步更新 退款申请流程中的 退款状态
|
||||
refundApi.updateStatus(createReqVO.getOrderNo());
|
||||
// 同步更新 租赁订单状态
|
||||
@ -95,6 +114,16 @@ public class RentalDepositRecordServiceImpl implements RentalDepositRecordServic
|
||||
|
||||
// 更新交易凭证附件 业务编号
|
||||
UpdateBusinessFile(rentalDepositRecord);
|
||||
|
||||
// 获取客户编号
|
||||
Long customerId = rentalOrderService.getCustomerIdByOrderNo(createReqVO.getOrderNo());
|
||||
if (customerId != null) {
|
||||
// 同步更新客户剩余押金 金额
|
||||
customerService.updateRentalCustomer(new RentalCustomerSaveReqVO()
|
||||
.setId(customerId)
|
||||
.setAmount(customerDepositAmount));
|
||||
}
|
||||
|
||||
// 返回
|
||||
return rentalDepositRecord.getId();
|
||||
}
|
||||
|
@ -42,6 +42,11 @@ public class RentalItemsRecordServiceImpl implements RentalItemsRecordService{
|
||||
List<RentalItemsCountReqVO> reqVOS = getRentalItemsCount(createReqVO.getOrderNo(), true);
|
||||
Map<Integer, RentalItemsCountReqVO> countMap = convertMap(reqVOS, RentalItemsCountReqVO::getRentalItemsType);
|
||||
|
||||
// 如果数量为0 则跳过
|
||||
if (createReqVO.getNumber() == 0) {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
// 判断租借类型为归还时,检验归还数量是否大于剩余数量
|
||||
if (createReqVO.getType() == 2 && countMap.get(createReqVO.getRentalItemsType()).getNumber() < createReqVO.getNumber()) {
|
||||
throw exception(RENTAL_ITEMS_NUMBER_EXCESS);
|
||||
@ -61,6 +66,8 @@ public class RentalItemsRecordServiceImpl implements RentalItemsRecordService{
|
||||
List<RentalItemsCountReqVO> reqVOS = getRentalItemsCount(createReqVO.get(0).getOrderNo(), true);
|
||||
Map<Integer, RentalItemsCountReqVO> countMap = convertMap(reqVOS, RentalItemsCountReqVO::getRentalItemsType);
|
||||
|
||||
// 移除 数量为0的数据
|
||||
createReqVO.removeIf(vo -> vo.getNumber() == 0);
|
||||
for (RentalItemsRecordSaveReqVO vo : createReqVO) {
|
||||
|
||||
// 判断租借类型为归还时,检验归还数量是否大于剩余数量
|
||||
|
@ -74,4 +74,11 @@ public interface RentalOrderService {
|
||||
* @return 剩余押金金额
|
||||
*/
|
||||
BigDecimal getOrderAmount(String orderNo);
|
||||
|
||||
/**
|
||||
* 根据订单号获取客户id
|
||||
* @param orderNo 订单号
|
||||
* @return 客户id
|
||||
*/
|
||||
Long getCustomerIdByOrderNo(String orderNo);
|
||||
}
|
@ -27,6 +27,7 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.RENTAL_ORDER_CUSTOMER_EXISTS;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.RENTAL_ORDER_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
@ -58,26 +59,35 @@ public class RentalOrderServiceImpl implements RentalOrderService {
|
||||
|
||||
@Override
|
||||
public Long createRentalOrder(RentalOrderSaveReqVO createReqVO) {
|
||||
// 检验当前客户是否已存在订单
|
||||
Long count = rentalOrderMapper.selectCount(new LambdaQueryWrapperX<RentalOrderDO>()
|
||||
.eq(RentalOrderDO::getCustomerId, createReqVO.getCustomerId())
|
||||
.ne(RentalOrderDO::getStatus, 4));
|
||||
if (count > 0L) {
|
||||
throw exception(RENTAL_ORDER_CUSTOMER_EXISTS);
|
||||
}
|
||||
|
||||
// 新增订单DO
|
||||
RentalOrderDO rentalOrder = BeanUtils.toBean(createReqVO, RentalOrderDO.class);
|
||||
|
||||
// 获取当前日期
|
||||
String now = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||
String key = "rental_order_no_" + now;
|
||||
// 获取分布式锁
|
||||
String LOCK_KEY = "lock:rental:order:create";
|
||||
RLock lock = redissonClient.getLock(LOCK_KEY);
|
||||
try {
|
||||
lock.lock();
|
||||
// redis 获取当天订单号
|
||||
String no = stringRedisTemplate.opsForValue().get(now);
|
||||
String no = stringRedisTemplate.opsForValue().get(key);
|
||||
if (no != null) {
|
||||
no = "ZL" + now + String.format("%03d", Integer.parseInt(no) + 1);
|
||||
// redis 缓存订单号
|
||||
stringRedisTemplate.opsForValue().increment(now, 1);
|
||||
stringRedisTemplate.opsForValue().increment(key, 1);
|
||||
}else {
|
||||
no = "ZL" + now + String.format("%03d", 1);
|
||||
// redis 缓存订单号
|
||||
stringRedisTemplate.opsForValue().set(now, "1", 1, TimeUnit.DAYS);
|
||||
stringRedisTemplate.opsForValue().set(key, "1", 1, TimeUnit.DAYS);
|
||||
}
|
||||
// 设置订单编号
|
||||
rentalOrder.setOrderNo(no);
|
||||
@ -164,4 +174,13 @@ public class RentalOrderServiceImpl implements RentalOrderService {
|
||||
|
||||
return rentalOrderMapper.selectOrderAmount(orderNo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getCustomerIdByOrderNo(String orderNo) {
|
||||
RentalOrderDO orderDO = rentalOrderMapper.selectOne(RentalOrderDO::getOrderNo, orderNo);
|
||||
if (orderDO != null) {
|
||||
return orderDO.getCustomerId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user