30-已入账未入账详情查询接口.md 20 KB

Web端商户已入账/未入账详情查询接口文档

模块概述

本接口用于查询商户的收入明细,支持查询已入账和未入账的收益详情。可以按时间范围、收入类型进行筛选,并提供分页功能。


接口信息

已入账/未入账详情查询

接口详情

  • 接口名称: 已入账/未入账详情查询
  • 接口路径: GET /incomeManage/getPaymentDetails
  • 请求方式: GET
  • 接口描述: 查询商户的收入明细,区分已入账和未入账状态
  • 登录验证: ✅ 需要(通过 JWT token 自动获取店铺ID)
  • 数据来源: app端 /alienStore/storeIncomeDetailsRecord/noYetPayment 接口

业务逻辑说明

入账规则

未入账 (paymentType=0):

  • 时间范围: 当前时间-3天内的记录
  • 条件: cash_out_id IS NULL(未绑定提现记录)
  • 说明: 3天内的收入还未到账期,不能提现

已入账 (paymentType=1):

  • 时间范围: 当前时间-4天 至 当前时间-27天的记录
  • 条件: 创建时间在4~27天之间
  • 说明: 4-27天前的收入已到账期,可以提现

收入类型说明

incomeType 说明 备注
0 主页 包含优惠券(1)和团购券(2)
1 优惠券 单独查询优惠券收入
2 代金券 单独查询代金券收入
3 套餐 单独查询套餐收入
4 联名卡 单独查询联名卡收入

请求参数

Query 参数

参数名 类型 必填 默认值 说明
incomeType Integer - 收入类型, 0:主页, 1:优惠券, 2:代金券, 3:套餐, 4:联名卡
paymentType Integer - 账期类型, 0:未入账, 1:已入账
startTime String - 开始时间(格式:yyyy-MM-dd)
endTime String - 结束时间(格式:yyyy-MM-dd)
page Integer 1 页码(从1开始)
size Integer 10 每页条数

说明:

  • storeId 从 JWT token 自动获取,无需传参
  • startTimeendTime 用于自定义查询时间范围
  • 系统会根据 paymentType 自动计算默认时间范围

请求示例

示例1: 查询未入账收入

GET /incomeManage/getPaymentDetails?paymentType=0&startTime=2025-11-09&endTime=2025-11-11&page=1&size=10
Headers:
  Authorization: Bearer YOUR_JWT_TOKEN
curl -X GET "http://localhost:8080/incomeManage/getPaymentDetails?paymentType=0&startTime=2025-11-09&endTime=2025-11-11&page=1&size=10" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

示例2: 查询已入账的优惠券收入

GET /incomeManage/getPaymentDetails?incomeType=1&paymentType=1&startTime=2025-10-01&endTime=2025-11-11&page=1&size=10
Headers:
  Authorization: Bearer YOUR_JWT_TOKEN
curl -X GET "http://localhost:8080/incomeManage/getPaymentDetails?incomeType=1&paymentType=1&startTime=2025-10-01&endTime=2025-11-11&page=1&size=10" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

示例3: 查询主页(优惠券+团购券)未入账收入

GET /incomeManage/getPaymentDetails?incomeType=0&paymentType=0&startTime=2025-11-09&endTime=2025-11-11&page=1&size=10
Headers:
  Authorization: Bearer YOUR_JWT_TOKEN

响应参数

成功响应

{
    "code": 200,
    "success": true,
    "data": {
        "date": "2025-11-08 ~ 2025-11-11",
        "money": "128.50",
        "data": {
            "records": [
                {
                    "id": 1001,
                    "storeId": 103,
                    "money": 5000,
                    "moneyStr": "50.00",
                    "commission": 150,
                    "commissionStr": "1.50",
                    "incomeMoney": "51.50",
                    "incomeType": 1,
                    "couponName": "50元优惠券",
                    "cashOutId": null,
                    "date": "2025-11-10",
                    "commissionRate": "3",
                    "createdTime": "2025-11-10 14:30:00"
                },
                {
                    "id": 1002,
                    "storeId": 103,
                    "money": 7800,
                    "moneyStr": "78.00",
                    "commission": 234,
                    "commissionStr": "2.34",
                    "incomeMoney": "80.34",
                    "incomeType": 2,
                    "couponName": "100元团购券",
                    "cashOutId": null,
                    "date": "2025-11-09",
                    "commissionRate": "3",
                    "createdTime": "2025-11-09 16:20:00"
                }
            ],
            "total": 25,
            "size": 10,
            "current": 1,
            "pages": 3
        }
    },
    "msg": "操作成功"
}

响应字段说明

顶层字段

字段名 类型 说明
code Integer 状态码(200-成功)
success Boolean 是否成功
data JSONObject 返回数据
msg String 提示信息

data 字段

