仓库领用成本统计表逻辑梳理.md
11.4 KB
仓库领用成本统计表逻辑梳理
📋 需求概述
创建一个仓库领用成本统计表,按月份和门店两个维度进行统计。
🔍 数据来源分析
相关数据表
1. lq_inventory_usage(仓库使用记录表)
关键字段:
F_Id:使用记录ID(主键)F_StoreId:门店IDF_ProductId:产品IDF_UsageBatchId:使用批次ID(关联申请表)F_TotalAmount:合计金额(单价×数量)F_UsageQuantity:使用数量F_UnitPrice:单价F_IsEffective:是否有效(1-有效,0-无效)
说明:
- 一个申请批次可能包含多条使用记录(多个产品)
- 每条记录都有金额(
F_TotalAmount)
2. lq_inventory_usage_application(仓库使用申请表)
关键字段:
F_Id:申请编号(主键)F_UsageBatchId:使用批次ID(关联使用记录表)F_ApplicationStoreId:申请门店IDF_ApprovalStatus:审批状态(待审批/审批中/已通过/未通过/已退回)F_IsReceived:是否已领取(1-已领取,0-未领取)F_ReceiveTime:领取时间(关键时间字段)F_TotalAmount:申请总金额(该批次所有商品的总价)F_IsEffective:是否有效(1-有效,0-无效)
说明:
- 领取时间(
F_ReceiveTime)是统计的时间依据 - 只有已领取(
F_IsReceived = 1)且审批通过(F_ApprovalStatus = '已通过')的记录才计入统计
3. lq_mdxx(门店信息表)
关键字段:
F_Id:门店IDdm:门店名称
📊 统计逻辑设计
统计维度
月份:YYYYMM格式(如:202601)
- 基于
lq_inventory_usage_application.F_ReceiveTime(领取时间) - 使用
DATE_FORMAT(a.F_ReceiveTime, '%Y%m')进行分组
- 基于
门店:门店ID(
F_StoreId)- 来源:
lq_inventory_usage.F_StoreId - 需要关联
lq_mdxx获取门店名称
- 来源:
统计指标
核心指标(必选)
领用成本金额(
TotalCostAmount)- 计算方式:
SUM(u.F_TotalAmount) - 含义:该月份该门店所有已领取的仓库使用记录的总金额
- 数据来源:
lq_inventory_usage.F_TotalAmount
- 计算方式:
领用次数(
ReceiveCount)- 计算方式:
COUNT(DISTINCT a.F_UsageBatchId) - 含义:该月份该门店已领取的申请批次数量(按批次去重)
- 数据来源:
lq_inventory_usage_application.F_UsageBatchId
- 计算方式:
领用记录数(
UsageRecordCount)- 计算方式:
COUNT(u.F_Id) - 含义:该月份该门店的使用记录明细数量(不按批次去重)
- 数据来源:
lq_inventory_usage.F_Id
- 计算方式:
扩展指标(可选)
平均领用金额(
AvgReceiveAmount)- 计算方式:
TotalCostAmount / ReceiveCount - 含义:每次领用的平均金额
- 计算方式:
平均单笔金额(
AvgRecordAmount)- 计算方式:
TotalCostAmount / UsageRecordCount - 含义:每条使用记录的平均金额
- 计算方式:
领用产品种类数(
ProductVarietyCount)- 计算方式:
COUNT(DISTINCT u.F_ProductId) - 含义:该月份该门店领用的不同产品种类数量
- 计算方式:
🔧 SQL 查询逻辑
基础查询结构
SELECT
DATE_FORMAT(a.F_ReceiveTime, '%Y%m') as StatisticsMonth,
u.F_StoreId as StoreId,
store.dm as StoreName,
-- 核心指标
COALESCE(SUM(u.F_TotalAmount), 0) as TotalCostAmount,
COUNT(DISTINCT a.F_UsageBatchId) as ReceiveCount,
COUNT(u.F_Id) as UsageRecordCount,
-- 扩展指标
CASE
WHEN COUNT(DISTINCT a.F_UsageBatchId) > 0
THEN COALESCE(SUM(u.F_TotalAmount), 0) / COUNT(DISTINCT a.F_UsageBatchId)
ELSE 0
END as AvgReceiveAmount,
CASE
WHEN COUNT(u.F_Id) > 0
THEN COALESCE(SUM(u.F_TotalAmount), 0) / COUNT(u.F_Id)
ELSE 0
END as AvgRecordAmount,
COUNT(DISTINCT u.F_ProductId) as ProductVarietyCount
FROM lq_inventory_usage u
INNER JOIN lq_inventory_usage_application a ON u.F_UsageBatchId = a.F_UsageBatchId
LEFT JOIN lq_mdxx store ON u.F_StoreId = store.F_Id
WHERE u.F_IsEffective = 1
AND a.F_IsEffective = 1
AND a.F_ApprovalStatus = '已通过'
AND a.F_IsReceived = 1
AND a.F_ReceiveTime IS NOT NULL
-- 时间筛选(可选)
-- AND DATE_FORMAT(a.F_ReceiveTime, '%Y%m') = '202601'
-- 门店筛选(可选)
-- AND u.F_StoreId = '门店ID'
GROUP BY
DATE_FORMAT(a.F_ReceiveTime, '%Y%m'),
u.F_StoreId,
store.dm
ORDER BY
StatisticsMonth DESC,
TotalCostAmount DESC
筛选条件说明
有效性筛选:
u.F_IsEffective = 1:使用记录有效a.F_IsEffective = 1:申请记录有效
状态筛选:
a.F_ApprovalStatus = '已通过':只统计审批通过的申请a.F_IsReceived = 1:只统计已领取的记录
时间筛选:
a.F_ReceiveTime IS NOT NULL:领取时间不能为空- 基于
F_ReceiveTime进行月份分组和筛选
📈 统计场景
场景1:查询指定月份所有门店的统计
输入参数:
statisticsMonth:统计月份(YYYYMM格式,如:202601)
返回数据:
- 该月份所有有领用记录的门店统计数据
- 按领用成本金额降序排列
场景2:查询指定门店所有月份的统计
输入参数:
storeId:门店ID
返回数据:
- 该门店所有月份的统计数据
- 按月份降序排列
场景3:查询指定月份和门店的统计
输入参数:
statisticsMonth:统计月份(YYYYMM格式)storeId:门店ID
返回数据:
- 该月份该门店的统计数据(单条记录)
场景4:查询时间范围内的统计(按月汇总)
输入参数:
startMonth:开始月份(YYYYMM格式)endMonth:结束月份(YYYYMM格式)storeIds:门店ID列表(可选)
返回数据:
- 时间范围内所有月份的统计数据
- 可按门店筛选
🎯 接口实现
接口信息
接口路径:POST /api/Extend/LqInventoryUsage/get-store-receive-cost-statistics
请求参数:
{
"statisticsMonth": "202601", // 可选,YYYYMM格式(优先使用)
"startMonth": "202601", // 可选,开始月份(YYYYMM,与endMonth配合使用)
"endMonth": "202612", // 可选,结束月份(YYYYMM,与startMonth配合使用)
"storeId": "门店ID", // 可选,单个门店查询
"storeIds": ["门店ID1", "门店ID2"], // 可选,多个门店查询
"warehouse": "仓库名称", // 可选,筛选特定仓库
"currentPage": 1, // 可选,分页参数,默认1
"pageSize": 20, // 可选,分页参数,默认20
"sidx": "StatisticsMonth", // 可选,排序字段
"sort": "desc" // 可选,排序方式(asc/desc)
}
返回结构:
{
"code": 200,
"data": {
"list": [
{
"StatisticsMonth": "202601",
"StoreId": "门店ID",
"StoreName": "门店名称",
"ReceiveCount": 10,
"ProductVarietyCount": 8,
"AvgUnitPrice": 1543.21,
"TotalCostAmount": 12345.67,
"WarehouseCount": 2,
"UsageRecordCount": 25,
"AvgReceiveAmount": 1234.57,
"AvgRecordAmount": 493.83,
"TotalUsageQuantity": 150,
"MaxRecordAmount": 5000.00,
"MinRecordAmount": 50.00
}
],
"pagination": {
"total": 100,
"pageIndex": 1,
"pageSize": 20
}
},
"message": "查询成功"
}
返回字段说明
| 字段名 | 类型 | 说明 |
|---|---|---|
| StatisticsMonth | string | 统计月份(YYYYMM格式) |
| StoreId | string | 门店ID |
| StoreName | string | 门店名称 |
| ReceiveCount | int | 领取数量(按批次去重,即领用次数) |
| ProductVarietyCount | int | 领取品种数量(产品种类数) |
| AvgUnitPrice | decimal | 平均单价(总价/领取品种数量) |
| TotalCostAmount | decimal | 总价(领用成本金额) |
| WarehouseCount | int | 涉及仓库数量(不同仓库的数量) |
| UsageRecordCount | int | 领用记录数(明细记录数,不按批次去重) |
| AvgReceiveAmount | decimal | 平均领用金额(总价/领取数量) |
| AvgRecordAmount | decimal | 平均单笔金额(总价/领用记录数) |
| TotalUsageQuantity | int | 领用总数量(所有产品的数量总和) |
| MaxRecordAmount | decimal | 最大单笔金额 |
| MinRecordAmount | decimal | 最小单笔金额 |
⚠️ 注意事项
1. 时间字段选择
- ✅ 使用
F_ReceiveTime(领取时间):这是财务统计的正确时间点 - ❌ 不使用
F_UsageTime(使用时间):使用时间可能早于领取时间,不符合财务统计逻辑
2. 数据完整性
- 必须关联申请表,因为领取时间和状态在申请表中
- 必须筛选
F_IsReceived = 1,只统计已领取的记录 - 必须筛选
F_ApprovalStatus = '已通过',只统计审批通过的记录
3. 金额计算
- 使用
lq_inventory_usage.F_TotalAmount(每条使用记录的金额) - 不要使用
lq_inventory_usage_application.F_TotalAmount(申请总金额),因为可能存在数据不一致
4. 去重逻辑
- 领用次数:按批次ID去重(
COUNT(DISTINCT a.F_UsageBatchId)) - 领用记录数:不去重(
COUNT(u.F_Id)) - 产品种类数:按产品ID去重(
COUNT(DISTINCT u.F_ProductId))
5. 门店信息关联
- 使用
LEFT JOIN关联lq_mdxx表获取门店名称 - 如果门店不存在,门店名称为空或显示"未知门店"
📝 参考实现
可以参考以下现有实现:
LqStoreManagerSalaryService.CalculateStoreManagerSalary(第335-347行)- 产品物料统计逻辑
- 基于领取时间的月份筛选
LqShareStatisticsStoreService.CalculateCost(第323-334行)- 产品成本统计逻辑
- 基于领取时间的时间范围筛选
LqInventoryUsageService.GetStoreReceiveStatisticsAsync(第1642行开始)- 门店领取统计逻辑
- 可以参考其查询结构
✅ 实现可行性
数据完整性
- ✅ 数据表结构完整
- ✅ 关联关系清晰(通过
F_UsageBatchId) - ✅ 时间字段存在(
F_ReceiveTime) - ✅ 状态字段完整(
F_IsReceived、F_ApprovalStatus)
统计逻辑
- ✅ 可以按月份分组(
DATE_FORMAT(a.F_ReceiveTime, '%Y%m')) - ✅ 可以按门店分组(
u.F_StoreId) - ✅ 可以计算金额总和(
SUM(u.F_TotalAmount)) - ✅ 可以统计次数(
COUNT(DISTINCT a.F_UsageBatchId))
性能考虑
- ✅ 建议在
F_ReceiveTime和F_StoreId上建立索引 - ✅ 建议在
F_UsageBatchId上建立索引(关联查询) - ✅ 大数据量时建议使用分页查询
🎯 总结
仓库领用成本统计表可以实现,核心逻辑如下:
- 数据来源:
lq_inventory_usage+lq_inventory_usage_application+lq_mdxx - 统计维度:月份(YYYYMM)+ 门店(StoreId)
- 时间依据:
F_ReceiveTime(领取时间) - 筛选条件:已领取 + 审批通过 + 有效记录
- 核心指标:领用成本金额、领用次数、领用记录数
建议实现方案:创建一个新的接口,支持按月份、门店、时间范围等多种查询方式,返回分页数据。