Bläddra i källkod

完善Mex模块账户流转逻辑

- 新增MexAccountLogic.php处理用户与仓库间的资金和物品流转
- 完善MexOrderLogic.php中的卖出和买入订单处理逻辑
- 为MexOrder模型添加failed_reason字段支持失败原因记录
- 集成Fund模块和GameItems模块实现真实的账户流转
- 添加完整的测试用例验证账户流转功能
- 支持订单失败状态和错误处理机制
notfff 7 månader sedan
förälder
incheckning
36c986b2fd

+ 252 - 0
AiWork/2025年06月/11日2140-完善Mex模块Logic层和创建计划任务.md

@@ -0,0 +1,252 @@
+# 完善Mex模块Logic层和创建计划任务
+
+## 任务概述
+- **任务时间**:2025年06月11日 21:40
+- **任务类型**:核心功能开发
+- **涉及模块**:Mex(农贸市场交易系统)
+- **主要内容**:完善Logic层业务逻辑,创建撮合计划任务
+
+## 任务背景
+继续开发Mex模块,需要完善Logic层的其他业务逻辑类,实现完整的撮合算法和管理员操作功能,并创建计划任务来定时执行撮合。
+
+## 执行过程
+
+### 1. 完善Logic层业务逻辑(5个Logic类)
+
+#### 1.1 MexWarehouseLogic(仓库逻辑)
+- **核心功能**:库存管理、统计分析、库存操作
+- **主要方法**:
+  - getItemStock():获取商品库存信息,包含平均价格计算
+  - getItemsStock():批量获取多个商品库存
+  - checkStockSufficient():检查库存充足性
+  - getAvailableItems():获取有库存商品列表
+  - getWarehouseStats():仓库统计信息
+  - addStock()、reduceStock():库存增减操作
+- **技术特点**:使用bcmath确保精度,完整的统计分析
+
+#### 1.2 MexTransactionLogic(成交记录逻辑)
+- **核心功能**:交易记录查询、统计分析、价格趋势
+- **主要方法**:
+  - getPublicTransactions():交易大厅成交记录(过滤管理员操作)
+  - getUserTransactions():用户成交记录,包含角色识别
+  - getItemTransactionStats():商品成交统计
+  - getMarketStats():市场整体统计
+  - getLatestPrice():最新成交价格
+  - createTransaction():创建成交记录
+  - getItemPriceTrend():商品价格趋势分析
+- **技术特点**:分页查询、角色识别、趋势分析
+
+#### 1.3 MexPriceConfigLogic(价格配置逻辑)
+- **核心功能**:价格验证、配置管理、缓存机制
+- **主要方法**:
+  - getItemPriceConfig():获取商品价格配置(带缓存)
+  - validateSellPrice():验证卖出价格(≤最低价)
+  - validateBuyPrice():验证买入价格(≥最高价)
+  - validateOrderQuantity():验证订单数量(保护阈值)
+  - validateOrderParams():批量验证价格和数量
+  - getPriceSuggestion():获取价格建议
+- **技术特点**:10分钟缓存、完整的验证机制、错误码标准化
+
+#### 1.4 MexAdminLogic(管理员操作逻辑)
+- **核心功能**:物品注入/回收、账户流转、操作记录
+- **主要方法**:
+  - injectItem():物品注入(调控账户→仓库账户)
+  - recycleItem():物品回收(仓库账户→调控账户)
+  - getAdminOperations():获取管理员操作记录
+  - getAdminOperationStats():管理员操作统计
+- **技术特点**:完整的账户流转设计、事务保证、操作审计
+- **账户体系**:
+  - 仓库账户(USER_ID: 15):交易中介方
+  - 调控账户(USER_ID: 16):管理员操作专用
+
+#### 1.5 MexMatchLogic(撮合逻辑)
+- **核心功能**:三级排序撮合、整单匹配、条件检查
+- **主要方法**:
+  - executeMatch():执行撮合任务(支持指定商品或全部)
+  - executeItemMatch():执行单商品撮合
+  - executeOrderMatch():执行单订单撮合
+  - checkMatchConditions():检查撮合条件
+  - getMatchStats():撮合统计信息
+- **撮合算法核心特性**:
+  - **三级排序**:价格优先(高价优先)→ 时间优先(早下单优先)→ 数量优先(小单优先)
+  - **整单匹配**:订单不拆分,库存充足则全部成交,不足则等待
+  - **数量保护**:过滤超过保护阈值的大额订单,防止市场操控
+  - **批量处理**:支持批处理大小控制,避免内存溢出
+
+### 2. 创建计划任务(1个Command类)
+
+#### 2.1 MexMatchCommand(撮合计划任务)
+- **核心功能**:定时执行撮合任务,处理待撮合的买入订单
+- **命令参数**:
+  - --item:指定商品ID,不指定则处理所有商品
+  - --batch:批处理大小,默认100
+  - --dry-run:试运行模式,不执行实际撮合
+- **主要功能**:
+  - 撮合前后统计对比
+  - 详细的执行结果展示
+  - 试运行模式支持
+  - 完整的错误处理和日志记录
+- **使用方式**:
+  ```bash
+  # 处理所有商品
+  php artisan mex:match
+  
+  # 处理指定商品
+  php artisan mex:match --item=1001
+  
+  # 试运行模式
+  php artisan mex:match --dry-run
+  
+  # 自定义批处理大小
+  php artisan mex:match --batch=50
+  ```
+
+## 核心技术实现
+
+### 1. 撮合算法详细设计
+
+#### 1.1 三级排序机制
+```sql
+ORDER BY 
+    price DESC,        -- 价格优先:买价高者优先
+    created_at ASC,    -- 时间优先:早下单者优先
+    quantity ASC       -- 数量优先:小单优先
+```
+
+#### 1.2 整单匹配原则
+- 检查库存是否充足满足整个订单
+- 库存充足:整单成交,更新订单状态为COMPLETED
+- 库存不足:跳过订单,保持PENDING状态等待下次撮合
+
+#### 1.3 数量保护机制
+- 过滤超过保护阈值的大额订单
+- 防止大户操控市场价格
+- 保护阈值对用户隐藏,增加不确定性
+
+### 2. 账户体系集成
+
+#### 2.1 账户角色定义
+- **仓库账户(USER_ID: 15)**:所有交易的中介方
+- **调控账户(USER_ID: 16)**:管理员操作专用账户
+
+#### 2.2 资金和物品流转设计
+- **用户卖出**:物品转入仓库账户,资金从仓库账户转出
+- **用户买入**:资金转入仓库账户,物品从仓库账户转出
+- **管理员注入**:调控账户→仓库账户
+- **管理员回收**:仓库账户→调控账户
+
+### 3. 缓存和性能优化
+
+#### 3.1 缓存策略
+- 价格配置:10分钟缓存,减少数据库查询
+- 缓存键设计:mex_price_config:{item_id}
+- 支持单个和批量缓存清除
+
+#### 3.2 性能优化
+- 批量处理机制,避免内存溢出
+- 数据库复合索引支持高效排序
+- 分页查询支持大数据量处理
+
+### 4. 监控和日志
+
+#### 4.1 详细日志记录
+- 撮合任务执行日志
+- 管理员操作审计日志
+- 异常错误追踪日志
+
+#### 4.2 统计分析功能
+- 实时撮合统计
+- 市场交易统计
+- 管理员操作统计
+- 价格趋势分析
+
+## 代码统计
+
+### Logic层代码统计
+| Logic类 | 行数 | 方法数 | 主要功能 |
+|---------|------|--------|----------|
+| MexWarehouseLogic | 280行 | 8个方法 | 库存管理、统计分析 |
+| MexTransactionLogic | 320行 | 9个方法 | 交易记录、统计分析 |
+| MexPriceConfigLogic | 300行 | 10个方法 | 价格验证、配置管理 |
+| MexAdminLogic | 280行 | 4个方法 | 管理员操作、账户流转 |
+| MexMatchLogic | 300行 | 6个方法 | 撮合算法、条件检查 |
+| **总计** | **1480行** | **37个方法** | **完整业务逻辑** |
+
+### Command类代码统计
+| Command类 | 行数 | 方法数 | 主要功能 |
+|-----------|------|--------|----------|
+| MexMatchCommand | 220行 | 6个方法 | 计划任务、统计展示 |
+
+### 总体代码统计
+- **新增文件**:6个(5个Logic + 1个Command)
+- **总代码行数**:1700行
+- **平均文件行数**:283行
+- **方法总数**:43个
+
+## 技术亮点
+
+### 1. 算法设计
+- 严格的三级排序撮合算法
+- 整单匹配原则确保交易完整性
+- 数量保护机制防止市场操控
+
+### 2. 数据一致性
+- 数据库事务确保操作原子性
+- 完整的错误处理和回滚机制
+- 账户流转的双重验证
+
+### 3. 性能优化
+- 缓存机制减少数据库压力
+- 批量处理支持大规模数据
+- 索引优化支持高效查询
+
+### 4. 监控完善
+- 详细的统计分析功能
+- 完整的日志记录机制
+- 试运行模式支持调试
+
+## 文件变更记录
+
+### 新增文件
+- 5个Logic文件:完整的业务逻辑实现
+- 1个Command文件:撮合计划任务
+
+### Git提交信息
+```
+完善Mex模块Logic层和创建计划任务
+
+## 完成内容
+### 1. 完善Logic层业务逻辑(5个Logic类)
+- 实现1480行核心业务逻辑代码
+- 包含撮合算法、账户流转、价格验证等完整功能
+
+### 2. 创建计划任务(1个Command类)
+- 支持指定商品、批处理、试运行模式
+- 完整的统计展示和错误处理
+
+## 核心功能
+- 三级排序撮合算法
+- 整单匹配原则
+- 账户体系集成
+- 缓存和性能优化
+- 监控和日志机制
+
+Logic层总计1400+行代码,实现了完整的业务逻辑处理
+```
+
+## 任务成果
+1. **Logic层完善**:实现了5个核心业务逻辑类,总计1480行代码
+2. **撮合算法实现**:完整的三级排序撮合算法,支持整单匹配和数量保护
+3. **账户体系集成**:完整的仓库账户和调控账户流转机制
+4. **计划任务创建**:功能完善的撮合计划任务,支持多种运行模式
+5. **性能优化**:缓存机制、批量处理、索引优化等性能保证
+
+## 后续建议
+1. 实现具体的账户流转逻辑(Fund模块集成)
+2. 创建后台管理控制器
+3. 添加更多的监控和告警机制
+4. 进行完整的功能测试和性能测试
+
+---
+**任务完成时间**:2025年06月11日 21:40  
+**文档状态**:已完成并提交到Git仓库