字段名 类型 说明
date String 账期时间范围
money String 总金额(元,保留2位小数)
data Page 分页数据

data.data 分页字段

字段名 类型 说明
records Array 收入明细列表
total Integer 总记录数
size Integer 每页条数
current Integer 当前页码
pages Integer 总页数

records 明细字段

字段名 类型 说明
id Integer 收入记录ID
storeId Integer 店铺ID
money Integer 收益金额(分)
moneyStr String 收益金额(元,格式化)
commission Integer 手续费(分)
commissionStr String 手续费(元,格式化)
incomeMoney String 售价(收益+手续费,元)
incomeType Integer 收入类型
couponName String 优惠券名称
cashOutId Integer 提现记录ID(null表示未提现)
date String 日期(yyyy-MM-dd)
commissionRate String 抽成比例
createdTime String 创建时间

失败响应

1. 未登录或 token 无效

{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "请先登录"
}

2. 参数错误

{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "查询失败:时间格式错误"
}

3. 查询异常

{
    "code": 500,
    "success": false,
    "data": null,
    "msg": "查询失败:{异常信息}"
}

业务场景

场景 1: 查询未入账收入(近3天)

业务需求: 商户想查看最近3天内产生的收入,这些收入还未到提现账期

请求:

GET /incomeManage/getPaymentDetails?paymentType=0&startTime=2025-11-08&endTime=2025-11-11&page=1&size=10
Headers:
  Authorization: Bearer VALID_TOKEN

响应:

{
    "code": 200,
    "success": true,
    "data": {
        "date": "2025-11-08 ~ 2025-11-11",
        "money": "256.80",
        "data": {
            "records": [...],
            "total": 15,
            "current": 1,
            "pages": 2
        }
    }
}

业务逻辑:

  • ✅ 查询 created_time > (当前时间 - 3天) 的记录
  • ✅ 且 cash_out_id IS NULL(未绑定提现)
  • ✅ 按创建时间倒序排列
  • ✅ 返回汇总金额和明细列表

场景 2: 查询已入账收入(4-27天前)

业务需求: 商户想查看可以提现的收入,这些收入已到账期

请求:

GET /incomeManage/getPaymentDetails?paymentType=1&startTime=2025-10-15&endTime=2025-11-07&page=1&size=10
Headers:
  Authorization: Bearer VALID_TOKEN

响应:

{
    "code": 200,
    "success": true,
    "data": {
        "date": "2025-10-15 ~ 2025-11-07",
        "money": "1580.50",
        "data": {
            "records": [...],
            "total": 42,
            "current": 1,
            "pages": 5
        }
    }
}

业务逻辑:

  • ✅ 查询 created_time BETWEEN (当前时间-27天) AND (当前时间-4天) 的记录
  • ✅ 按创建时间倒序排列
  • ✅ 这些收入可以申请提现

场景 3: 按收入类型筛选(优惠券)

业务需求: 商户只想查看优惠券产生的收入

请求:

GET /incomeManage/getPaymentDetails?incomeType=1&paymentType=0&startTime=2025-11-09&endTime=2025-11-11&page=1&size=10
Headers:
  Authorization: Bearer VALID_TOKEN

响应:

{
    "code": 200,
    "success": true,
    "data": {
        "date": "2025-11-08 ~ 2025-11-11",
        "money": "86.20",
        "data": {
            "records": [
                {
                    "incomeType": 1,
                    "couponName": "50元优惠券",
                    "moneyStr": "50.00",
                    ...
                }
            ],
            "total": 5,
            "current": 1,
            "pages": 1
        }
    }
}

场景 4: 查询主页收入(优惠券+团购券)

业务需求: 商户想查看主页展示的收入汇总(包含优惠券和团购券)

请求:

GET /incomeManage/getPaymentDetails?incomeType=0&paymentType=0&startTime=2025-11-09&endTime=2025-11-11&page=1&size=10
Headers:
  Authorization: Bearer VALID_TOKEN

响应:

{
    "code": 200,
    "success": true,
    "data": {
        "date": "2025-11-08 ~ 2025-11-11",
        "money": "328.60",
        "data": {
            "records": [
                {"incomeType": 1, "couponName": "50元优惠券", ...},
                {"incomeType": 2, "couponName": "100元团购券", ...}
            ],
            "total": 18,
            "current": 1,
            "pages": 2
        }
    }
}

业务逻辑:

  • incomeType=0 会自动查询 income_type IN (1, 2)
  • ✅ 包含优惠券和团购券的收入

数据库查询逻辑

SQL 示例(未入账)

SELECT sidr.*
FROM store_income_details_record sidr
WHERE sidr.store_id = ?
  AND sidr.cash_out_id IS NULL
  AND sidr.created_time > DATE_SUB(NOW(), INTERVAL 3 DAY)
  AND sidr.created_time BETWEEN ? AND ?
  AND sidr.income_type IN (1, 2)  -- 如果 incomeType=0
