|
|
@@ -0,0 +1,169 @@
|
|
|
+# 修复Mex模块取消挂单没有解冻的问题
|
|
|
+
|
|
|
+## 任务信息
|
|
|
+- **时间**: 2025年06月20日 17:59-18:06
|
|
|
+- **类型**: Bug修复
|
|
|
+- **模块**: Mex(农贸市场)
|
|
|
+- **状态**: ✅ 已完成
|
|
|
+
|
|
|
+## 问题描述
|
|
|
+用户在农贸市场创建卖出订单时,系统会冻结相应的物品。但是当用户取消挂单时,系统只是将订单状态改为取消,没有解冻之前冻结的物品,导致用户物品被永久冻结。
|
|
|
+
|
|
|
+## 问题分析
|
|
|
+1. **原始代码问题**:`MexOrderLogic::cancelOrder`方法只更新订单状态,没有处理解冻逻辑
|
|
|
+2. **影响范围**:所有取消的卖出订单都会导致物品永久冻结
|
|
|
+3. **业务影响**:用户体验差,物品无法正常使用
|
|
|
+
|
|
|
+## 解决方案
|
|
|
+
|
|
|
+### 1. 修改取消订单逻辑
|
|
|
+在`app/Module/Mex/Logic/MexOrderLogic.php`中:
|
|
|
+
|
|
|
+- 添加事务检查确保数据一致性
|
|
|
+- 根据订单类型分别处理解冻逻辑:
|
|
|
+ - 卖出订单:解冻物品
|
|
|
+ - 买入订单:解冻资金(占位实现)
|
|
|
+
|
|
|
+### 2. 新增解冻方法
|
|
|
+- `unfreezeOrderItems()`: 解冻卖出订单相关的物品
|
|
|
+- `unfreezeOrderFunds()`: 解冻买入订单相关的资金
|
|
|
+
|
|
|
+### 3. 修改服务层
|
|
|
+在`app/Module/Mex/Services/MexOrderService.php`中:
|
|
|
+- 确保取消订单操作在数据库事务中执行
|
|
|
+- 添加异常处理
|
|
|
+
|
|
|
+## 核心代码修改
|
|
|
+
|
|
|
+### MexOrderLogic::cancelOrder方法
|
|
|
+```php
|
|
|
+public static function cancelOrder(int $userId, int $orderId): array
|
|
|
+{
|
|
|
+ // 检查事务状态,确保调用者已开启事务
|
|
|
+ \UCore\Db\Helper::check_tr();
|
|
|
+
|
|
|
+ $order = MexOrder::where('id', $orderId)->where('user_id', $userId)->first();
|
|
|
+ if (!$order) {
|
|
|
+ return ['success' => false, 'message' => '订单不存在'];
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($order->status !== OrderStatus::PENDING) {
|
|
|
+ return ['success' => false, 'message' => '只能取消等待中的订单'];
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 1. 更新订单状态为取消
|
|
|
+ $order->update(['status' => OrderStatus::CANCELLED]);
|
|
|
+
|
|
|
+ // 2. 处理解冻逻辑
|
|
|
+ if ($order->order_type === OrderType::SELL) {
|
|
|
+ // 卖出订单:解冻物品
|
|
|
+ $unfreezeResult = self::unfreezeOrderItems($order);
|
|
|
+ if (!$unfreezeResult['success']) {
|
|
|
+ return ['success' => false, 'message' => '解冻物品失败:' . $unfreezeResult['message']];
|
|
|
+ }
|
|
|
+ } elseif ($order->order_type === OrderType::BUY) {
|
|
|
+ // 买入订单:解冻资金
|
|
|
+ $unfreezeResult = self::unfreezeOrderFunds($order);
|
|
|
+ if (!$unfreezeResult['success']) {
|
|
|
+ return ['success' => false, 'message' => '解冻资金失败:' . $unfreezeResult['message']];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return ['success' => true, 'message' => '订单已取消'];
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ return ['success' => false, 'message' => '取消订单失败:' . $e->getMessage()];
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 解冻物品方法
|
|
|
+```php
|
|
|
+private static function unfreezeOrderItems(MexOrder $order): array
|
|
|
+{
|
|
|
+ try {
|
|
|
+ // 查找该订单相关的冻结记录
|
|
|
+ $freezeLogs = \App\Module\GameItems\Models\ItemFreezeLog::where('source_id', $order->id)
|
|
|
+ ->where('source_type', 'mex_sell_order')
|
|
|
+ ->where('action_type', \App\Module\GameItems\Enums\FREEZE_ACTION_TYPE::FREEZE)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ if ($freezeLogs->isEmpty()) {
|
|
|
+ return ['success' => true, 'message' => '没有找到需要解冻的物品'];
|
|
|
+ }
|
|
|
+
|
|
|
+ $unfrozenCount = 0;
|
|
|
+ foreach ($freezeLogs as $freezeLog) {
|
|
|
+ try {
|
|
|
+ // 使用ItemService解冻物品
|
|
|
+ \App\Module\GameItems\Services\ItemService::unfreezeItem($freezeLog->id);
|
|
|
+ $unfrozenCount++;
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ // 记录错误但继续处理其他冻结记录
|
|
|
+ \Log::error("解冻物品失败", [
|
|
|
+ 'order_id' => $order->id,
|
|
|
+ 'freeze_log_id' => $freezeLog->id,
|
|
|
+ 'error' => $e->getMessage()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'success' => true,
|
|
|
+ 'message' => "成功解冻 {$unfrozenCount} 个冻结记录",
|
|
|
+ 'unfrozen_count' => $unfrozenCount
|
|
|
+ ];
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ return ['success' => false, 'message' => $e->getMessage()];
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## 测试验证
|
|
|
+
|
|
|
+### 1. 手动测试
|
|
|
+创建了完整的测试脚本`app/Module/Mex/Tests/manual_cancel_test.php`
|
|
|
+
|
|
|
+### 2. 实际验证
|
|
|
+使用真实数据进行测试:
|
|
|
+- 用户1001,萝卜(物品ID=2)
|
|
|
+- 创建卖出订单20个,价格10.5
|
|
|
+- 验证物品冻结状态
|
|
|
+- 取消订单
|
|
|
+- 验证物品解冻状态
|
|
|
+
|
|
|
+### 3. 测试结果
|
|
|
+✅ **订单状态正确更新**:PENDING → CANCELLED
|
|
|
+✅ **物品正确解冻**:is_frozen=1 → is_frozen=0
|
|
|
+✅ **解冻日志正确创建**:action_type=2(解冻)
|
|
|
+✅ **物品数量正确**:用户物品完全恢复可用状态
|
|
|
+
|
|
|
+## 文件变更
|
|
|
+- `app/Module/Mex/Logic/MexOrderLogic.php` - 修改取消订单逻辑
|
|
|
+- `app/Module/Mex/Services/MexOrderService.php` - 添加事务处理
|
|
|
+- `app/Module/Mex/Tests/MexOrderCancelTest.php` - 新增单元测试
|
|
|
+- `app/Module/Mex/Tests/manual_cancel_test.php` - 新增手动测试脚本
|
|
|
+
|
|
|
+## 提交信息
|
|
|
+```
|
|
|
+修复Mex模块取消挂单时没有解冻物品的问题
|
|
|
+
|
|
|
+- 修改MexOrderLogic::cancelOrder方法,添加解冻逻辑
|
|
|
+- 卖出订单取消时自动解冻相关物品
|
|
|
+- 买入订单取消时处理资金解冻(当前为占位实现)
|
|
|
+- 添加unfreezeOrderItems和unfreezeOrderFunds私有方法
|
|
|
+- 修改MexOrderService::cancelOrder在事务中执行
|
|
|
+- 添加完整的测试用例和手动测试脚本
|
|
|
+- 通过实际测试验证功能正常工作
|
|
|
+```
|
|
|
+
|
|
|
+## 注意事项
|
|
|
+1. **数据一致性**:所有操作都在事务中执行
|
|
|
+2. **错误处理**:解冻失败时记录日志但不中断整个流程
|
|
|
+3. **向后兼容**:不影响现有的订单创建和撮合逻辑
|
|
|
+4. **扩展性**:为将来的资金冻结功能预留了接口
|
|
|
+
|
|
|
+## 后续优化建议
|
|
|
+1. 考虑为买入订单实现真正的资金冻结功能
|
|
|
+2. 添加批量解冻功能以提高性能
|
|
|
+3. 考虑添加解冻失败的重试机制
|