201759-修复Mex模块取消挂单没有解冻的问题.md 6.0 KB

修复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方法

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()];
    }
}

解冻物品方法

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. 考虑添加解冻失败的重试机制