25-团购收益查询接口.md 11 KB

团购收益查询接口

接口信息

  • 接口名称: 团购收益查询
  • 接口路径: /incomeManage/getGroupIncome
  • 请求方式: GET
  • 接口描述: 查询指定日期内的团购收益详情,包括收益金额、手续费、券数量、退款金额等统计信息,以及分页的收入明细记录列表

请求参数

Query参数

参数名 类型 必填 描述 示例
date String 查询日期(格式:yyyy-MM-dd) 2025-11-11
incomeType Integer 收入类型
0: 主页(优惠券+团购券)
1: 优惠券
2: 代金券
3: 套餐
4: 联名卡
不传则查询所有类型
0
page Integer 页码,默认1 1
size Integer 每页条数,默认10 10

Headers

参数名 类型 必填 描述
token String 用户登录凭证(JWT Token)

说明

  • 门店ID:通过LoginUserUtil从当前登录用户token中自动获取,无需前端传递
  • 收入类型特殊处理:前端展示逻辑中,当incomeType=0时,会同时查询优惠券(code=1)和团购券(code=2)
  • 账期过滤:仅查询未绑定提现记录的收入(cashOutId为空)

响应数据

响应格式

{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "storeId": 103,
    "storeName": "测试门店",
    "date": "2025-11-11",
    "commissionRate": 5,
    "incomeMoney": "100.00",
    "commissionStr": "5.00",
    "noYetPaymentMoney": "95.00",
    "couponCount": 10,
    "refundMoney": 2.50,
    "incomeDetailsRecordVoList": [
      {
        "id": 1001,
        "storeId": 103,
        "orderId": "ORDER123456",
        "money": 1000,
        "moneyStr": "10.00",
        "commission": 50,
        "incomeType": 1,
        "refundType": "false",
        "checkTime": "2025-11-11 10:30:00",
        "createdTime": "2025-11-11 10:30:00"
      },
      {
        "id": 1002,
        "storeId": 103,
        "orderId": "ORDER123457",
        "money": 2000,
        "moneyStr": "20.00",
        "commission": 100,
        "incomeType": 2,
        "refundType": "false",
        "checkTime": "2025-11-11 14:20:00",
        "createdTime": "2025-11-11 14:20:00"
      }
    ]
  }
}

响应字段说明

主要字段

字段名 类型 描述
storeId Integer 门店ID
storeName String 门店名称
date String 查询日期
commissionRate Integer 佣金率(百分比)
incomeMoney String 售价总额(收入+手续费,单位:元)
commissionStr String 手续费总额(单位:元)
noYetPaymentMoney String 实际收益金额(售价-手续费,单位:元)
couponCount Integer 券数量(正常订单数 - 退款订单数)
refundMoney BigDecimal 退款金额(单位:元)
incomeDetailsRecordVoList Array 收入明细记录列表(分页后的数据)

incomeDetailsRecordVoList数组元素字段

字段名 类型 描述
id Long 收入明细记录ID
storeId Integer 门店ID
orderId String 订单ID
money Integer 收入金额(单位:分)
moneyStr String 收入金额(单位:元,格式化后)
commission Integer 手续费(单位:分)
incomeType Integer 收入类型(1:优惠券, 2:代金券, 3:套餐, 4:联名卡)
refundType String 是否退款("true":已退款, "false":未退款)
checkTime String 核销时间
createdTime String 创建时间

响应说明

  1. 金额单位转换

    • 数据库存储单位:分(Integer)
    • 返回给前端单位:元(String,保留2位小数)
  2. 收益计算逻辑

    • 售价总额(incomeMoney) = 收入(money) + 手续费(commission)
    • 手续费总额(commissionStr) = 所有记录的commission之和
    • 实际收益(noYetPaymentMoney) = 收入(money)之和(存入时已减去手续费)
  3. 退款处理

    • 根据refundType字段分组统计
    • refundType="false": 正常订单,计入明细列表
    • refundType="true": 退款订单,只统计退款金额
  4. 券数量计算

    • 券数量 = 正常订单数量 - 退款订单数量
  5. 分页说明

    • 明细列表(incomeDetailsRecordVoList)按照分页参数返回
    • 统计数据(总金额、券数量、退款金额)基于所有符合条件的记录计算

业务逻辑

查询流程

1. 从token中获取当前登录用户的storeId
   ↓
2. 构建查询条件
   - 时间范围:指定日期的00:00:00 ~ 23:59:59
   - 账期过滤:cashOutId为空(未绑定提现记录)
   - 门店过滤:storeId匹配
   - 收入类型:根据incomeType参数筛选
   ↓
3. 查询收入明细记录(基础统计)
   - 计算总收入(allIncome)
   - 计算总手续费(commission)
   ↓
4. 查询店铺信息
   - 获取店铺名称、佣金率
   ↓
5. 查询明细记录列表(含退款标识)
   - 通过自定义Mapper查询(getIncomeList)
   - 包含退款标识字段
   ↓
6. 按退款类型分组
   - refundType="false": 正常订单
   - refundType="true": 退款订单
   ↓
7. 计算统计信息
   - 售价总额 = 收入 + 手续费
   - 券数量 = 正常订单数 - 退款订单数
   - 退款金额 = 退款订单金额之和
   ↓
