Explorar o código

Fund模块币种ID概念修复

- 明确币种ID概念:FUND_CURRENCY_TYPE枚举值,不是数据库表ID
- 修复FUND_TYPE枚举中重复映射错误
- 增强CurrencyDto,同时包含数据库表ID和币种ID
- 修复CurrencyService中所有使用数据库表ID的错误
- 修复FundService中传递错误币种ID的问题
- 更新所有币种比较和查找逻辑使用正确的币种ID
- 创建专门的验证命令确保修复正确
- 完善验证:币种映射、一致性检查、精度获取、格式化显示
- 更新记忆习惯文档明确币种ID概念
notfff hai 7 meses
pai
achega
bcbd4abfd0

+ 159 - 0
AiWork/2025年06月/13日1530-Fund模块币种ID概念修复.md

@@ -0,0 +1,159 @@
+# Fund模块币种ID概念修复
+
+**任务时间**: 2025年06月13日 15:30:00 CST  
+**任务内容**: 明确Fund模块中'币种ID'概念,修复混淆币种ID和数据库表ID的错误
+
+## 1. 问题背景
+
+Fund模块中存在概念混淆:
+- **币种ID**:应该是 `FUND_CURRENCY_TYPE` 枚举的 `value`(1=金币, 2=钻石, 3=人民币, 4=美元)
+- **数据库表ID**:是 `fund_currency` 表的自增主键 `id`
+
+多个地方错误地使用了数据库表ID而不是币种ID,导致逻辑错误。
+
+## 2. 主要修复
+
+### 2.1 FUND_TYPE枚举修复
+
+**修复前**:
+```php
+$map = [
+    self::FUND1->value() => FUND_CURRENCY_TYPE::JINBI,
+    self::FUND2->value() => FUND_CURRENCY_TYPE::ZUANSHI,
+    self::FUND2->value() => FUND_CURRENCY_TYPE::ZUANSHI  // 重复映射错误
+];
+```
+
+**修复后**:
+```php
+$map = [
+    self::FUND1->value() => FUND_CURRENCY_TYPE::JINBI,    // 金币账户 -> 金币币种
+    self::FUND2->value() => FUND_CURRENCY_TYPE::ZUANSHI,  // 钻石账户 -> 钻石币种
+    self::FUND3->value() => FUND_CURRENCY_TYPE::ZUANSHI   // 钻石冻结账户 -> 钻石币种
+];
+```
+
+### 2.2 CurrencyDto增强
+
+**新增字段**:
+- `$id`:数据库表ID
+- `$currencyId`:币种ID(枚举值)
+
+**fromModel方法更新**:
+```php
+$dto->id = $model->id;  // 数据库表ID
+$dto->currencyId = $model->type ? $model->type->value : 0;  // 币种ID(枚举值)
+```
+
+### 2.3 CurrencyService修复
+
+**check方法**:
+```php
+// 修复前:使用数据库表ID比较
+return $currency1->id === $currency2->id;
+
+// 修复后:使用币种ID比较
+return $currency1->currencyId === $currency2->currencyId;
+```
+
+**getCurrencyByFundId方法**:
+```php
+// 修复前:错误使用数据库表ID查找
+$currency = FundCurrencyModel::find($currencyEnum->value());
+
+// 修复后:通过币种枚举查找
+$currency = FundCurrencyModel::where('type', $currencyEnum)->first();
+```
+
+**getCurrencyPrecision方法**:
+```php
+// 修复前:通过数据库表ID查找
+$currency = FundCurrencyModel::find($currency_id);
+
+// 修复后:直接通过币种ID获取精度
+$currencyEnum = FUND_CURRENCY_TYPE::tryFrom($currency_id);
+return $currencyEnum->getPrecision();
+```
+
+**formatAmount方法**:
+```php
+// 修复前:使用数据库表ID查找
+$currency = FundCurrencyModel::find($currency_id);
+
+// 修复后:通过币种ID查找
+$currencyEnum = FUND_CURRENCY_TYPE::tryFrom($currency_id);
+$currency = FundCurrencyModel::where('type', $currencyEnum)->first();
+```
+
+### 2.4 FundService修复
+
+所有调用CurrencyService的地方都修复为使用币种ID:
+
+```php
+// 修复前:使用数据库表ID
+CurrencyService::validateAmountPrecision($amount, $currency->id)
+
+// 修复后:使用币种ID
+CurrencyService::validateAmountPrecision($amount, $currency->currencyId)
+```
+
+## 3. 概念明确
+
+### 3.1 币种ID映射
+
+| 币种名称 | 币种ID(枚举值) | 数据库表ID | 标识 |
+|----------|------------------|------------|------|
+| 金币     | 1                | 1          | GOLD |
+| 钻石     | 2                | 2          | OWG  |
+| 人民币   | 3                | 3          | CNY  |
+| 美元     | 4                | 4          | USD  |
+
+### 3.2 账户到币种映射
+
+| 账户类型 | 账户ID | 币种ID | 币种名称 |
+|----------|--------|--------|----------|
+| FUND1    | 1      | 1      | 金币     |
+| FUND2    | 2      | 2      | 钻石     |
+| FUND3    | 3      | 2      | 钻石     |
+
+### 3.3 使用原则
+
+- **对外接口**:使用币种ID(枚举值)
+- **内部存储**:数据库表ID仅用于关联查询
+- **业务逻辑**:统一使用币种ID进行比较和计算
+
+## 4. 验证结果
+
+创建了专门的验证命令 `php artisan fund:verify-currency-id`:
+
+✅ **币种ID概念正确**:1=金币, 2=钻石, 3=人民币, 4=美元  
+✅ **账户映射正确**:FUND1→金币, FUND2→钻石, FUND3→钻石  
+✅ **币种一致性检查正确**:金币≠钻石, 钻石=钻石冻结  
+✅ **精度获取正确**:金币0位, 钻石10位, 人民币/美元2位  
+✅ **格式化显示正确**:使用正确的币种标识和精度
+
+## 5. 影响范围
+
+### 5.1 修复的文件
+- `app/Module/Fund/Enums/FUND_TYPE.php`
+- `app/Module/Fund/Dto/CurrencyDto.php`
+- `app/Module/Fund/Services/CurrencyService.php`
+- `app/Module/Fund/Services/FundService.php`
+
+### 5.2 新增的验证
+- `app/Console/Commands/VerifyFundCurrencyId.php`
+
+### 5.3 文档更新
+- `AiWork/记忆习惯.md`
+
+## 6. 总结
+
+成功修复了Fund模块中币种ID概念混淆的问题:
+
+1. **明确了概念**:币种ID = FUND_CURRENCY_TYPE枚举值,不是数据库表ID
+2. **修复了逻辑错误**:所有币种比较和查找都使用正确的币种ID
+3. **增强了数据结构**:CurrencyDto同时包含数据库表ID和币种ID
+4. **完善了验证**:创建专门的验证命令确保修复正确
+5. **更新了文档**:在记忆习惯中明确记录币种ID概念
+
+Fund模块现在拥有了清晰、正确的币种ID概念和实现!

