Commit 0bf53482965e0906bbf2b20143847ccc1c33e172
1 parent
ba386929
feat: implement duplicate usage record fix in inventory service
- Added a new endpoint to fix duplicate inventory usage records by merging entries based on UsageBatchId, ProductId, and StoreId. - Implemented logic to retain the earliest record while summing quantities and amounts, marking others as invalid. - Enhanced the service to log the repair process and provide feedback on the number of processed and invalidated records.
Showing
4 changed files
with
428 additions
and
2 deletions
docs/库存使用记录-修复与测试报告.md
0 → 100644
| 1 | +# 库存使用记录 - 修复与测试报告 | |
| 2 | + | |
| 3 | +## 一、问题与修复概要 | |
| 4 | + | |
| 5 | +| 项目 | 说明 | | |
| 6 | +|------|------| | |
| 7 | +| 问题1 | 修改申请时,同一产品+门店出现多条记录 → 领用多算 | | |
| 8 | +| 修复1 | UpdateApplicationUsageRecords 按 ProductId+StoreId 合并 | | |
| 9 | +| 问题2 | 历史已有多算数据无法人工调整 | | |
| 10 | +| 修复2 | 新增 FixDuplicateUsageRecords 自动修复接口 | | |
| 11 | +| 验证点 | 作废记录不应参与领用统计 | | |
| 12 | + | |
| 13 | +--- | |
| 14 | + | |
| 15 | +## 二、代码审查结论:作废记录是否会被统计? | |
| 16 | + | |
| 17 | +### ✅ 结论:作废记录(IsEffective=0)**不会**被计入领用统计 | |
| 18 | + | |
| 19 | +所有涉及 `totalUsage`、领用数量统计的查询均包含 `IsEffective == StatusEnum.有效` 条件: | |
| 20 | + | |
| 21 | +| 文件 | 位置 | 说明 | | |
| 22 | +|------|------|------| | |
| 23 | +| LqInventoryUsageService | GetReceivedBatchIdsAsync、MarkReceivedAsync、CalculateAveragePriceFromInventoryAsync 等 | `x.IsEffective == StatusEnum.有效.GetHashCode()` | | |
| 24 | +| LqInventoryService | 入库前检查、可用库存、平均单价计算 | `x.IsEffective == StatusEnum.有效.GetHashCode()` | | |
| 25 | +| LqProductService | 产品作废检查、库存明细 | `x.IsEffective == StatusEnum.有效.GetHashCode()` | | |
| 26 | +| GetStoreReceiveCostStatistics | whereConditions | `u.F_IsEffective = 1` | | |
| 27 | +| LqBusinessUnitManagerSalaryService | 原生SQL | `WHERE u.F_IsEffective = 1` | | |
| 28 | +| LqDirectorSalaryService | 原生SQL | `WHERE u.F_IsEffective = 1` | | |
| 29 | +| LqStoreManagerSalaryService | 原生SQL | `WHERE u.F_IsEffective = 1` | | |
| 30 | + | |
| 31 | +**领用作废后可用库存会加回去**:作废使用记录后,该记录不再参与 totalUsage 统计,可用库存 = 总库存 - totalUsage 会自动增加。 | |
| 32 | + | |
| 33 | +--- | |
| 34 | + | |
| 35 | +## 三、数据库现状(MCP 查询结果) | |
| 36 | + | |
| 37 | +- 有效使用记录总数:3240 条 | |
| 38 | +- **存在重复数据**:至少 5 组同一 UsageBatchId+ProductId+StoreId 有多条有效记录,需执行修复接口 | |
| 39 | + | |
| 40 | +示例重复组: | |
| 41 | +- 批次 770197935005631749,产品 763991211127080197,门店 1649328471923847172:2条,总数量6 | |
| 42 | +- 批次 770807754649502981,产品 763992934394627333,门店 1649328471923847187:2条,总数量4 | |
| 43 | +- … | |
| 44 | + | |
| 45 | +--- | |
| 46 | + | |
| 47 | +## 四、测试清单 | |
| 48 | + | |
| 49 | +### 1. 修复接口测试 FixDuplicateUsageRecords | |
| 50 | + | |
| 51 | +```bash | |
| 52 | +# 1) 获取 Token | |
| 53 | +TOKEN=$(curl -s -X POST "http://localhost:2011/api/oauth/Login" \ | |
| 54 | + -H "Content-Type: application/x-www-form-urlencoded" \ | |
| 55 | + -d "account=admin&password=e10adc3949ba59abbe56e057f20f883e" | jq -r '.data.token') | |
| 56 | + | |
| 57 | +# 2) 执行修复 | |
| 58 | +curl -X POST "http://localhost:2011/api/Extend/LqInventoryUsage/FixDuplicateUsageRecords" \ | |
| 59 | + -H "Authorization: $TOKEN" \ | |
| 60 | + -H "Content-Type: application/json" | |
| 61 | +``` | |
| 62 | + | |
| 63 | +**验证**: | |
| 64 | +- 返回 `success: true`,`duplicateGroups`、`invalidatedCount` 合理 | |
| 65 | +- 查库:同一 UsageBatchId+ProductId+StoreId 仅剩 1 条有效记录 | |
| 66 | +- 查库:被合并的重复记录 `F_IsEffective = 0` | |
| 67 | + | |
| 68 | +### 2. 修改申请防重复测试 | |
| 69 | + | |
| 70 | +1. 新建申请,同一产品+门店添加两条(或修改时故意提交重复) | |
| 71 | +2. 调用 `UpdateApplicationUsageRecords` 提交 | |
| 72 | +3. 查库:该批次下同一产品+门店应只有 1 条有效记录,数量为合并值 | |
| 73 | + | |
| 74 | +### 3. 作废后不计入统计测试 | |
| 75 | + | |
| 76 | +1. 记录某产品当前可用库存 A | |
| 77 | +2. 新建申请并领用该产品若干数量,记领用后可用库存 B | |
| 78 | +3. 作废该领用记录 | |
| 79 | +4. 再次查询可用库存,应恢复为 A(或接近 A,若存在其他领用) | |
| 80 | + | |
| 81 | +### 4. 领用统计接口一致性测试 | |
| 82 | + | |
| 83 | +- 调用 GetStoreReceiveStatistics、GetStoreReceiveCostStatistics | |
| 84 | +- 与数据库直接 SUM 有效记录对比,结果一致 | |
| 85 | + | |
| 86 | +--- | |
| 87 | + | |
| 88 | +## 五、执行建议 | |
| 89 | + | |
| 90 | +1. **部署后立即执行**:`POST /api/Extend/LqInventoryUsage/FixDuplicateUsageRecords` 修复历史数据 | |
| 91 | +2. **接口测试**:确保 API 已启动(localhost:2011),按上述 curl 执行 | |
| 92 | +3. **查库验证**:按 mcp-mysql-and-sql-validation 规范,修复后必须查库核对 | |
| 93 | + | |
| 94 | +--- | |
| 95 | + | |
| 96 | +## 六、实际执行结果(2025-02-13) | |
| 97 | + | |
| 98 | +### 1. 修复前数据库状态 | |
| 99 | + | |
| 100 | +- 有效使用记录:3240 条 | |
| 101 | +- 无效使用记录:838 条 | |
| 102 | +- **重复组**:5 组(同一 UsageBatchId+ProductId+StoreId 有多条有效记录) | |
| 103 | + | |
| 104 | +| 批次ID | 产品ID | 门店ID | 重复条数 | 总数量 | | |
| 105 | +|--------|--------|--------|----------|--------| | |
| 106 | +| 784301392666821893 | 763979563993662725 | 1649328471923847179 | 2 | 20 | | |
| 107 | +| 787563597701055749 | 763987810846770437 | 1649328471923847176 | 2 | 270 | | |
| 108 | +| 770197935005631749 | 763991211127080197 | 1649328471923847172 | 2 | 6 | | |
| 109 | +| 784209727247615237 | 763991302353192197 | 1649328471923847188 | 2 | 10 | | |
| 110 | +| 770807754649502981 | 763992934394627333 | 1649328471923847187 | 2 | 4 | | |
| 111 | + | |
| 112 | +### 2. 修复接口调用结果 | |
| 113 | + | |
| 114 | +```json | |
| 115 | +{ | |
| 116 | + "success": true, | |
| 117 | + "message": "修复完成,处理 5 组重复数据,作废 5 条记录", | |
| 118 | + "duplicateGroups": 5, | |
| 119 | + "invalidatedCount": 5 | |
| 120 | +} | |
| 121 | +``` | |
| 122 | + | |
| 123 | +### 3. 修复后数据库验证 | |
| 124 | + | |
| 125 | +- **重复组**:0 组 ✓(已清空) | |
| 126 | +- **有效记录**:减少 5 条(每组保留 1 条,作废 1 条) | |
| 127 | +- **无效记录**:843 条(原 838 + 新增 5) | |
| 128 | +- **合并验证**:以批次 787563597701055749 为例,保留 1 条有效(F_UsageQuantity=270, F_TotalAmount=1196.10),另 1 条已作废(F_IsEffective=-1)✓ | |
| 129 | + | |
| 130 | +### 4. 幂等性验证 | |
| 131 | + | |
| 132 | +再次调用修复接口,返回: | |
| 133 | + | |
| 134 | +```json | |
| 135 | +{ | |
| 136 | + "success": true, | |
| 137 | + "message": "未发现重复数据", | |
| 138 | + "duplicateGroups": 0, | |
| 139 | + "invalidatedCount": 0 | |
| 140 | +} | |
| 141 | +``` | |
| 142 | + | |
| 143 | +✓ 幂等性正常,重复执行不会误伤数据。 | |
| 144 | + | |
| 145 | +### 5. 结论 | |
| 146 | + | |
| 147 | +- 修复接口工作正常 | |
| 148 | +- 合并逻辑正确(数量、金额累加,保留 CreateTime 最早的一条) | |
| 149 | +- 作废记录 (F_IsEffective=-1) 不参与领用统计 | |
| 150 | +- 无需后端代理修复,当前实现正确 | ... | ... |
docs/批次784301392666821893-青春驻颜美拉乳与一次性床单-测试分析.md
0 → 100644
| 1 | +# 批次 784301392666821893 - 青春驻颜美拉乳、一次性床单 测试分析 | |
| 2 | + | |
| 3 | +## 一、客户反馈 | |
| 4 | + | |
| 5 | +「出现无效的,但是又没有返回到库存」 | |
| 6 | + | |
| 7 | +--- | |
| 8 | + | |
| 9 | +## 二、数据现状(查库结果) | |
| 10 | + | |
| 11 | +### 1. 批次 784301392666821893 相关信息 | |
| 12 | + | |
| 13 | +| 字段 | 值 | | |
| 14 | +|------|-----| | |
| 15 | +| 申请ID | 784301392687793414 | | |
| 16 | +| 审批状态 | 已通过 | | |
| 17 | +| 是否已领取 | 1(已领取) | | |
| 18 | +| 领取时间 | 2026-02-11 | | |
| 19 | + | |
| 20 | +### 2. 青春驻颜美拉乳(763983452226716933) | |
| 21 | + | |
| 22 | +| 记录ID | 数量 | 是否有效 | 创建时间 | | |
| 23 | +|--------|------|----------|----------| | |
| 24 | +| 784301392671016217 | 2 | -1(无效) | 2026-01-23 | | |
| 25 | +| 784563060160333083 | 2 | 1(有效) | 2026-01-24 | | |
| 26 | + | |
| 27 | +### 3. 一次性床单(763994300500411653) | |
| 28 | + | |
| 29 | +| 记录ID | 数量 | 是否有效 | 创建时间 | | |
| 30 | +|--------|------|----------|----------| | |
| 31 | +| 784301392671016197 | 5 | -1(无效) | 2026-01-23 | | |
| 32 | +| 784563060160333062 | 5 | 1(有效) | 2026-01-24 | | |
| 33 | + | |
| 34 | +### 4. 库存与领用统计 | |
| 35 | + | |
| 36 | +| 产品 | 总库存 | 已使用(仅有效记录) | 可用库存 | | |
| 37 | +|------|--------|----------------------|----------| | |
| 38 | +| 青春驻颜美拉乳 | 834 | 195 | **639** | | |
| 39 | +| 一次性床单 | 947 | 915 | **32** | | |
| 40 | + | |
| 41 | +--- | |
| 42 | + | |
| 43 | +## 三、数据来源分析 | |
| 44 | + | |
| 45 | +- 无效记录(2026-01-23 创建):来自**修改申请**时被作废的**旧记录** | |
| 46 | +- 有效记录(2026-01-24 创建):修改申请后插入的**新记录** | |
| 47 | + | |
| 48 | +业务流程是:用户修改申请 → 后端作废旧记录 → 插入新记录。当前有效记录与无效记录的**数量一致**(青春驻颜美拉乳均为 2,一次性床单均为 5),说明是“替换”而不是“删除后补新”。 | |
| 49 | + | |
| 50 | +--- | |
| 51 | + | |
| 52 | +## 四、库存计算逻辑 | |
| 53 | + | |
| 54 | +- 可用库存 = 总库存 - 已使用数量 | |
| 55 | +- 已使用数量 = 仅统计 `F_IsEffective = 1` 的记录 | |
| 56 | + | |
| 57 | +作废记录(`F_IsEffective = -1`)**不会**参与已使用数量统计,因此也不影响可用库存。 | |
| 58 | + | |
| 59 | +--- | |
| 60 | + | |
| 61 | +## 五、为何“无效记录没有返回到库存” | |
| 62 | + | |
| 63 | +- 有效记录 = 新记录(修改后保留的) | |
| 64 | +- 无效记录 = 旧记录(修改时被替换的) | |
| 65 | + | |
| 66 | +两份记录数量相同,因此: | |
| 67 | + | |
| 68 | +- 修改前:统计 1 条有效记录,数量 = 2(或 5) | |
| 69 | +- 修改后:仍统计 1 条有效记录,数量 = 2(或 5) | |
| 70 | +- 作废旧记录并没有减少“已使用数量”,所以可用库存不会增加,也不存在“返还到库存”。 | |
| 71 | + | |
| 72 | +这是**按设计**的行为:在“修改申请”中,旧记录作废、新记录替换,当数量未变时,可用库存不变。 | |
| 73 | + | |
| 74 | +--- | |
| 75 | + | |
| 76 | +## 六、库存逻辑验证 | |
| 77 | + | |
| 78 | +| 验证项 | 结果 | | |
| 79 | +|--------|------| | |
| 80 | +| 作废记录是否参与已使用统计 | 否,仅统计 `F_IsEffective = 1` | | |
| 81 | +| 青春驻颜美拉乳可用库存 | 834 - 195 = **639** | | |
| 82 | +| 一次性床单可用库存 | 947 - 915 = **32** | | |
| 83 | + | |
| 84 | +--- | |
| 85 | + | |
| 86 | +## 七、若客户是“手动作废”有效记录 | |
| 87 | + | |
| 88 | +若客户通过「作废使用记录」对**有效**记录(如 784563060160333083 或 784563060160333062)进行作废: | |
| 89 | + | |
| 90 | +- 作废后该记录变为 `F_IsEffective = -1` | |
| 91 | +- 已使用数量会减少 | |
| 92 | +- 可用库存应增加,即发生“返回到库存” | |
| 93 | + | |
| 94 | +若此时界面仍显示未增加,可能原因包括: | |
| 95 | + | |
| 96 | +1. 前端或报表缓存未刷新 | |
| 97 | +2. 调用接口未使用最新数据 | |
| 98 | +3. 另有统计口径或查询条件未排除无效记录 | |
| 99 | + | |
| 100 | +建议:在前端、接口和报表中统一校验「作废后可用库存是否按预期增加」。 | |
| 101 | + | |
| 102 | +--- | |
| 103 | + | |
| 104 | +## 八、结论与建议 | |
| 105 | + | |
| 106 | +1. **库存计算逻辑正确**:作废记录未计入已使用数量,可用库存计算无误。 | |
| 107 | +2. **“修改申请”场景**:旧记录作废、新记录替换且数量不变时,可用库存不会增加,属于正常逻辑。 | |
| 108 | +3. **“手动作废”场景**:作废有效记录后,可用库存理论上会增加;若未增加,需要排查前端、接口或报表的展示与缓存。 | ... | ... |
netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs
| ... | ... | @@ -1533,8 +1533,25 @@ namespace NCC.Extend |
| 1533 | 1533 | } |
| 1534 | 1534 | |
| 1535 | 1535 | // 2. 创建新的使用记录(不计算价格,价格在确认领用时计算) |
| 1536 | + // 按 ProductId+StoreId 合并,避免同一产品+门店出现多条导致领用多算(修复:修改申请后变成两个单据、多算领用数量的问题) | |
| 1537 | + var mergedItems = input.UsageItems | |
| 1538 | + .GroupBy(x => new { x.ProductId, x.StoreId }) | |
| 1539 | + .Select(g => | |
| 1540 | + { | |
| 1541 | + var first = g.First(); | |
| 1542 | + return new LqInventoryUsageItemInput | |
| 1543 | + { | |
| 1544 | + ProductId = g.Key.ProductId, | |
| 1545 | + StoreId = g.Key.StoreId, | |
| 1546 | + UsageQuantity = g.Sum(x => x.UsageQuantity), | |
| 1547 | + UsageTime = first.UsageTime, | |
| 1548 | + RelatedConsumeId = g.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.RelatedConsumeId))?.RelatedConsumeId ?? first.RelatedConsumeId | |
| 1549 | + }; | |
| 1550 | + }) | |
| 1551 | + .ToList(); | |
| 1552 | + | |
| 1536 | 1553 | var entitiesToInsert = new List<LqInventoryUsageEntity>(); |
| 1537 | - foreach (var item in input.UsageItems) | |
| 1554 | + foreach (var item in mergedItems) | |
| 1538 | 1555 | { |
| 1539 | 1556 | var usageEntity = new LqInventoryUsageEntity |
| 1540 | 1557 | { |
| ... | ... | @@ -1570,7 +1587,7 @@ namespace NCC.Extend |
| 1570 | 1587 | |
| 1571 | 1588 | // 5. 检查关联数据是否需要更新 |
| 1572 | 1589 | // 如果有关联消耗ID,检查消耗记录是否存在 |
| 1573 | - var relatedConsumeIds = input.UsageItems | |
| 1590 | + var relatedConsumeIds = mergedItems | |
| 1574 | 1591 | .Where(x => !string.IsNullOrWhiteSpace(x.RelatedConsumeId)) |
| 1575 | 1592 | .Select(x => x.RelatedConsumeId) |
| 1576 | 1593 | .Distinct() |
| ... | ... | @@ -1602,6 +1619,107 @@ namespace NCC.Extend |
| 1602 | 1619 | |
| 1603 | 1620 | #endregion |
| 1604 | 1621 | |
| 1622 | + #region 多算数据自动修复 | |
| 1623 | + | |
| 1624 | + /// <summary> | |
| 1625 | + /// 修复库存使用记录多算数据 | |
| 1626 | + /// </summary> | |
| 1627 | + /// <remarks> | |
| 1628 | + /// 修复场景:修改申请时,同一批次下同一产品+同一门店出现多条有效记录,导致领用数量多算。 | |
| 1629 | + /// 修复逻辑:按 UsageBatchId+ProductId+StoreId 合并重复记录,保留一条(取 CreateTime 最早),数量/金额累加,其余标为无效。 | |
| 1630 | + /// | |
| 1631 | + /// 调用方式:POST /api/Extend/LqInventoryUsage/FixDuplicateUsageRecords | |
| 1632 | + /// 建议部署后调用一次修复历史数据。 | |
| 1633 | + /// </remarks> | |
| 1634 | + /// <returns>修复结果(修复组数、作废条数等)</returns> | |
| 1635 | + [HttpPost("FixDuplicateUsageRecords")] | |
| 1636 | + public async Task<dynamic> FixDuplicateUsageRecordsAsync() | |
| 1637 | + { | |
| 1638 | + try | |
| 1639 | + { | |
| 1640 | + _logger.LogInformation("开始修复库存使用记录多算数据"); | |
| 1641 | + | |
| 1642 | + // 1. 查询所有有效使用记录 | |
| 1643 | + var allUsageRecords = await _db.Queryable<LqInventoryUsageEntity>() | |
| 1644 | + .Where(x => x.IsEffective == StatusEnum.有效.GetHashCode()) | |
| 1645 | + .ToListAsync(); | |
| 1646 | + | |
| 1647 | + if (allUsageRecords == null || !allUsageRecords.Any()) | |
| 1648 | + { | |
| 1649 | + return new { success = true, message = "没有有效使用记录需要处理", duplicateGroups = 0, invalidatedCount = 0 }; | |
| 1650 | + } | |
| 1651 | + | |
| 1652 | + // 2. 按 UsageBatchId + ProductId + StoreId 分组,找出有多条的组 | |
| 1653 | + var duplicateGroups = allUsageRecords | |
| 1654 | + .GroupBy(x => new { x.UsageBatchId, x.ProductId, x.StoreId }) | |
| 1655 | + .Where(g => g.Count() > 1) | |
| 1656 | + .ToList(); | |
| 1657 | + | |
| 1658 | + if (!duplicateGroups.Any()) | |
| 1659 | + { | |
| 1660 | + return new { success = true, message = "未发现重复数据", duplicateGroups = 0, invalidatedCount = 0 }; | |
| 1661 | + } | |
| 1662 | + | |
| 1663 | + var invalidatedCount = 0; | |
| 1664 | + _db.Ado.BeginTran(); | |
| 1665 | + | |
| 1666 | + try | |
| 1667 | + { | |
| 1668 | + foreach (var group in duplicateGroups) | |
| 1669 | + { | |
| 1670 | + var records = group.OrderBy(x => x.CreateTime).ToList(); | |
| 1671 | + var keepRecord = records[0]; | |
| 1672 | + var toInvalidate = records.Skip(1).ToList(); | |
| 1673 | + | |
| 1674 | + // 更新保留记录:数量、金额累加 | |
| 1675 | + keepRecord.UsageQuantity = records.Sum(x => x.UsageQuantity); | |
| 1676 | + keepRecord.TotalAmount = records.Sum(x => x.TotalAmount); | |
| 1677 | + keepRecord.UpdateUser = _userManager.UserId; | |
| 1678 | + keepRecord.UpdateTime = DateTime.Now; | |
| 1679 | + await _db.Updateable(keepRecord).ExecuteCommandAsync(); | |
| 1680 | + | |
| 1681 | + // 将重复记录标为无效 | |
| 1682 | + foreach (var record in toInvalidate) | |
| 1683 | + { | |
| 1684 | + record.IsEffective = StatusEnum.无效.GetHashCode(); | |
| 1685 | + record.UpdateUser = _userManager.UserId; | |
| 1686 | + record.UpdateTime = DateTime.Now; | |
| 1687 | + } | |
| 1688 | + await _db.Updateable(toInvalidate).ExecuteCommandAsync(); | |
| 1689 | + invalidatedCount += toInvalidate.Count; | |
| 1690 | + | |
| 1691 | + _logger.LogInformation("修复批次 {BatchId} 产品 {ProductId} 门店 {StoreId}:保留1条(数量{Qty}),作废{Count}条", | |
| 1692 | + keepRecord.UsageBatchId, keepRecord.ProductId, keepRecord.StoreId, | |
| 1693 | + keepRecord.UsageQuantity, toInvalidate.Count); | |
| 1694 | + } | |
| 1695 | + | |
| 1696 | + _db.Ado.CommitTran(); | |
| 1697 | + _logger.LogInformation("修复完成:处理 {Groups} 组重复数据,作废 {Count} 条记录", duplicateGroups.Count, invalidatedCount); | |
| 1698 | + | |
| 1699 | + return new | |
| 1700 | + { | |
| 1701 | + success = true, | |
| 1702 | + message = $"修复完成,处理 {duplicateGroups.Count} 组重复数据,作废 {invalidatedCount} 条记录", | |
| 1703 | + duplicateGroups = duplicateGroups.Count, | |
| 1704 | + invalidatedCount = invalidatedCount | |
| 1705 | + }; | |
| 1706 | + } | |
| 1707 | + catch | |
| 1708 | + { | |
| 1709 | + _db.Ado.RollbackTran(); | |
| 1710 | + throw; | |
| 1711 | + } | |
| 1712 | + } | |
| 1713 | + catch (Exception ex) | |
| 1714 | + { | |
| 1715 | + _db.Ado.RollbackTran(); | |
| 1716 | + _logger.LogError(ex, "修复库存使用记录多算数据失败"); | |
| 1717 | + throw NCCException.Oh($"修复失败:{ex.Message}"); | |
| 1718 | + } | |
| 1719 | + } | |
| 1720 | + | |
| 1721 | + #endregion | |
| 1722 | + | |
| 1605 | 1723 | #region 门店领取统计 |
| 1606 | 1724 | |
| 1607 | 1725 | /// <summary> | ... | ... |
scripts/test-inventory-usage-fix.sh
0 → 100755
| 1 | +#!/bin/bash | |
| 2 | +# 库存使用记录修复与测试脚本 | |
| 3 | +# 前置:API 需运行在 localhost:2011 | |
| 4 | + | |
| 5 | +BASE_URL="${API_BASE_URL:-http://localhost:2011}" | |
| 6 | + | |
| 7 | +echo "=== 1. 获取 Token ===" | |
| 8 | +LOGIN_RESP=$(curl -s -X POST "${BASE_URL}/api/oauth/Login" \ | |
| 9 | + -H "Content-Type: application/x-www-form-urlencoded" \ | |
| 10 | + -d "account=admin&password=e10adc3949ba59abbe56e057f20f883e") | |
| 11 | + | |
| 12 | +if command -v jq &> /dev/null; then | |
| 13 | + TOKEN=$(echo "$LOGIN_RESP" | jq -r '.data.token // empty') | |
| 14 | +else | |
| 15 | + TOKEN=$(echo "$LOGIN_RESP" | grep -o '"token":"[^"]*"' | sed 's/"token":"\(.*\)"/\1/') | |
| 16 | +fi | |
| 17 | + | |
| 18 | +if [ -z "$TOKEN" ]; then | |
| 19 | + echo "登录失败,请检查 API 是否运行: $BASE_URL" | |
| 20 | + echo "响应: $LOGIN_RESP" | |
| 21 | + exit 1 | |
| 22 | +fi | |
| 23 | + | |
| 24 | +echo "Token 获取成功" | |
| 25 | + | |
| 26 | +echo "" | |
| 27 | +echo "=== 2. 执行修复接口 FixDuplicateUsageRecords ===" | |
| 28 | +FIX_RESP=$(curl -s -X POST "${BASE_URL}/api/Extend/LqInventoryUsage/FixDuplicateUsageRecords" \ | |
| 29 | + -H "Authorization: $TOKEN" \ | |
| 30 | + -H "Content-Type: application/json") | |
| 31 | + | |
| 32 | +echo "$FIX_RESP" | |
| 33 | + | |
| 34 | +if echo "$FIX_RESP" | grep -q '"success":true'; then | |
| 35 | + echo "修复接口调用成功" | |
| 36 | +else | |
| 37 | + echo "修复接口可能失败,请检查响应" | |
| 38 | +fi | |
| 39 | + | |
| 40 | +echo "" | |
| 41 | +echo "=== 3. 验证说明 ===" | |
| 42 | +echo "请使用 MCP 或 MySQL 客户端执行以下 SQL 验证修复结果:" | |
| 43 | +echo "" | |
| 44 | +echo " -- 检查是否还有重复(应无结果)" | |
| 45 | +echo " SELECT F_UsageBatchId, F_ProductId, F_StoreId, COUNT(*) as cnt" | |
| 46 | +echo " FROM lq_inventory_usage WHERE F_IsEffective = 1" | |
| 47 | +echo " GROUP BY F_UsageBatchId, F_ProductId, F_StoreId HAVING COUNT(*) > 1;" | |
| 48 | +echo "" | |
| 49 | +echo " -- 检查作废记录数" | |
| 50 | +echo " SELECT F_IsEffective, COUNT(*) FROM lq_inventory_usage GROUP BY F_IsEffective;" | ... | ... |