1、管理端现金总额查询来源和数值修正;2、新增管理端总额明细查询和导出接口;

This commit is contained in:
gaoqr
2025-09-02 15:46:43 +08:00
parent a8a9bac5d4
commit 180a18f087
13 changed files with 359 additions and 13 deletions
@@ -2,6 +2,8 @@ package com.cf.imes.module.system.controller.admin.funds.balancedetails.vo;
import com.cf.imes.framework.common.pojo.PageParam;
import com.cf.imes.module.system.validation.pay.IncomeExpenseTypeEnumValid;
import com.cf.imes.module.system.validation.pay.TradeTypeEnumValid;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -24,9 +26,11 @@ public class BalanceDetailsPageReqVO extends PageParam {
private String businessNo;
@Schema(description = "交易类型")
@TradeTypeEnumValid
private Integer tradeType;
@Schema(description = "收支类型")
@IncomeExpenseTypeEnumValid
private Integer incomeExpenseType;
@Schema(description = "创建时间", example = "[2022-07-01 ,2022-07-01]")
@@ -1,13 +1,20 @@
package com.cf.imes.module.system.controller.admin.funds.organamount;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.pojo.PageParam;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.excel.core.util.ExcelUtils;
import com.cf.imes.framework.operatelog.core.annotations.OperateLog;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.AllOrganAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganFundsStatisticsReqVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.TotalAmountDetailsPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.TotalAmountDetailsRespVO;
import com.cf.imes.module.system.service.funds.organamount.OrganAmountService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -16,9 +23,12 @@ import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static com.cf.imes.framework.common.pojo.CommonResult.success;
import static com.cf.imes.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
/**
* @author 组织资金
@@ -40,12 +50,30 @@ public class OrganAmountController {
return success(organAmountService.getOrganAmount());
}
@GetMapping("/manage")
@GetMapping("/manage/total")
@Operation(summary = "获取管理端账户现金总额")
public CommonResult<AllOrganAmountRespVO> getManageOrganAmount() {
public CommonResult<AllOrganAmountRespVO> getManageTotalAmount() {
return success(organAmountService.getOrganAmountAll());
}
@GetMapping("/manage/total/details")
@Operation(summary = "获取管理端总额明细")
public CommonResult<PageResult<TotalAmountDetailsRespVO>> getManageTotalAmountDetails(@Valid TotalAmountDetailsPageReqVO reqVO) {
return success(organAmountService.getManageTotalAmountDetails(reqVO));
}
@GetMapping("/manage/total/details/export")
@Operation(summary = "管理端总额明细导出")
@OperateLog(type = EXPORT)
public void exportManageTotalAmountDetails(@Valid TotalAmountDetailsPageReqVO reqVO,
HttpServletResponse response) throws IOException {
reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<TotalAmountDetailsRespVO> list = organAmountService.getManageTotalAmountDetails(reqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "总额明细.xls", "数据", TotalAmountDetailsRespVO.class,
BeanUtils.toBean(list, TotalAmountDetailsRespVO.class));
}
@GetMapping("/statistics/consumptionTrend")
@Operation(summary = "获取组织消费趋势")
public CommonResult<Map<String, Object>> getOrganConsumptionTrend(@Valid OrganFundsStatisticsReqVO reqVO) {
@@ -0,0 +1,32 @@
package com.cf.imes.module.system.controller.admin.funds.organamount.vo;
import com.cf.imes.framework.common.pojo.PageParam;
import com.cf.imes.module.system.validation.pay.IncomeExpenseTypeEnumValid;
import com.cf.imes.module.system.validation.pay.TradeTypeEnumValid;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.time.LocalDate;
/**
* @author Gqr
* @since 2025/9/2 14:14
*/
@Schema(description = "管理后台 - 总额明细 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class TotalAmountDetailsPageReqVO extends PageParam {
@Schema(description = "时间范围")
private LocalDate[] createTime;
@Schema(description = "交易类型")
@TradeTypeEnumValid
private Integer tradeType;
@Schema(description = "收入支出类型")
@IncomeExpenseTypeEnumValid
private Integer incomeExpenseType;
}
@@ -0,0 +1,64 @@
package com.cf.imes.module.system.controller.admin.funds.organamount.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.cf.imes.framework.excel.core.annotations.EnumFormat;
import com.cf.imes.framework.excel.core.convert.EnumConvert;
import com.cf.imes.module.system.enums.pay.IncomeExpenseTypeEnum;
import com.cf.imes.module.system.enums.pay.TradeTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* @author Gqr
* @since 2025/9/2 14:51
*/
@Schema(description = "管理后台 - 总额明细信息 Response VO")
@Data
public class TotalAmountDetailsRespVO {
@Schema(description = "流水号")
@ExcelProperty("流水号")
private String businessNo;
@Schema(description = "交易类型,0充值 1软件购买")
@ExcelProperty(value = "交易类型", converter = EnumConvert.class)
@EnumFormat(value = TradeTypeEnum.class)
private Integer tradeType;
@Schema(description = "收支类型,0收入 1支出")
@ExcelProperty(value = "收支类型", converter = EnumConvert.class)
@EnumFormat(value = IncomeExpenseTypeEnum.class)
private Integer incomeExpenseType;
@Schema(description = "充值金额")
@ExcelProperty("充值金额")
private BigDecimal rechargeAmount;
@Schema(description = "产品金额")
@ExcelProperty("产品金额")
private BigDecimal productAmount;
@Schema(description = "现金金额支付")
@ExcelProperty("现金金额支付")
private BigDecimal cashAmount;
@Schema(description = "账户现金余额")
@ExcelProperty("账户现金余额")
private BigDecimal accountCashBalance;
@Schema(description = "操作人")
@ExcelProperty("操作人")
private String operatorName;
@Schema(description = "操作组织")
@ExcelProperty("操作组织")
private String organName;
@Schema(description = "交易时间")
@ExcelProperty("交易时间")
private LocalDateTime createTime;
}
@@ -1,15 +1,16 @@
package com.cf.imes.module.system.dal.mysql.incomeandexpense;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.system.controller.admin.funds.balancedetails.vo.BalanceDetailsPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.TotalAmountDetailsPageReqVO;
import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 收支明细 Mapper
*
@@ -18,15 +19,36 @@ import java.util.List;
*/
@Mapper
public interface IncomeExpenseDetailsMapper extends BaseMapperX<IncomeExpenseDetailsDO> {
default PageResult<IncomeExpenseDetailsDO> selectDetailsPage(BalanceDetailsPageReqVO pageReqVO, List<Long> organIds) {
/**
* 获取余额明细
*
* @param pageReqVO
* @return
*/
default PageResult<IncomeExpenseDetailsDO> selectDetailsPage(BalanceDetailsPageReqVO pageReqVO) {
Long organId = pageReqVO.getOrganId();
return selectPage(pageReqVO, new LambdaQueryWrapperX<IncomeExpenseDetailsDO>()
.eqIfPresent(IncomeExpenseDetailsDO::getOrganId, pageReqVO.getOrganId())
.inIfPresent(IncomeExpenseDetailsDO::getOrganId, organIds)
.eqIfPresent(IncomeExpenseDetailsDO::getOrganId, ObjectUtil.isNotNull(organId) ? organId : SecurityFrameworkUtils.getUserOrganId())
.eq(IncomeExpenseDetailsDO::getDeleted, false)
.likeIfPresent(IncomeExpenseDetailsDO::getBusinessNo, pageReqVO.getBusinessNo())
.eqIfPresent(IncomeExpenseDetailsDO::getTradeType,pageReqVO.getTradeType())
.eqIfPresent(IncomeExpenseDetailsDO::getIncomeExpenseType,pageReqVO.getIncomeExpenseType())
.betweenIfPresent(IncomeExpenseDetailsDO::getCreateTime,pageReqVO.getCreateTime()));
.betweenIfPresent(IncomeExpenseDetailsDO::getCreateTime,pageReqVO.getCreateTime())
.orderByDesc(IncomeExpenseDetailsDO::getId));
}
/**
* 总额明细分页
* @param pageReqVO
* @return
*/
default PageResult<IncomeExpenseDetailsDO> selectTotalAmountDetailsPage(TotalAmountDetailsPageReqVO pageReqVO) {
return selectPage(pageReqVO, new LambdaQueryWrapperX<IncomeExpenseDetailsDO>()
.eq(IncomeExpenseDetailsDO::getDeleted, false)
.eqIfPresent(IncomeExpenseDetailsDO::getTradeType, pageReqVO.getTradeType())
.eqIfPresent(IncomeExpenseDetailsDO::getIncomeExpenseType, pageReqVO.getIncomeExpenseType())
.betweenIfPresent(IncomeExpenseDetailsDO::getCreateTime, pageReqVO.getCreateTime())
.orderByDesc(IncomeExpenseDetailsDO::getId));
}
}
@@ -6,6 +6,7 @@ import lombok.Getter;
/**
* 交易类型枚举
*
* @author Gqr
* @since 2025/8/12 17:45
*/
@@ -34,4 +35,24 @@ public enum TradeTypeEnum implements BaseEnum {
}
return null;
}
/**
* 是否充值
*
* @param code
* @return
*/
public static boolean isRecharge(Integer code) {
return RECHARGE.getCode().equals(code);
}
/**
* 是否产品购买
*
* @param code
* @return
*/
public static boolean isProduct(Integer code) {
return PRODUCT.getCode().equals(code);
}
}
@@ -29,7 +29,7 @@ public class IncomeExpenseServiceImpl implements IncomeExpenseService {
@Override
public PageResult<BalanceDetailsRespVO> getBalanceDetailsPage(BalanceDetailsPageReqVO pageReqVO) {
PageResult<IncomeExpenseDetailsDO> pageResult = incomeExpenseDetailsMapper.selectDetailsPage(pageReqVO,null);
PageResult<IncomeExpenseDetailsDO> pageResult = incomeExpenseDetailsMapper.selectDetailsPage(pageReqVO);
if(CollUtil.isEmpty(pageResult.getList())){
return new PageResult<>();
}
@@ -1,10 +1,14 @@
package com.cf.imes.module.system.service.funds.organamount;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.AllOrganAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganFundsStatisticsReqVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganRechargeAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.TotalAmountDetailsPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.TotalAmountDetailsRespVO;
import com.cf.imes.module.system.dal.dataobject.funds.organamount.OrganAmountDO;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.util.Map;
@@ -70,4 +74,12 @@ public interface OrganAmountService {
* @return
*/
Map<String, Object> getConsumptionTrend(OrganFundsStatisticsReqVO reqVO, boolean queryOrg);
/**
* 获取管理端总额明细
*
* @param reqVO
* @return
*/
PageResult<TotalAmountDetailsRespVO> getManageTotalAmountDetails(@Param("reqVO") TotalAmountDetailsPageReqVO reqVO);
}
@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaUpdateWrapperX;
@@ -18,6 +19,12 @@ import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganAmou
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganFundsStatisticsReqVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganRechargeAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.TotalAmountDetailsPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.TotalAmountDetailsRespVO;
import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO;
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
import com.cf.imes.module.system.dal.mysql.incomeandexpense.IncomeExpenseDetailsMapper;
import com.cf.imes.module.system.enums.pay.TradeTypeEnum;
import com.cf.imes.module.system.service.funds.invoice.InvoiceService;
import com.cf.imes.module.system.service.funds.purchase.PurchaseService;
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.OrgEarliestPurchaseProductRespVO;
@@ -60,6 +67,9 @@ public class OrganAmountServiceImpl implements OrganAmountService {
@Resource
private OrganAmountMapper organAmountMapper;
@Resource
private IncomeExpenseDetailsMapper incomeExpenseDetailsMapper;
@Resource
private OrganService organService;
@@ -207,9 +217,9 @@ public class OrganAmountServiceImpl implements OrganAmountService {
AllOrganAmountRespVO respVO = new AllOrganAmountRespVO();
// 所有账户的总额
QueryWrapper<OrganAmountDO> wrapper = new QueryWrapper<>();
wrapper.select("sum(amount) as total");
Map<String, Object> result = organAmountMapper.selectMaps(wrapper).get(0);
QueryWrapper<IncomeExpenseDetailsDO> wrapper = new QueryWrapper<>();
wrapper.select("sum(cash_amount_change) as total");
Map<String, Object> result = incomeExpenseDetailsMapper.selectMaps(wrapper).get(0);
BigDecimal allOrganAmount = (BigDecimal) result.get("total");
// 管理端查看可开票金额
InvoiceAmountRespVO invoiceAmount = invoiceService.getManageInvoiceAmount();
@@ -221,6 +231,42 @@ public class OrganAmountServiceImpl implements OrganAmountService {
}
@Override
public PageResult<TotalAmountDetailsRespVO> getManageTotalAmountDetails(TotalAmountDetailsPageReqVO reqVO) {
PageResult<IncomeExpenseDetailsDO> pageResult = incomeExpenseDetailsMapper.selectTotalAmountDetailsPage(reqVO);
List<TotalAmountDetailsRespVO> resultList = new ArrayList<>();
List<IncomeExpenseDetailsDO> list = pageResult.getList();
for (IncomeExpenseDetailsDO detailsDO : list) {
TotalAmountDetailsRespVO totalAmountDetailsRespVO = new TotalAmountDetailsRespVO();
totalAmountDetailsRespVO.setBusinessNo(detailsDO.getBusinessNo());
// 根据交易类型赋值对应的金额
Integer tradeType = detailsDO.getTradeType();
totalAmountDetailsRespVO.setTradeType(tradeType);
if (TradeTypeEnum.isRecharge(tradeType)) {
totalAmountDetailsRespVO.setRechargeAmount(detailsDO.getCashAmountChange());
totalAmountDetailsRespVO.setProductAmount(BigDecimal.ZERO);
}
if (TradeTypeEnum.isProduct(tradeType)) {
totalAmountDetailsRespVO.setRechargeAmount(BigDecimal.ZERO);
totalAmountDetailsRespVO.setProductAmount(detailsDO.getCashAmountChange());
}
totalAmountDetailsRespVO.setIncomeExpenseType(detailsDO.getIncomeExpenseType());
totalAmountDetailsRespVO.setCashAmount(BigDecimal.ZERO);
totalAmountDetailsRespVO.setAccountCashBalance(detailsDO.getAmount());
totalAmountDetailsRespVO.setOperatorName(detailsDO.getCreator());
OrganizationDO organ = organService.getOrgan(detailsDO.getOrganId());
if (ObjectUtil.isNotNull(organ)) {
totalAmountDetailsRespVO.setOrganName(organ.getName());
}
totalAmountDetailsRespVO.setCreateTime(detailsDO.getCreateTime());
resultList.add(totalAmountDetailsRespVO);
}
return new PageResult<>(resultList, pageResult.getTotal());
}
@Override
public Map<String, Object> getConsumptionTrend(OrganFundsStatisticsReqVO reqVO, boolean queryOrg) {
Map<String, Object> resultMap = new HashMap<>();
@@ -0,0 +1,31 @@
package com.cf.imes.module.system.validation.pay;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 收支类型校验注解
* @author Gqr
* @since 2025/9/2 14:31
*/
@Target({
ElementType.FIELD,
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = {IncomeExpenseTypeEnumValidator.class}
)
public @interface IncomeExpenseTypeEnumValid {
String message() default "不支持的收支类型";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@@ -0,0 +1,27 @@
package com.cf.imes.module.system.validation.pay;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.module.system.enums.pay.IncomeExpenseTypeEnum;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
/**
* 收支类型校验器
*
* @author Gqr
* @since 2025/9/2 14:32
*/
public class IncomeExpenseTypeEnumValidator implements ConstraintValidator<IncomeExpenseTypeEnumValid, Integer> {
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (ObjectUtil.isNull(value)) {
return true;
}
for (IncomeExpenseTypeEnum codeEnum : IncomeExpenseTypeEnum.values()) {
if (ObjectUtil.equal(codeEnum.getCode(), value)) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,32 @@
package com.cf.imes.module.system.validation.pay;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 交易类型校验注解
*
* @author Gqr
* @since 2025/9/2 14:24
*/
@Target({
ElementType.FIELD,
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = {TradeTypeEnumValidator.class}
)
public @interface TradeTypeEnumValid {
String message() default "不支持的交易类型";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@@ -0,0 +1,27 @@
package com.cf.imes.module.system.validation.pay;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.module.system.enums.pay.TradeTypeEnum;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
/**
* 交易类型校验器
*
* @author Gqr
* @since 2025/9/2 14:25
*/
public class TradeTypeEnumValidator implements ConstraintValidator<TradeTypeEnumValid, Integer> {
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (ObjectUtil.isNull(value)) {
return true;
}
for (TradeTypeEnum codeEnum : TradeTypeEnum.values()) {
if (ObjectUtil.equal(codeEnum.getCode(), value)) {
return true;
}
}
return false;
}
}