+ 5 - 0
app/Module/Mex/Databases/GenerateSql/add_failed_reason_to_mex_orders.sql

@@ -0,0 +1,5 @@
+-- 为mex_orders表添加failed_reason字段
+-- 用于记录订单失败的原因
+
+ALTER TABLE `kku_mex_orders` 
+ADD COLUMN `failed_reason` text NULL COMMENT '失败原因' AFTER `completed_at`;

+ 289 - 0
app/Module/Mex/Logic/MexAccountLogic.php

@@ -0,0 +1,289 @@
+<?php
+
+namespace App\Module\Mex\Logic;
+
+use App\Module\Fund\Services\FundService;
+use App\Module\Fund\Enums\FUND_TYPE;
+use App\Module\GameItems\Services\ItemService;
+use App\Module\Mex\Logic\MexTransactionLogic;
+use App\Module\Mex\Logic\MexWarehouseLogic;
+use App\Module\Mex\Enums\TransactionType;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+
+/**
+ * 农贸市场账户流转逻辑
+ * 
+ * 处理用户与仓库账户之间的资金和物品流转
+ * 仓库账户USER_ID为15,调控账户USER_ID为16
+ */
+class MexAccountLogic
+{
+    // 仓库账户ID
+    const WAREHOUSE_USER_ID = 15;
+    
+    // 调控账户ID  
+    const REGULATION_USER_ID = 16;
+    
+    // 默认资金类型(金币)
+    const DEFAULT_FUND_TYPE = FUND_TYPE::FUND1;
+
+    /**
+     * 处理用户卖出订单的账户流转
+     * 用户卖出:资金从仓库转出到用户、物品从用户转入仓库
+     * 
+     * @param int $userId 用户ID
+     * @param int $itemId 商品ID
+     * @param int $quantity 数量
+     * @param string $price 单价
+     * @param string $totalAmount 总金额
+     * @param int $orderId 订单ID
+     * @return array 操作结果
+     */
+    public static function processSellOrder(int $userId, int $itemId, int $quantity, string $price, string $totalAmount, int $orderId): array
+    {
+        try {
+            DB::beginTransaction();
+            
+            // 1. 验证用户是否有足够的物品
+            $checkResult = ItemService::checkItemQuantity($userId, $itemId, $quantity);
+            if (!$checkResult->success) {
+                DB::rollBack();
+                return ['success' => false, 'message' => $checkResult->message];
+            }
+            
+            // 2. 从用户扣除物品
+            $consumeResult = ItemService::consumeItem($userId, $itemId, null, $quantity, [
+                'reason' => 'mex_sell',
+                'order_id' => $orderId,
+                'remark' => "农贸市场卖出物品,订单ID:{$orderId}"
+            ]);
+            
+            if (!$consumeResult['success']) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '扣除用户物品失败:' . ($consumeResult['message'] ?? '未知错误')];
+            }
+            
+            // 3. 给仓库账户添加物品
+            $addResult = ItemService::addItem(self::WAREHOUSE_USER_ID, $itemId, $quantity, [
+                'reason' => 'mex_warehouse_buy',
+                'order_id' => $orderId,
+                'remark' => "农贸市场仓库收购物品,订单ID:{$orderId}"
+            ]);
+            
+            if (!$addResult['success']) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '仓库添加物品失败:' . ($addResult['message'] ?? '未知错误')];
+            }
+            
+            // 4. 从仓库账户转出资金给用户
+            $warehouseFundService = new FundService(self::WAREHOUSE_USER_ID, self::DEFAULT_FUND_TYPE);
+            $fundAmount = (int)bcmul($totalAmount, '100', 0); // 转换为整数(分)
+            
+            $transferResult = $warehouseFundService->trade(
+                $userId,
+                $fundAmount,
+                'mex_sell',
+                $orderId,
+                "农贸市场卖出收款,订单ID:{$orderId}"
+            );
+            
+            if (is_string($transferResult)) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '资金转移失败:' . $transferResult];
+            }
+            
+            // 5. 更新仓库统计
+            $warehouseResult = MexWarehouseLogic::addStock($itemId, $quantity, $totalAmount);
+            if (!$warehouseResult) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '更新仓库统计失败'];
+            }
+            
+            // 6. 创建成交记录
+            $transactionResult = MexTransactionLogic::createTransaction([
+                'sell_order_id' => $orderId,
+                'buyer_id' => self::WAREHOUSE_USER_ID,
+                'seller_id' => $userId,
+                'item_id' => $itemId,
+                'quantity' => $quantity,
+                'price' => $price,
+                'total_amount' => $totalAmount,
+                'transaction_type' => TransactionType::USER_SELL,
+                'is_admin_operation' => false,
+            ]);
+            
+            if (!$transactionResult) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '创建成交记录失败'];
+            }
+            
+            DB::commit();
+            
+            return [
+                'success' => true,
+                'message' => '卖出订单处理成功',
+                'transaction_id' => $transactionResult->id,
+                'fund_transfer' => $transferResult,
+                'item_consume' => $consumeResult,
+                'warehouse_add' => $addResult
+            ];
+            
+        } catch (\Exception $e) {
+            DB::rollBack();
+            Log::error('Mex卖出订单处理失败', [
+                'user_id' => $userId,
+                'item_id' => $itemId,
+                'quantity' => $quantity,
+                'order_id' => $orderId,
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString()
+            ]);
+            
+            return ['success' => false, 'message' => '系统错误:' . $e->getMessage()];
+        }
+    }
+
+    /**
+     * 处理用户买入订单的账户流转
+     * 用户买入:资金从用户转入仓库、物品从仓库转出到用户
+     * 
+     * @param int $userId 用户ID
+     * @param int $itemId 商品ID
+     * @param int $quantity 数量
+     * @param string $price 单价
+     * @param string $totalAmount 总金额
+     * @param int $orderId 订单ID
+     * @return array 操作结果
+     */
+    public static function processBuyOrder(int $userId, int $itemId, int $quantity, string $price, string $totalAmount, int $orderId): array
+    {
+        try {
+            DB::beginTransaction();
+            
+            // 1. 验证仓库是否有足够的物品
+            if (!MexWarehouseLogic::checkStockSufficient($itemId, $quantity)) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '仓库库存不足'];
+            }
+            
+            // 2. 验证用户是否有足够的资金
+            $userFundService = new FundService($userId, self::DEFAULT_FUND_TYPE);
+            $fundAmount = (int)bcmul($totalAmount, '100', 0); // 转换为整数(分)
+            
+            if ($userFundService->balance() < $fundAmount) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '用户资金不足'];
+            }
+            
+            // 3. 从用户转出资金到仓库
+            $transferResult = $userFundService->trade(
+                self::WAREHOUSE_USER_ID,
+                $fundAmount,
+                'mex_buy',
+                $orderId,
+                "农贸市场买入付款,订单ID:{$orderId}"
+            );
+            
+            if (is_string($transferResult)) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '资金转移失败:' . $transferResult];
+            }
+            
+            // 4. 从仓库扣除物品
+            $consumeResult = ItemService::consumeItem(self::WAREHOUSE_USER_ID, $itemId, null, $quantity, [
+                'reason' => 'mex_warehouse_sell',
+                'order_id' => $orderId,
+                'remark' => "农贸市场仓库出售物品,订单ID:{$orderId}"
+            ]);
+            
+            if (!$consumeResult['success']) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '仓库扣除物品失败:' . ($consumeResult['message'] ?? '未知错误')];
+            }
+            
+            // 5. 给用户添加物品
+            $addResult = ItemService::addItem($userId, $itemId, $quantity, [
+                'reason' => 'mex_buy',
+                'order_id' => $orderId,
+                'remark' => "农贸市场买入物品,订单ID:{$orderId}"
+            ]);
+            
+            if (!$addResult['success']) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '用户添加物品失败:' . ($addResult['message'] ?? '未知错误')];
+            }
+            
+            // 6. 更新仓库统计
+            $warehouseResult = MexWarehouseLogic::reduceStock($itemId, $quantity, $totalAmount);
+            if (!$warehouseResult) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '更新仓库统计失败'];
+            }
+            
+            // 7. 创建成交记录
+            $transactionResult = MexTransactionLogic::createTransaction([
+                'buy_order_id' => $orderId,
+                'buyer_id' => $userId,
+                'seller_id' => self::WAREHOUSE_USER_ID,
+                'item_id' => $itemId,
+                'quantity' => $quantity,
+                'price' => $price,
+                'total_amount' => $totalAmount,
+                'transaction_type' => TransactionType::USER_BUY,
+                'is_admin_operation' => false,
+            ]);
+            
+            if (!$transactionResult) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '创建成交记录失败'];
+            }
+            
+            DB::commit();
+            
+            return [
+                'success' => true,
+                'message' => '买入订单处理成功',
+                'transaction_id' => $transactionResult->id,
+                'fund_transfer' => $transferResult,
+                'item_consume' => $consumeResult,
+                'user_add' => $addResult
+            ];
+            
+        } catch (\Exception $e) {
+            DB::rollBack();
+            Log::error('Mex买入订单处理失败', [
+                'user_id' => $userId,
+                'item_id' => $itemId,
+                'quantity' => $quantity,
+                'order_id' => $orderId,
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString()
+            ]);
+            
+            return ['success' => false, 'message' => '系统错误:' . $e->getMessage()];
+        }
+    }
+
+    /**
+     * 检查仓库账户资金余额
+     * 
+     * @return int 余额(分)
+     */
+    public static function getWarehouseFundBalance(): int
+    {
+        $warehouseFundService = new FundService(self::WAREHOUSE_USER_ID, self::DEFAULT_FUND_TYPE);
+        return $warehouseFundService->balance();
+    }
+
+    /**
+     * 检查调控账户资金余额
+     * 
+     * @return int 余额(分)
+     */
+    public static function getRegulationFundBalance(): int
+    {
+        $regulationFundService = new FundService(self::REGULATION_USER_ID, self::DEFAULT_FUND_TYPE);
+        return $regulationFundService->balance();
+    }
+}

