fd65ae16
“wangming”
feat: inventory a...
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
|
# 仓库领用成本统计表逻辑梳理
## 📋 需求概述
创建一个**仓库领用成本统计表**,按**月份**和**门店**两个维度进行统计。
---
## 🔍 数据来源分析
### 相关数据表
#### 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`
#### 扩展指标(可选)
4. **平均领用金额**(`AvgReceiveAmount`)
- **计算方式**:`TotalCostAmount / ReceiveCount`
- **含义**:每次领用的平均金额
5. **平均单笔金额**(`AvgRecordAmount`)
- **计算方式**:`TotalCostAmount / UsageRecordCount`
- **含义**:每条使用记录的平均金额
6. **领用产品种类数**(`ProductVarietyCount`)
- **计算方式**:`COUNT(DISTINCT u.F_ProductId)`
- **含义**:该月份该门店领用的不同产品种类数量
---
## 🔧 SQL 查询逻辑
### 基础查询结构
```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`
**请求参数**:
```json
{
"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)
}
```
**返回结构**:
```json
{
"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_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` 上建立索引(关联查询)
- ✅ 大数据量时建议使用分页查询
---
## 🎯 总结
**仓库领用成本统计表**可以实现,核心逻辑如下:
1. **数据来源**:`lq_inventory_usage` + `lq_inventory_usage_application` + `lq_mdxx`
2. **统计维度**:月份(YYYYMM)+ 门店(StoreId)
3. **时间依据**:`F_ReceiveTime`(领取时间)
4. **筛选条件**:已领取 + 审批通过 + 有效记录
5. **核心指标**:领用成本金额、领用次数、领用记录数
**建议实现方案**:创建一个新的接口,支持按月份、门店、时间范围等多种查询方式,返回分页数据。
|