用户在农贸市场创建卖出订单时,系统会冻结相应的物品。但是当用户取消挂单时,系统只是将订单状态改为取消,没有解冻之前冻结的物品,导致用户物品被永久冻结。
MexOrderLogic::cancelOrder方法只更新订单状态,没有处理解冻逻辑在app/Module/Mex/Logic/MexOrderLogic.php中:
unfreezeOrderItems(): 解冻卖出订单相关的物品unfreezeOrderFunds(): 解冻买入订单相关的资金在app/Module/Mex/Services/MexOrderService.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()];
}
}
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()];
}
}
创建了完整的测试脚本app/Module/Mex/Tests/manual_cancel_test.php
使用真实数据进行测试:
✅ 订单状态正确更新: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在事务中执行
- 添加完整的测试用例和手动测试脚本
- 通过实际测试验证功能正常工作
发现并修复了Fund模块中的参数类型错误:
Circulation::handle方法的$amount参数类型从int改为floatUser::handle方法的$amount参数类型从int改为float这些方法在Fund模块全面采用小数模式后,应该接受float类型参数,但代码中仍然声明为int,导致类型不匹配错误。
完善了买入订单的真正资金冻结功能:
创建订单时冻结资金:
createBuyOrder方法中添加freezeOrderFunds调用circulation方法实现取消订单时解冻资金:
unfreezeOrderFunds方法实现真正的资金解冻测试验证结果:
circulation方法进行资金流转FundLogic获取可用账户和冻结账户类型