ORDER BY sidr.created_time DESC

SQL 示例(已入账)

SELECT sidr.*
FROM store_income_details_record sidr
WHERE sidr.store_id = ?
  AND sidr.created_time BETWEEN DATE_SUB(NOW(), INTERVAL 27 DAY) 
                        AND DATE_SUB(NOW(), INTERVAL 4 DAY)
  AND sidr.created_time BETWEEN ? AND ?
  AND sidr.income_type = ?
ORDER BY sidr.created_time DESC

金额计算逻辑

单条记录计算

// 1. 收益(分转元)
moneyStr = money / 100  // 例: 5000分 = 50.00元

// 2. 手续费(分转元)
commissionStr = commission / 100  // 例: 150分 = 1.50元

// 3. 售价(收益 + 手续费)
incomeMoney = (money + commission) / 100  // 例: (5000 + 150) / 100 = 51.50元

汇总计算

// 所有记录的收益总和(分转元)
totalMoney = SUM(money) / 100

前端集成示例

Vue.js 示例

export default {
    data() {
        return {
            paymentType: 0,  // 0-未入账, 1-已入账
            incomeType: null,
            startTime: '2025-11-09',
            endTime: '2025-11-11',
            page: 1,
            size: 10,
            loading: false,
            tableData: [],
            totalMoney: '0.00',
            dateRange: '',
            total: 0
        };
    },
    methods: {
        async fetchPaymentDetails() {
            this.loading = true;
            try {
                const params = {
                    paymentType: this.paymentType,
                    startTime: this.startTime,
                    endTime: this.endTime,
                    page: this.page,
                    size: this.size
                };
                
                if (this.incomeType !== null) {
                    params.incomeType = this.incomeType;
                }
                
                const response = await this.$axios.get('/incomeManage/getPaymentDetails', { params });
                
                if (response.data.success) {
                    const data = response.data.data;
                    this.tableData = data.data.records;
                    this.totalMoney = data.money;
                    this.dateRange = data.date;
                    this.total = data.data.total;
                    this.$message.success('查询成功');
                } else {
                    this.$message.error(response.data.msg);
                }
            } catch (error) {
                console.error('查询失败:', error);
                this.$message.error('查询失败,请稍后重试');
            } finally {
                this.loading = false;
            }
        },
        
        handlePageChange(page) {
            this.page = page;
            this.fetchPaymentDetails();
        },
        
        switchPaymentType(type) {
            this.paymentType = type;
            this.page = 1;
            this.fetchPaymentDetails();
        }
    },
    mounted() {
        this.fetchPaymentDetails();
    }
}

React 示例

import { useState, useEffect } from 'react';
import axios from 'axios';
import { Table, Radio, DatePicker, Select } from 'antd';

function PaymentDetails() {
    const [paymentType, setPaymentType] = useState(0);
    const [incomeType, setIncomeType] = useState(null);
    const [dateRange, setDateRange] = useState(['2025-11-09', '2025-11-11']);
    const [page, setPage] = useState(1);
    const [size, setSize] = useState(10);
    const [loading, setLoading] = useState(false);
    const [tableData, setTableData] = useState([]);
    const [totalMoney, setTotalMoney] = useState('0.00');
    const [total, setTotal] = useState(0);
    
    const fetchData = async () => {
        setLoading(true);
        try {
            const params = {
                paymentType,
                startTime: dateRange[0],
                endTime: dateRange[1],
                page,
                size
            };
            
            if (incomeType !== null) {
                params.incomeType = incomeType;
            }
            
            const response = await axios.get('/incomeManage/getPaymentDetails', { params });
            
            if (response.data.success) {
                const data = response.data.data;
                setTableData(data.data.records);
                setTotalMoney(data.money);
                setTotal(data.data.total);
            }
        } catch (error) {
            console.error('查询失败:', error);
        } finally {
            setLoading(false);
        }
    };
    
    useEffect(() => {
        fetchData();
    }, [paymentType, dateRange, page, incomeType]);
    
    return (
        <div>
            <Radio.Group value={paymentType} onChange={e => setPaymentType(e.target.value)}>
                <Radio.Button value={0}>未入账</Radio.Button>
                <Radio.Button value={1}>已入账</Radio.Button>
            </Radio.Group>
            
            <Select 
                value={incomeType} 
                onChange={setIncomeType}
                placeholder="选择收入类型"
                allowClear
            >
                <Select.Option value={0}>主页</Select.Option>
                <Select.Option value={1}>优惠券</Select.Option>
                <Select.Option value={2}>代金券</Select.Option>
                <Select.Option value={3}>套餐</Select.Option>
                <Select.Option value={4}>联名卡</Select.Option>
            </Select>
            
            <div>总金额: ¥{totalMoney}</div>
            
            <Table 
                dataSource={tableData}
                loading={loading}
                pagination={{
                    current: page,
                    pageSize: size,
                    total: total,
                    onChange: setPage
                }}
            />
        </div>
    );
}