+ 84 - 13
app/Module/Mex/Logic/MexOrderLogic.php

@@ -6,7 +6,7 @@ use App\Module\Mex\Models\MexOrder;
 use App\Module\Mex\Models\MexPriceConfig;
 use App\Module\Mex\Enums\OrderType;
 use App\Module\Mex\Enums\OrderStatus;
-use Illuminate\Support\Facades\DB;
+use App\Module\Mex\Logic\MexAccountLogic;
 
 /**
  * 农贸市场订单逻辑
@@ -100,7 +100,10 @@ class MexOrderLogic
                 'frozen_amount' => $totalAmount,
             ]);
 
-            return ['success' => true, 'order_id' => $order->id, 'message' => '买入订单创建成功,等待撮合'];
+            // 买入订单立即处理
+            $result = self::processBuyOrderImmediately($order);
+
+            return ['success' => true, 'order_id' => $order->id, 'result' => $result];
         } catch (\Exception $e) {
             return ['success' => false, 'message' => '创建订单失败:' . $e->getMessage()];
         }
@@ -108,22 +111,90 @@ class MexOrderLogic
 
     /**
      * 立即处理卖出订单
-     * 
+     *
      * @param MexOrder $order 订单
      * @return array 处理结果
      */
     private static function processSellOrderImmediately(MexOrder $order): array
     {
-        // 这里应该调用账户流转逻辑
-        // 暂时返回成功结果
-        $order->update([
-            'status' => OrderStatus::COMPLETED,
-            'completed_quantity' => $order->quantity,
-            'completed_amount' => $order->total_amount,
-            'completed_at' => now(),
-        ]);
-
-        return ['success' => true, 'message' => '卖出订单已完成'];
+        // 调用账户流转逻辑处理卖出订单
+        $result = MexAccountLogic::processSellOrder(
+            $order->user_id,
+            $order->item_id,
+            $order->quantity,
+            $order->price,
+            $order->total_amount,
+            $order->id
+        );
+
+        if ($result['success']) {
+            // 更新订单状态为已完成
+            $order->update([
+                'status' => OrderStatus::COMPLETED,
+                'completed_quantity' => $order->quantity,
+                'completed_amount' => $order->total_amount,
+                'completed_at' => now(),
+            ]);
+
+            return [
+                'success' => true,
+                'message' => '卖出订单已完成',
+                'transaction_id' => $result['transaction_id'] ?? null
+            ];
+        } else {
+            // 处理失败,更新订单状态为失败
+            $order->update([
+                'status' => OrderStatus::FAILED,
+                'failed_reason' => $result['message'],
+                'completed_at' => now(),
+            ]);
+
+            return $result;
+        }
+    }
+
+    /**
+     * 立即处理买入订单
+     *
+     * @param MexOrder $order 订单
+     * @return array 处理结果
+     */
+    private static function processBuyOrderImmediately(MexOrder $order): array
+    {
+        // 调用账户流转逻辑处理买入订单
+        $result = MexAccountLogic::processBuyOrder(
+            $order->user_id,
+            $order->item_id,
+            $order->quantity,
+            $order->price,
+            $order->total_amount,
+            $order->id
+        );
+
+        if ($result['success']) {
+            // 更新订单状态为已完成
+            $order->update([
+                'status' => OrderStatus::COMPLETED,
+                'completed_quantity' => $order->quantity,
+                'completed_amount' => $order->total_amount,
+                'completed_at' => now(),
+            ]);
+
+            return [
+                'success' => true,
+                'message' => '买入订单已完成',
+                'transaction_id' => $result['transaction_id'] ?? null
+            ];
+        } else {
+            // 处理失败,更新订单状态为失败
+            $order->update([
+                'status' => OrderStatus::FAILED,
+                'failed_reason' => $result['message'],
+                'completed_at' => now(),
+            ]);
+
+            return $result;
+        }
     }
 
     /**

+ 18 - 1
app/Module/Mex/Models/MexOrder.php

@@ -23,13 +23,29 @@ use UCore\ModelCore;
  * @property  \Carbon\Carbon  $created_at  创建时间
  * @property  \Carbon\Carbon  $updated_at  更新时间
  * @property  \Carbon\Carbon  $completed_at  完成时间
+ * @property  string  $failed_reason  失败原因
  * field end
  */
 class MexOrder extends ModelCore
 {
     protected $table = 'mex_orders';
 
-
+    // attrlist start
+    protected $fillable = [
+        'user_id',
+        'item_id',
+        'order_type',
+        'quantity',
+        'price',
+        'total_amount',
+        'status',
+        'frozen_amount',
+        'completed_quantity',
+        'completed_amount',
+        'completed_at',
+        'failed_reason',
+    ];
+    // attrlist end
 
     protected $casts = [
         'user_id' => 'integer',
@@ -43,6 +59,7 @@ class MexOrder extends ModelCore
         'completed_quantity' => 'integer',
         'completed_amount' => 'decimal:5',
         'completed_at' => 'datetime',
+        'failed_reason' => 'string',
     ];
 
 

+ 187 - 0
app/Module/Mex/Tests/MexAccountLogicTest.php

@@ -0,0 +1,187 @@
+<?php
+
+namespace App\Module\Mex\Tests;
+
+use App\Module\Mex\Logic\MexAccountLogic;
+use App\Module\Mex\Logic\MexOrderLogic;
+use App\Module\Mex\Models\MexPriceConfig;
+use App\Module\Fund\Services\FundService;
+use App\Module\Fund\Enums\FUND_TYPE;
+use App\Module\GameItems\Services\ItemService;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Tests\TestCase;
+
+/**
+ * Mex账户流转逻辑测试
+ */
+class MexAccountLogicTest extends TestCase
+{
+    use RefreshDatabase;
+
+    private int $testUserId = 1001;
+    private int $testItemId = 10001;
+    private int $warehouseUserId = 15;
+    
+    protected function setUp(): void
+    {
+        parent::setUp();
+        
+        // 初始化测试数据
+        $this->initTestData();
+    }
+
+    /**
+     * 初始化测试数据
+     */
+    private function initTestData(): void
+    {
+        // 创建价格配置
+        MexPriceConfig::create([
+            'item_id' => $this->testItemId,
+            'min_price' => '1.00000',
+            'max_price' => '10.00000',
+            'protection_threshold' => 1000,
+            'is_enabled' => true,
+        ]);
+
+        // 给测试用户添加物品
+        ItemService::addItem($this->testUserId, $this->testItemId, 100, [
+            'reason' => 'test_init',
+            'remark' => '测试初始化物品'
+        ]);
+
+        // 给仓库用户添加资金
+        $warehouseFundService = new FundService($this->warehouseUserId, FUND_TYPE::FUND1);
+        $warehouseFundService->admin_operate(
+            1, // admin_id
+            FUND_TYPE::FUND1,
+            1000000, // 10000.00元
+            '测试初始化仓库资金'
+        );
+
+        // 给测试用户添加资金
+        $userFundService = new FundService($this->testUserId, FUND_TYPE::FUND1);
+        $userFundService->admin_operate(
+            1, // admin_id
+            FUND_TYPE::FUND1,
+            500000, // 5000.00元
+            '测试初始化用户资金'
+        );
+    }
+
+    /**
+     * 测试用户卖出订单处理
+     */
+    public function testUserSellOrder(): void
+    {
+        // 创建卖出订单
+        $result = MexOrderLogic::createSellOrder(
+            $this->testUserId,
+            $this->testItemId,
+            10,
+            '2.50000'
+        );
+
+        $this->assertTrue($result['success'], '卖出订单创建应该成功');
+        $this->assertArrayHasKey('order_id', $result);
+        $this->assertArrayHasKey('result', $result);
+        
+        $orderResult = $result['result'];
+        $this->assertTrue($orderResult['success'], '卖出订单处理应该成功');
+        $this->assertArrayHasKey('transaction_id', $orderResult);
+
+        // 验证用户物品减少
+        $userItems = ItemService::getUserItems($this->testUserId, ['item_id' => $this->testItemId]);
+        $totalQuantity = $userItems->sum('quantity');
+        $this->assertEquals(90, $totalQuantity, '用户物品应该减少10个');
+
+        // 验证用户资金增加
+        $userFundService = new FundService($this->testUserId, FUND_TYPE::FUND1);
+        $userBalance = $userFundService->balance();
+        $this->assertGreaterThan(500000, $userBalance, '用户资金应该增加');
+    }
+
+    /**
+     * 测试用户买入订单处理
+     */
+    public function testUserBuyOrder(): void
+    {
+        // 先给仓库添加一些物品
+        ItemService::addItem($this->warehouseUserId, $this->testItemId, 50, [
+            'reason' => 'test_warehouse_stock',
+            'remark' => '测试仓库库存'
+        ]);
+
+        // 创建买入订单
+        $result = MexOrderLogic::createBuyOrder(
+            $this->testUserId,
+            $this->testItemId,
+            5,
+            '8.00000'
+        );
+
+        $this->assertTrue($result['success'], '买入订单创建应该成功');
+        $this->assertArrayHasKey('order_id', $result);
+        $this->assertArrayHasKey('result', $result);
+        
+        $orderResult = $result['result'];
+        $this->assertTrue($orderResult['success'], '买入订单处理应该成功');
+        $this->assertArrayHasKey('transaction_id', $orderResult);
+
+        // 验证用户物品增加
+        $userItems = ItemService::getUserItems($this->testUserId, ['item_id' => $this->testItemId]);
+        $totalQuantity = $userItems->sum('quantity');
+        $this->assertEquals(105, $totalQuantity, '用户物品应该增加5个');
+
+        // 验证用户资金减少
+        $userFundService = new FundService($this->testUserId, FUND_TYPE::FUND1);
+        $userBalance = $userFundService->balance();
+        $this->assertLessThan(500000, $userBalance, '用户资金应该减少');
+    }
+
+    /**
+     * 测试资金不足的买入订单
+     */
+    public function testBuyOrderInsufficientFunds(): void
+    {
+        // 先给仓库添加一些物品
+        ItemService::addItem($this->warehouseUserId, $this->testItemId, 50, [
+            'reason' => 'test_warehouse_stock',
+            'remark' => '测试仓库库存'
+        ]);
+
+        // 尝试创建超出资金能力的买入订单
+        $result = MexOrderLogic::createBuyOrder(
+            $this->testUserId,
+            $this->testItemId,
+            1000, // 大量购买
+            '10.00000' // 高价
+        );
+
+        $this->assertTrue($result['success'], '订单创建应该成功');
+        
+        $orderResult = $result['result'];
+        $this->assertFalse($orderResult['success'], '订单处理应该失败');
+        $this->assertStringContainsString('资金不足', $orderResult['message']);
+    }
+
+    /**
+     * 测试物品不足的卖出订单
+     */
+    public function testSellOrderInsufficientItems(): void
+    {
+        // 尝试卖出超过拥有数量的物品
+        $result = MexOrderLogic::createSellOrder(
+            $this->testUserId,
+            $this->testItemId,
+            200, // 超过拥有的100个
+            '2.50000'
+        );
+
+        $this->assertTrue($result['success'], '订单创建应该成功');
+        
+        $orderResult = $result['result'];
+        $this->assertFalse($orderResult['success'], '订单处理应该失败');
+        $this->assertStringContainsString('不足', $orderResult['message']);
+    }
+}

+ 41 - 0
app/Module/Mex/Tests/README.md

@@ -0,0 +1,41 @@
+# Mex模块测试
+
+本目录包含Mex模块的自动化测试文件。
+
+## 测试文件说明
+
+### MexAccountLogicTest.php
+测试Mex模块的账户流转逻辑,包括:
+- 用户卖出订单处理
+- 用户买入订单处理  
+- 资金不足情况处理
+- 物品不足情况处理
+
+## 运行测试
+
+```bash
+# 运行所有Mex模块测试
+php artisan test app/Module/Mex/Tests/
+
+# 运行特定测试文件
+php artisan test app/Module/Mex/Tests/MexAccountLogicTest.php
+
+# 运行特定测试方法
+php artisan test app/Module/Mex/Tests/MexAccountLogicTest.php::testUserSellOrder
+```
+
+## 测试数据
+
+测试使用以下测试数据:
+- 测试用户ID:1001
+- 测试物品ID:10001
+- 仓库用户ID:15
+- 初始用户物品数量:100个
+- 初始用户资金:5000.00元
+- 初始仓库资金:10000.00元
+
+## 注意事项
+
+1. 测试使用RefreshDatabase trait,每次测试后会重置数据库
+2. 测试需要Fund模块和GameItems模块正常工作
+3. 测试前确保相关数据库表已创建