Compare commits

...

5 Commits

Author SHA1 Message Date
furongxin
f0ab7b7b9d feat(bpm): 添加回款相关的 API 接口和数据对象- 新增 BpmOAReceiptApi 接口,提供回款统计和回款列表的 RPC 服务
- 添加 BpmOAReceiptDTO、BpmOAReceiptVO 和 ReceiptStatisticsDTO 数据对象
- 用于处理回款申请、回款列表获取和回款统计等功能
2024-12-20 15:39:13 +08:00
furongxin
f9b0c8cf7d feat(bpm): 添加 OA 回款申请功能
- 实现了 OA 回款申请的创建、查询、统计等功能
- 添加了回款申请相关的数据结构和接口定义
- 实现了回款申请的流程控制和状态更新- 添加了回款申请的附件上传和处理逻辑
2024-12-20 15:38:08 +08:00
furongxin
1c07abebb0 feat(bpm): 增加客户合同列表查询功能并优化采购和退款相关逻辑
- 在 BpmOAContractController 中添加了 getContractByCustomerId 方法,用于获取指定客户的合同列表
- 在 BpmOAContractService 接口中添加了 getListByCustomerId 方法
- 在 BpmOAContractServiceImpl 中实现了 getListByCustomerId 方法
- 优化了 BpmOAProcureController 中的项目编号判断逻辑
- 改进了 BpmOARefundServiceImpl 中的 getListByOrderNo 方法,增加了非空判断
- 在 BpmProcessInstanceServiceImpl 中的 transform 方法中添加了空字符串判断
2024-12-20 15:37:09 +08:00
furongxin
af22e311ec feat(crm): 集成回款功能
- 新增回款相关的 API 接口和实现类
- 在 AchievementService 和 CrmIndexService 中添加回款统计逻辑
- 修改 CrmCustomerApi,增加获取客户信息的接口- 更新 RpcConfiguration,添加 BpmOAReceiptApi 的配置
2024-12-20 15:35:57 +08:00
furongxin
be9085e3ac feat(rental): 优化押金退还逻辑和订单相关功能
- 完善押金退还逻辑,增加对未归还物品的检查- 更新客户剩余押金金额
- 优化订单列表展示,增加剩余押金字段
- 修复订单号生成逻辑
- 新增根据订单号获取客户ID的功能
2024-12-20 15:34:52 +08:00
39 changed files with 1181 additions and 140 deletions

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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, "已经存在流程标识为【{}】的流程");

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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());
}

View File

@ -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));
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 ;
}

View File

@ -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);
}

View File

@ -104,4 +104,11 @@ public interface BpmOAContractService {
* @return 合同列表
*/
List<BpmOAContractDO> getContractList(BpmOAContractVO respVO);
/**
* 获得指定客户合同列表
* @param customerId 客户编号
* @return 合同列表
*/
List<BpmOAContractDO> getListByCustomerId(Long customerId);
}

View File

@ -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 进行高精度计算

View File

@ -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);
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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());
}
}

View File

@ -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 &gt;= #{createTime[0]}
</if>
<if test="createTime[1] != null">
and create_time &lt;= #{createTime[1]}
</if>
</if>
GROUP BY user_id
</select>
</mapper>

View File

@ -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);
}

View File

@ -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));
}
}

View File

@ -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();
}

View File

@ -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 {
}

View File

@ -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;

View File

@ -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);
});
}

View File

@ -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)

View File

@ -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>

View File

@ -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, "项目不存在!");

View File

@ -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);
}

View File

@ -34,6 +34,9 @@ public class RentalOrderRespVO {
@Schema(description = "押金金额")
private BigDecimal depositAmount;
@Schema(description = "剩余押金")
private BigDecimal remainingDeposit;
@Schema(description = "已收金额")
private BigDecimal receivedAmount;

View File

@ -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);

View File

@ -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();
}

View File

@ -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) {
// 判断租借类型为归还时检验归还数量是否大于剩余数量

View File

@ -74,4 +74,11 @@ public interface RentalOrderService {
* @return 剩余押金金额
*/
BigDecimal getOrderAmount(String orderNo);
/**
* 根据订单号获取客户id
* @param orderNo 订单号
* @return 客户id
*/
Long getCustomerIdByOrderNo(String orderNo);
}

View File

@ -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;
}
}