+ 1 - 0
AiWork/记忆习惯.md

@@ -72,6 +72,7 @@
 - Fund模块全面采用小数存储模式,数据库使用DECIMAL(30,10)直接存储小数值,不再使用整数存储转换
 - Fund模块精度配置硬编码到FUND_CURRENCY_TYPE枚举中,用于显示格式化和精度验证
 - Fund模块需要支持冻结账户功能,钻石币种支持10位小数精度,冻结账户作为特殊账户类型与普通账户同属一个币种
+- Fund模块中'币种ID'概念明确指FUND_CURRENCY_TYPE枚举的value值(1=金币,2=钻石,3=人民币,4=美元),而不是fund_currency数据库表的自增ID字段
 - Point模块基于Fund模块创建,专注于整数型积分逻辑处理,不使用小数模式
 
 ### Mex模块

+ 81 - 0
app/Console/Commands/VerifyFundCurrencyId.php

@@ -0,0 +1,81 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Module\Fund\Enums\FUND_CURRENCY_TYPE;
+use App\Module\Fund\Enums\FUND_TYPE;
+use App\Module\Fund\Services\CurrencyService;
+use App\Module\Fund\Models\FundCurrencyModel;
+use Illuminate\Console\Command;
+
+class VerifyFundCurrencyId extends Command
+{
+    protected $signature = 'fund:verify-currency-id';
+    protected $description = '验证Fund模块币种ID概念的正确性';
+
+    public function handle()
+    {
+        $this->info('=== Fund模块币种ID概念验证 ===');
+        
+        try {
+            // 测试1: 验证币种ID概念
+            $this->info('1. 验证币种ID概念...');
+            $this->line('   币种ID应该是FUND_CURRENCY_TYPE枚举的value,不是数据库表的ID');
+            
+            foreach (FUND_CURRENCY_TYPE::cases() as $currencyType) {
+                $this->line("   - {$currencyType->getCurrencyName()}: 币种ID = {$currencyType->value}");
+            }
+            
+            // 测试2: 验证数据库表ID vs 币种ID
+            $this->info('2. 验证数据库表ID vs 币种ID...');
+            $currencies = FundCurrencyModel::all();
+            foreach ($currencies as $currency) {
+                $this->line("   - {$currency->name}: 数据库表ID = {$currency->id}, 币种ID = " . ($currency->type ? $currency->type->value : 'NULL'));
+            }
+            
+            // 测试3: 验证账户类型到币种的映射
+            $this->info('3. 验证账户类型到币种的映射...');
+            foreach (FUND_TYPE::cases() as $fundType) {
+                $currency = CurrencyService::getCurrencyByFundId($fundType->value);
+                if ($currency) {
+                    $this->line("   - {$fundType->name} (账户ID:{$fundType->value}) -> 币种ID:{$currency->currencyId} ({$currency->name})");
+                } else {
+                    $this->line("   - {$fundType->name} (账户ID:{$fundType->value}) -> 无对应币种");
+                }
+            }
+            
+            // 测试4: 验证币种一致性检查
+            $this->info('4. 验证币种一致性检查...');
+            $fund1 = FUND_TYPE::FUND1->value;  // 金币账户
+            $fund2 = FUND_TYPE::FUND2->value;  // 钻石账户
+            $fund3 = FUND_TYPE::FUND3->value;  // 钻石冻结账户
+            
+            $check1 = CurrencyService::check($fund1, $fund2);
+            $check2 = CurrencyService::check($fund2, $fund3);
+            
+            $this->line("   - 金币账户 vs 钻石账户: " . ($check1 ? '币种一致' : '币种不一致') . ' (应该不一致)');
+            $this->line("   - 钻石账户 vs 钻石冻结账户: " . ($check2 ? '币种一致' : '币种不一致') . ' (应该一致)');
+            
+            // 测试5: 验证精度获取
+            $this->info('5. 验证精度获取...');
+            foreach (FUND_CURRENCY_TYPE::cases() as $currencyType) {
+                $precision = CurrencyService::getCurrencyPrecision($currencyType->value);
+                $this->line("   - {$currencyType->getCurrencyName()} (币种ID:{$currencyType->value}): 精度 = {$precision}");
+            }
+            
+            // 测试6: 验证格式化显示
+            $this->info('6. 验证格式化显示...');
+            $testAmount = 123.456789;
+            foreach (FUND_CURRENCY_TYPE::cases() as $currencyType) {
+                $formatted = CurrencyService::formatAmount($testAmount, $currencyType->value);
+                $this->line("   - {$currencyType->getCurrencyName()}: {$testAmount} -> {$formatted}");
+            }
+            
+            $this->info('=== 验证完成 ===');
+            
+        } catch (\Exception $e) {
+            $this->error("错误: " . $e->getMessage());
+            $this->error("文件: " . $e->getFile() . ":" . $e->getLine());
+        }
+    }
+}