测试用例

测试场景1: 查询未入账收入

前置条件:

  • 用户已登录
  • 店铺ID=103
  • 近3天有5笔收入记录

执行步骤:

  1. 发送请求: GET /incomeManage/getPaymentDetails?paymentType=0&startTime=2025-11-09&endTime=2025-11-11&page=1&size=10

预期结果:

  • 返回成功
  • date = "2025-11-08 ~ 2025-11-11"
  • money = 所有记录的收益总和
  • data.total = 5
  • 所有记录的 cashOutId = null

测试场景2: 查询已入账收入

前置条件:

  • 用户已登录
  • 4-27天前有10笔收入记录

执行步骤:

  1. 发送请求: GET /incomeManage/getPaymentDetails?paymentType=1&startTime=2025-10-15&endTime=2025-11-07&page=1&size=10

预期结果:

  • 返回成功
  • date = "2025-10-15 ~ 2025-11-07"
  • data.total = 10
  • 记录的创建时间在4-27天之间

测试场景3: 按收入类型筛选

前置条件:

  • 近3天有优惠券收入3笔、团购券收入2笔

执行步骤:

  1. 发送请求: GET /incomeManage/getPaymentDetails?incomeType=1&paymentType=0&startTime=2025-11-09&endTime=2025-11-11&page=1&size=10

预期结果:

  • 返回成功
  • 只返回优惠券收入(incomeType=1)
  • data.total = 3

常见问题

Q1: 未入账和已入账的时间范围是固定的吗?

答案: 是的。

  • 未入账: 固定为当前时间-3天内
  • 已入账: 固定为当前时间-4天至-27天
  • startTimeendTime 用于进一步筛选时间范围

Q2: incomeType=0 和不传 incomeType 有什么区别?

答案:

  • incomeType=0: 查询优惠券(1)和团购券(2)的收入
  • 不传: 查询所有类型的收入

Q3: money 和 incomeMoney 有什么区别?

答案:

  • money: 商户实际收益(已扣除手续费)
  • incomeMoney: 售价(收益 + 手续费)
  • 关系: incomeMoney = money + commission

Q4: 为什么有些记录有 cashOutId,有些没有?

答案:

  • 有 cashOutId: 已绑定提现记录,收益已申请提现
  • 无 cashOutId: 未绑定提现记录,收益还未提现

Q5: 分页查询时,total 是指什么?

答案: total 是符合查询条件的总记录数,不是总页数。

  • 总页数 = pages 字段
  • 当前页 = current 字段

注意事项

1. 时间范围理解

  • ⚠️ 系统自动根据 paymentType 计算默认时间范围
  • ⚠️ startTimeendTime 用于进一步筛选
  • ⚠️ 实际查询是两个时间范围的交集

2. 金额单位

  • ⚠️ 数据库存储单位:
  • ⚠️ 接口返回单位:(保留2位小数)
  • ⚠️ 转换公式:元 = 分 / 100

3. 收入类型

  • ⚠️ incomeType=0 是特殊值,表示主页(优惠券+团购券)
  • ⚠️ 其他值直接对应具体的收入类型
  • ⚠️ 不传表示查询所有类型

4. 分页注意

  • ⚠️ 使用内存分页(ListToPage)
  • ⚠️ 先查询所有符合条件的记录,再分页
  • ⚠️ 数据量大时可能影响性能

更新日志

2025-11-21 (v1.0)

新增接口:

  • GET /incomeManage/getPaymentDetails - 已入账/未入账详情查询

核心功能:

  • ✅ 区分未入账(3天内)和已入账(4-27天)
  • ✅ 支持按收入类型筛选
  • ✅ 支持自定义时间范围
  • ✅ 支持分页查询
  • ✅ 返回汇总金额和明细列表
  • ✅ 金额自动转换(分转元)
  • ✅ 自动计算售价、手续费

数据来源:

  • app端 /alienStore/storeIncomeDetailsRecord/noYetPayment 接口
  • 完全复用业务逻辑

涉及文件:

  • IncomeManageController.java - 新增 getPaymentDetails 接口
  • IncomeManageService.java - 新增方法定义
  • IncomeManageServiceImpl.java - 新增方法实现

代码质量:

  • ✅ Linter检查:无错误(1个警告可忽略)
  • ✅ 日志记录:详细
  • ✅ 异常处理:完善
  • ✅ 代码注释:完整

开发人员: ssk


文档版本: v1.0
最后更新: 2025-11-21
维护人员: ssk