8. 手动分页(ListToPage.setPage)
   - 对明细列表进行内存分页
   ↓
9. 返回结果

收入类型处理

// incomeType参数说明
if (incomeType == null) {
    // 不传:查询所有类型
    // 不添加incomeType筛选条件
} else if (incomeType == 0) {
    // 0: 主页(优惠券+团购券)
    // 查询incomeType IN (1, 2)
    wrapper.in(StoreIncomeDetailsRecord::getIncomeType, 
        CouponTypeEnum.COUPON.getCode(),      // 1
        CouponTypeEnum.GROUP_BUY.getCode());  // 2
} else {
    // 1/2/3/4: 具体类型
    // 查询incomeType = 指定值
    wrapper.eq(StoreIncomeDetailsRecord::getIncomeType, incomeType);
}

账期过滤规则

  • 仅查询未绑定提现记录的收入(cashOutId IS NULL
  • 这部分收入代表"可提现"但尚未提现的金额
  • 已提现的收入(cashOutId不为空)不在此接口查询范围

错误响应

门店不存在

{
  "code": 500,
  "msg": "查询失败:门店不存在",
  "data": null
}

未登录

{
  "code": 500,
  "msg": "查询失败:用户未登录",
  "data": null
}

日期格式错误

{
  "code": 500,
  "msg": "查询失败:日期格式错误",
  "data": null
}

调用示例

请求示例

# 查询指定日期的主页收益(优惠券+团购券)
GET /incomeManage/getGroupIncome?date=2025-11-11&incomeType=0&page=1&size=10
Headers:
  token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

# 查询指定日期的优惠券收益
GET /incomeManage/getGroupIncome?date=2025-11-11&incomeType=1&page=1&size=10
Headers:
  token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

# 查询指定日期的所有类型收益
GET /incomeManage/getGroupIncome?date=2025-11-11&page=1&size=20
Headers:
  token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

代码实现

Controller

@ApiOperation("团购收益查询")
@GetMapping("/getGroupIncome")
public R<?> getGroupIncome(
        @RequestParam("date") String date,
        @RequestParam(value = "incomeType", required = false) Integer incomeType,
        @RequestParam(value = "page", defaultValue = "1") Integer page,
        @RequestParam(value = "size", defaultValue = "10") Integer size) {
    log.info("IncomeManageController.getGroupIncome?date={}, incomeType={}, page={}, size={}",
            date, incomeType, page, size);
    try {
        Integer storeId = LoginUserUtil.getCurrentStoreId();
        Object result = incomeManageService.getGroupIncome(storeId, date, incomeType, page, size);
        return R.data(result);
    } catch (Exception e) {
        log.error("IncomeManageController.getGroupIncome ERROR: {}", e.getMessage(), e);
        return R.fail("查询失败:" + e.getMessage());
    }
}

Service关键逻辑

@Override
public Object getGroupIncome(Integer storeId, String date, Integer incomeType, Integer page, Integer size) {
    // 1. 构建查询条件
    LambdaQueryWrapper<StoreIncomeDetailsRecord> wrapper = new LambdaQueryWrapper<>();
    wrapper.between(StoreIncomeDetailsRecord::getCreatedTime, date + " 00:00:00", date + " 23:59:59")
            .isNull(StoreIncomeDetailsRecord::getCashOutId)
            .eq(StoreIncomeDetailsRecord::getStoreId, storeId);
    
    // 2. 收入类型筛选
    if (null != incomeType && 0 == incomeType) {
        wrapper.in(StoreIncomeDetailsRecord::getIncomeType,
                CouponTypeEnum.COUPON.getCode(), CouponTypeEnum.GROUP_BUY.getCode());
    } else if (null != incomeType) {
        wrapper.eq(StoreIncomeDetailsRecord::getIncomeType, incomeType);
    }
    
    // 3. 查询并统计
    // ... 省略详细实现
    
    return vo;
}

注意事项

  1. 日期格式严格要求

    • 必须为yyyy-MM-dd格式
    • 例如:2025-11-11
    • 错误格式会导致SQL查询异常
  2. 收入类型说明

    • 前端展示时,incomeType=0表示"主页",实际查询优惠券+团购券
    • 建议前端根据业务需要选择合适的收入类型参数
  3. 分页机制

    • 使用内存分页(ListToPage.setPage
    • 统计数据(总金额、券数量、退款金额)基于全量数据
    • 明细列表基于分页参数返回
  4. 金额精度

    • 所有金额计算使用BigDecimal
    • 四舍五入保留2位小数(RoundingMode.HALF_UP
  5. 性能考虑

    • 单日数据量通常不大,内存分页可接受
    • 如需跨多日查询,建议在数据库层面实现分页
  6. 账期规则

    • 收入创建后3天才能提现
    • 此接口查询的是"可提现"金额
    • 已提现金额不在查询范围

相关接口


更新日志

版本 日期 说明 作者
v1.0 2025-11-19 从app端迁移到web端,使用LoginUserUtil获取storeId ssk

文档生成时间: 2025-11-19
接口版本: v1.0
维护人: AI Assistant