+ 71 - 0
app/Console/Commands/VerifyFundDecimal.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Module\Fund\Enums\FUND_TYPE;
+use App\Module\Fund\Services\FundService;
+use App\Module\Fund\Services\AccountService;
+use App\Module\Fund\Services\CurrencyService;
+use Illuminate\Console\Command;
+
+class VerifyFundDecimal extends Command
+{
+    protected $signature = 'fund:verify-decimal';
+    protected $description = '验证Fund模块小数适配';
+
+    public function handle()
+    {
+        $this->info('=== Fund模块小数适配验证 ===');
+        
+        try {
+            $testUserId = 10001;
+            
+            // 确保测试用户有账户
+            AccountService::check4user($testUserId);
+            
+            // 测试1: 验证balance方法返回类型
+            $this->info('1. 测试balance方法返回类型...');
+            $fund = new FundService($testUserId, FUND_TYPE::FUND2->value);
+            $balance = $fund->balance();
+            $this->line("   余额类型: " . gettype($balance));
+            $this->line("   余额值: " . $balance);
+            
+            // 测试2: 验证CurrencyService的小数处理和币种ID概念
+            $this->info('2. 测试CurrencyService小数处理和币种ID概念...');
+            $currency = CurrencyService::getCurrencyByFundId(FUND_TYPE::FUND2->value);
+            if ($currency) {
+                $this->line("   数据库表ID: " . $currency->id);
+                $this->line("   币种ID(枚举值): " . $currency->currencyId);
+                $this->line("   币种精度: " . $currency->precision);
+
+                // 测试精度验证(使用币种ID,不是数据库表ID)
+                $testAmount = 100.123456789;
+                $isValid = CurrencyService::validateAmountPrecision($testAmount, $currency->currencyId);
+                $formatted = CurrencyService::formatAmountToPrecision($testAmount, $currency->currencyId);
+
+                $this->line("   原始金额: " . $testAmount);
+                $this->line("   精度验证: " . ($isValid ? '通过' : '失败'));
+                $this->line("   格式化后: " . $formatted);
+                $this->line("   格式化显示: " . CurrencyService::formatAmount($formatted, $currency->currencyId));
+            } else {
+                $this->line("   无法获取币种信息");
+            }
+            
+            // 测试3: 验证FundAccountDto
+            $this->info('3. 测试FundAccountDto...');
+            $account = $fund->getAccount();
+            if ($account) {
+                $this->line("   账户余额类型: " . gettype($account->balance));
+                $this->line("   账户余额值: " . $account->balance);
+            } else {
+                $this->line("   无法获取账户信息");
+            }
+            
+            $this->info('=== 验证完成 ===');
+            
+        } catch (\Exception $e) {
+            $this->error("错误: " . $e->getMessage());
+            $this->error("文件: " . $e->getFile() . ":" . $e->getLine());
+        }
+    }
+}

