仓库领用成本统计表逻辑梳理.md 11.4 KB

仓库领用成本统计表逻辑梳理

📋 需求概述

创建一个仓库领用成本统计表,按月份门店两个维度进行统计。


🔍 数据来源分析

相关数据表

1. lq_inventory_usage(仓库使用记录表)

关键字段

  • F_Id:使用记录ID(主键)
  • F_StoreId:门店ID
  • F_ProductId:产品ID
  • F_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:申请门店ID
  • F_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:门店ID
  • dm:门店名称

📊 统计逻辑设计

统计维度

  1. 月份:YYYYMM格式(如:202601)

    • 基于 lq_inventory_usage_application.F_ReceiveTime(领取时间)
    • 使用 DATE_FORMAT(a.F_ReceiveTime, '%Y%m') 进行分组
  2. 门店:门店ID(F_StoreId

    • 来源:lq_inventory_usage.F_StoreId
    • 需要关联 lq_mdxx 获取门店名称

统计指标

核心指标(必选)

  1. 领用成本金额TotalCostAmount

    • 计算方式SUM(u.F_TotalAmount)
    • 含义:该月份该门店所有已领取的仓库使用记录的总金额
    • 数据来源lq_inventory_usage.F_TotalAmount
  2. 领用次数ReceiveCount

    • 计算方式COUNT(DISTINCT a.F_UsageBatchId)
    • 含义:该月份该门店已领取的申请批次数量(按批次去重)
    • 数据来源lq_inventory_usage_application.F_UsageBatchId
  3. 领用记录数UsageRecordCount

    • 计算方式COUNT(u.F_Id)
    • 含义:该月份该门店的使用记录明细数量(不按批次去重)
    • 数据来源lq_inventory_usage.F_Id

扩展指标(可选)

  1. 平均领用金额AvgReceiveAmount

    • 计算方式TotalCostAmount / ReceiveCount
    • 含义:每次领用的平均金额
  2. 平均单笔金额AvgRecordAmount

    • 计算方式TotalCostAmount / UsageRecordCount
    • 含义:每条使用记录的平均金额
  3. 领用产品种类数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

筛选条件说明

  1. 有效性筛选

    • u.F_IsEffective = 1:使用记录有效
    • a.F_IsEffective = 1:申请记录有效
  2. 状态筛选

    • a.F_ApprovalStatus = '已通过':只统计审批通过的申请
    • a.F_IsReceived = 1:只统计已领取的记录
  3. 时间筛选

    • 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 表获取门店名称
  • 如果门店不存在,门店名称为空或显示"未知门店"

📝 参考实现

可以参考以下现有实现:

  1. LqStoreManagerSalaryService.CalculateStoreManagerSalary(第335-347行)

    • 产品物料统计逻辑
    • 基于领取时间的月份筛选
  2. LqShareStatisticsStoreService.CalculateCost(第323-334行)

    • 产品成本统计逻辑
    • 基于领取时间的时间范围筛选
  3. LqInventoryUsageService.GetStoreReceiveStatisticsAsync(第1642行开始)

    • 门店领取统计逻辑
    • 可以参考其查询结构

✅ 实现可行性

数据完整性

  • ✅ 数据表结构完整
  • ✅ 关联关系清晰(通过 F_UsageBatchId
  • ✅ 时间字段存在(F_ReceiveTime
  • ✅ 状态字段完整(F_IsReceivedF_ApprovalStatus

统计逻辑

  • ✅ 可以按月份分组(DATE_FORMAT(a.F_ReceiveTime, '%Y%m')
  • ✅ 可以按门店分组(u.F_StoreId
  • ✅ 可以计算金额总和(SUM(u.F_TotalAmount)
  • ✅ 可以统计次数(COUNT(DISTINCT a.F_UsageBatchId)

性能考虑

  • ✅ 建议在 F_ReceiveTimeF_StoreId 上建立索引
  • ✅ 建议在 F_UsageBatchId 上建立索引(关联查询)
  • ✅ 大数据量时建议使用分页查询

🎯 总结

仓库领用成本统计表可以实现,核心逻辑如下:

  1. 数据来源lq_inventory_usage + lq_inventory_usage_application + lq_mdxx
  2. 统计维度:月份(YYYYMM)+ 门店(StoreId)
  3. 时间依据F_ReceiveTime(领取时间)
  4. 筛选条件:已领取 + 审批通过 + 有效记录
  5. 核心指标:领用成本金额、领用次数、领用记录数

建议实现方案:创建一个新的接口,支持按月份、门店、时间范围等多种查询方式,返回分页数据。