+ 9 - 6
app/Module/Fund/Dto/CurrencyDto.php

@@ -12,10 +12,15 @@ use App\Module\Fund\Models\FundCurrencyModel;
 class CurrencyDto
 {
     /**
-     * @var int 币种ID
+     * @var int 数据库表ID
      */
     public int $id;
 
+    /**
+     * @var int 币种ID(FUND_CURRENCY_TYPE枚举值)
+     */
+    public int $currencyId;
+
     /**
      * @var string 币种标识
      */
@@ -57,7 +62,8 @@ class CurrencyDto
     public static function fromModel(FundCurrencyModel $model): self
     {
         $dto = new self();
-        $dto->id = $model->id;
+        $dto->id = $model->id;  // 数据库表ID
+        $dto->currencyId = $model->type ? $model->type->value : 0;  // 币种ID(枚举值)
         $dto->identification = $model->identification;
         $dto->icon = $model->icon;
         $dto->name = $model->name;
@@ -75,10 +81,6 @@ class CurrencyDto
     }
 
 
-    public static function fromModel(FundCurrencyModel $model): self
-    {
-
-    }
 
     /**
      * 转换为数组
@@ -89,6 +91,7 @@ class CurrencyDto
     {
         return [
             'id' => $this->id,
+            'currency_id' => $this->currencyId,
             'identification' => $this->identification,
             'icon' => $this->icon,
             'name' => $this->name,

+ 3 - 3
app/Module/Fund/Enums/FUND_TYPE.php

@@ -52,9 +52,9 @@ enum FUND_TYPE: int
     public static function type2Currency(FUND_TYPE $FUND_TYPE): ?FUND_CURRENCY_TYPE
     {
         $map = [
-            self::FUND1->value() => FUND_CURRENCY_TYPE::JINBI,
-            self::FUND2->value() => FUND_CURRENCY_TYPE::ZUANSHI,
-            self::FUND2->value() => FUND_CURRENCY_TYPE::ZUANSHI
+            self::FUND1->value() => FUND_CURRENCY_TYPE::JINBI,    // 金币账户 -> 金币币种
+            self::FUND2->value() => FUND_CURRENCY_TYPE::ZUANSHI,  // 钻石账户 -> 钻石币种
+            self::FUND3->value() => FUND_CURRENCY_TYPE::ZUANSHI   // 钻石冻结账户 -> 钻石币种
         ];
 
         return $map[$FUND_TYPE->value()] ?? null;

+ 31 - 14
app/Module/Fund/Services/CurrencyService.php

@@ -4,6 +4,7 @@ namespace App\Module\Fund\Services;
 
 
 use App\Module\Fund\Dto\CurrencyDto;
+use App\Module\Fund\Enums\FUND_CURRENCY_TYPE;
 use App\Module\Fund\Enums\FUND_TYPE;
 use App\Module\Fund\Models\FundConfigModel;
 use App\Module\Fund\Models\FundCurrencyModel;
@@ -42,8 +43,8 @@ class CurrencyService
             return false;
         }
 
-        // 检查两个币种ID是否一致
-        return $currency1->id === $currency2->id;
+        // 检查两个币种ID是否一致(使用币种枚举值,不是数据库表ID)
+        return $currency1->currencyId === $currency2->currencyId;
     }
 
     /**
@@ -54,10 +55,14 @@ class CurrencyService
      */
     static public function getCurrencyByFundId($fund_id)
     {
-        // 获取账户种类信息
+        // 获取账户种类对应的币种枚举
         $currencyEnum = self::getCurrency2ByFundId($fund_id);
-        // 获取币种信息
-        $currency = FundCurrencyModel::find($currencyEnum->value());
+        if (!$currencyEnum) {
+            return null;
+        }
+
+        // 通过币种枚举查找对应的数据库记录
+        $currency = FundCurrencyModel::where('type', $currencyEnum)->first();
         if (!$currency) {
             return null;
         }
@@ -81,7 +86,7 @@ class CurrencyService
     /**
      * 获取币种配置
      *
-     * @param int|null $currency_id 币种ID,为null时返回所有币种配置
+     * @param int|null $currency_id 币种ID(FUND_CURRENCY_TYPE枚举值),为null时返回所有币种配置
      * @return CurrencyDto|CurrencyDto[] 币种配置DTO或DTO数组
      */
     public function getConfig($currency_id = null)
@@ -89,7 +94,12 @@ class CurrencyService
         if ($currency_id) {
             // 获取指定币种的配置
             return Cache::remember('currency_config_dto_' . $currency_id, self::CACHE_TTL, function () use ($currency_id) {
-                $currency = FundCurrencyModel::find($currency_id);
+                $currencyEnum = FUND_CURRENCY_TYPE::tryFrom($currency_id);
+                if (!$currencyEnum) {
+                    return null;
+                }
+
+                $currency = FundCurrencyModel::where('type', $currencyEnum)->first();
                 if (!$currency) {
                     return null;
                 }
@@ -168,18 +178,19 @@ class CurrencyService
     /**
      * 获取币种的精度
      *
-     * @param int $currency_id 币种ID
+     * @param int $currency_id 币种ID(FUND_CURRENCY_TYPE枚举值)
      * @return int 精度(小数位数)
      */
     static public function getCurrencyPrecision($currency_id)
     {
-        $currency = FundCurrencyModel::find($currency_id);
-        if (!$currency || !$currency->type) {
+        // 直接通过币种ID(枚举值)获取精度
+        $currencyEnum = FUND_CURRENCY_TYPE::tryFrom($currency_id);
+        if (!$currencyEnum) {
             return 2; // 默认精度为2
         }
 
         // 从枚举中获取精度信息
-        return $currency->type->getPrecision();
+        return $currencyEnum->getPrecision();
     }
 
     /**
@@ -199,9 +210,15 @@ class CurrencyService
         // 根据币种精度格式化金额
         $formattedAmount = number_format($numericAmount, $precision, '.', ',');
 
-        // 获取币种标识
-        $currency = FundCurrencyModel::find($currency_id);
-        $symbol   = $currency ? $currency->identification : '';
+        // 获取币种标识(通过币种ID获取)
+        $currencyEnum = FUND_CURRENCY_TYPE::tryFrom($currency_id);
+        if ($currencyEnum) {
+            // 通过枚举查找对应的数据库记录
+            $currency = FundCurrencyModel::where('type', $currencyEnum)->first();
+            $symbol   = $currency ? $currency->identification : '';
+        } else {
+            $symbol = '';
+        }
 
         return $symbol . ' ' . $formattedAmount;
     }

+ 8 - 8
app/Module/Fund/Services/FundService.php

@@ -67,10 +67,10 @@ class FundService
         }
 
         # 验证并格式化金额精度
-        if (!CurrencyService::validateAmountPrecision($amount, $currency->id)) {
+        if (!CurrencyService::validateAmountPrecision($amount, $currency->currencyId)) {
             return '金额精度超出币种支持范围';
         }
-        $formattedAmount = CurrencyService::formatAmountToPrecision($amount, $currency->id);
+        $formattedAmount = CurrencyService::formatAmountToPrecision($amount, $currency->currencyId);
 
         # 实例化操作对象
 
@@ -155,10 +155,10 @@ class FundService
         }
 
         # 验证并格式化金额精度
-        if (!CurrencyService::validateAmountPrecision($amount, $currency->id)) {
+        if (!CurrencyService::validateAmountPrecision($amount, $currency->currencyId)) {
             return '金额精度超出币种支持范围';
         }
-        $formattedAmount = CurrencyService::formatAmountToPrecision($amount, $currency->id);
+        $formattedAmount = CurrencyService::formatAmountToPrecision($amount, $currency->currencyId);
 
         # 实例化操作对象
 
@@ -232,10 +232,10 @@ class FundService
         }
 
         # 验证并格式化金额精度
-        if (!CurrencyService::validateAmountPrecision($amount, $currency->id)) {
+        if (!CurrencyService::validateAmountPrecision($amount, $currency->currencyId)) {
             return '金额精度超出币种支持范围';
         }
-        $formattedAmount = CurrencyService::formatAmountToPrecision($amount, $currency->id);
+        $formattedAmount = CurrencyService::formatAmountToPrecision($amount, $currency->currencyId);
 
         # 检查事务开启
         Helper::check_tr();
@@ -298,10 +298,10 @@ class FundService
         }
 
         # 验证并格式化金额精度
-        if (!CurrencyService::validateAmountPrecision($fund_fee, $currency->id)) {
+        if (!CurrencyService::validateAmountPrecision($fund_fee, $currency->currencyId)) {
             return '金额精度超出币种支持范围';
         }
-        $formattedFundFee = CurrencyService::formatAmountToPrecision($fund_fee, $currency->id);
+        $formattedFundFee = CurrencyService::formatAmountToPrecision($fund_fee, $currency->currencyId);
 
         $data = [
             'total_fee' => $formattedFundFee,