Преглед изворни кода

refactor(AiWork): 优化文档格式和代码结构

- 修改文档中的代码示例,使其符合规范格式
- 优化数据库表结构设计,增加必要的索引和字段
- 更新模型类中的属性注释,使其与数据库表结构一致
- 重构部分代码,提高可读性和可维护性
notfff пре 6 месеци
родитељ
комит
a1a50f8049
28 измењених фајлова са 543 додато и 635 уклоњено
  1. 1 1
      AiWork/202506/201823-Transfer模块手续费异常修复.md
  2. 5 1
      app/Module/Farm/Databases/GenerateSql/farm_crops.sql
  3. 5 14
      app/Module/Farm/Databases/GenerateSql/farm_daily_stats.sql
  4. 2 2
      app/Module/Farm/Models/FarmCrop.php
  5. 20 44
      app/Module/Game/Databases/GenerateSql/game_configs.sql
  6. 8 8
      app/Module/Game/Models/GameConfig.php
  7. 20 80
      app/Module/Mex/Databases/GenerateSql/mex_configs.sql
  8. 20 10
      app/Module/Mex/Databases/GenerateSql/mex_daily_price_trends.sql
  9. 24 0
      app/Module/Mex/Databases/GenerateSql/mex_match_logs.sql
  10. 1 0
      app/Module/Mex/Databases/GenerateSql/mex_orders.sql
  11. 6 6
      app/Module/Mex/Databases/GenerateSql/mex_price_adjustments.sql
  12. 7 7
      app/Module/Mex/Models/MexConfig.php
  13. 11 1
      app/Module/Mex/Models/MexDailyPriceTrend.php
  14. 1 1
      app/Module/Mex/Models/MexOrder.php
  15. 1 0
      app/Module/Transfer/Databases/GenerateSql/transfer_orders.sql
  16. 54 35
      app/Module/Transfer/Events/FeeCalculatedEvent.php
  17. 12 27
      app/Module/Transfer/Events/FeeCalculatingEvent.php
  18. 151 127
      app/Module/Transfer/Logics/TransferLogic.php
  19. 4 15
      app/Module/Transfer/Models/TransferApp.php
  20. 4 1
      app/Module/Transfer/Models/TransferOrder.php
  21. 28 30
      app/Module/Transfer/Services/FeeService.php
  22. 89 158
      app/Module/Transfer/Services/TransferService.php
  23. 7 31
      app/Module/Transfer/Services/TransferThirdPartyService.php
  24. 24 0
      app/Module/Transfer/Tests/Unit/CalculateOutFeeTest.php
  25. 2 0
      app/Module/UrsPromotion/Databases/GenerateSql/urs_promotion_talent_configs.sql
  26. 32 36
      app/Module/UrsPromotion/Listeners/UrsTransferFeeListener.php
  27. 2 0
      app/Module/UrsPromotion/Models/UrsTalentConfig.php
  28. 2 0
      database/test/delete.sql

+ 1 - 1
AiWork/202506/201823-Transfer模块手续费异常修复.md

@@ -54,7 +54,7 @@ public function calculateOutFee(string $amount): array
 }
 
 // 修改后  
-public function calculateOutFee(string $amount, array $context = []): array
+public function calculateOutFee(string $amount, array $context = []): FeeCalculatedEvent
 {
     // 使用FeeService来计算手续费,这样可以触发事件机制
     return \App\Module\Transfer\Services\FeeService::calculateOutFee($this, $amount, $context);

+ 5 - 1
app/Module/Farm/Databases/GenerateSql/farm_crops.sql

@@ -9,6 +9,7 @@ CREATE TABLE `kku_farm_crops` (
   `land_id` bigint unsigned NOT NULL COMMENT '土地ID',
   `user_id` bigint NOT NULL COMMENT '用户ID',
   `seed_id` bigint unsigned NOT NULL COMMENT '种子ID',
+  `land_level` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '种植时的土地等级,用于产出计算',
   `plant_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '种植时间',
   `growth_stage` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '生长阶段:1种子期,2发芽期,3生长期,4成熟期,5枯萎期',
   `stage_start_time` timestamp NULL DEFAULT NULL COMMENT '当前阶段结束时间',
@@ -21,8 +22,9 @@ CREATE TABLE `kku_farm_crops` (
   `final_output_amount` int DEFAULT NULL COMMENT '最终产出数量(成熟期确定)',
   `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
   `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `deleted_at` timestamp NULL DEFAULT NULL COMMENT '删除时间',
   PRIMARY KEY (`id`) USING BTREE,
-  UNIQUE KEY `idx_land_id` (`land_id`) USING BTREE,
+  UNIQUE KEY `idx_land_id_deleted_at` (`land_id`,`deleted_at`),
   KEY `idx_user_id` (`user_id`) USING BTREE,
   KEY `idx_seed_id` (`seed_id`) USING BTREE,
   KEY `idx_growth_stage` (`growth_stage`) USING BTREE,
@@ -31,5 +33,7 @@ CREATE TABLE `kku_farm_crops` (
   KEY `idx_disaster_check` (`can_disaster`,`last_disaster_check_time`) USING BTREE,
   KEY `idx_can_disaster` (`can_disaster`) USING BTREE,
   KEY `idx_final_output_item_id` (`final_output_item_id`),
+  KEY `idx_deleted_at` (`deleted_at`),
+  KEY `idx_land_level` (`land_level`),
   CONSTRAINT `fk_farm_crops_land_id` FOREIGN KEY (`land_id`) REFERENCES `kku_farm_land_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='作物信息表';

+ 5 - 14
app/Module/Farm/Databases/GenerateSql/farm_daily_stats.sql

@@ -1,15 +1,14 @@
--- 农场每日统计表
--- 用于存储每日的土地和房屋等级统计数据
-
-DROP TABLE IF EXISTS `kku_farm_daily_stats`;
+-- ******************************************************************
+-- 表 kku_farm_daily_stats 的创建SQL
+-- 对应的Model: App\Module\Farm\Models\FarmDailyStats
+-- 警告: 此文件由系统自动生成,禁止修改!
+-- ******************************************************************
 
 CREATE TABLE `kku_farm_daily_stats` (
   `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
   `stats_date` date NOT NULL COMMENT '统计日期',
   `total_users` int unsigned NOT NULL DEFAULT '0' COMMENT '总用户数',
   `active_users` int unsigned NOT NULL DEFAULT '0' COMMENT '活跃用户数(当日有操作)',
-  
-  -- 房屋等级统计
   `house_level_1` int unsigned NOT NULL DEFAULT '0' COMMENT '1级房屋数量',
   `house_level_2` int unsigned NOT NULL DEFAULT '0' COMMENT '2级房屋数量',
   `house_level_3` int unsigned NOT NULL DEFAULT '0' COMMENT '3级房屋数量',
@@ -20,31 +19,23 @@ CREATE TABLE `kku_farm_daily_stats` (
   `house_level_8` int unsigned NOT NULL DEFAULT '0' COMMENT '8级房屋数量',
   `house_level_9` int unsigned NOT NULL DEFAULT '0' COMMENT '9级房屋数量',
   `house_level_10` int unsigned NOT NULL DEFAULT '0' COMMENT '10级房屋数量',
-  
-  -- 土地类型统计
   `land_type_1` int unsigned NOT NULL DEFAULT '0' COMMENT '普通土地数量',
   `land_type_2` int unsigned NOT NULL DEFAULT '0' COMMENT '红土地数量',
   `land_type_3` int unsigned NOT NULL DEFAULT '0' COMMENT '黑土地数量',
   `land_type_4` int unsigned NOT NULL DEFAULT '0' COMMENT '金色特殊土地数量',
   `land_type_5` int unsigned NOT NULL DEFAULT '0' COMMENT '蓝色特殊土地数量',
   `land_type_6` int unsigned NOT NULL DEFAULT '0' COMMENT '紫色特殊土地数量',
-  
-  -- 土地状态统计
   `land_status_0` int unsigned NOT NULL DEFAULT '0' COMMENT '空闲土地数量',
   `land_status_1` int unsigned NOT NULL DEFAULT '0' COMMENT '种植中土地数量',
   `land_status_2` int unsigned NOT NULL DEFAULT '0' COMMENT '灾害土地数量',
   `land_status_3` int unsigned NOT NULL DEFAULT '0' COMMENT '可收获土地数量',
   `land_status_4` int unsigned NOT NULL DEFAULT '0' COMMENT '枯萎土地数量',
-  
-  -- 总计统计
   `total_lands` int unsigned NOT NULL DEFAULT '0' COMMENT '总土地数量',
   `total_special_lands` int unsigned NOT NULL DEFAULT '0' COMMENT '特殊土地总数量',
   `total_crops` int unsigned NOT NULL DEFAULT '0' COMMENT '总作物数量',
   `total_disasters` int unsigned NOT NULL DEFAULT '0' COMMENT '总灾害数量',
-  
   `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
   `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-  
   PRIMARY KEY (`id`) USING BTREE,
   UNIQUE KEY `idx_stats_date` (`stats_date`) USING BTREE,
   KEY `idx_created_at` (`created_at`) USING BTREE

+ 2 - 2
app/Module/Farm/Models/FarmCrop.php

@@ -12,12 +12,12 @@ use Illuminate\Database\Eloquent\SoftDeletes;
 /**
  * 作物信息模型
  *
- * field start
+ * field start 
  * @property  int  $id  主键ID
  * @property  int  $land_id  土地ID
  * @property  int  $user_id  用户ID
  * @property  int  $seed_id  种子ID
- * @property  int  $land_level  种植时的土地等级
+ * @property  int  $land_level  种植时的土地等级,用于产出计算
  * @property  \Carbon\Carbon  $plant_time  种植时间
  * @property  \App\Module\Farm\Enums\GROWTH_STAGE  $growth_stage  生长阶段:1种子期,2发芽期,3生长期,4成熟期,5枯萎期
  * @property  \Carbon\Carbon  $stage_start_time  当前阶段结束时间

+ 20 - 44
app/Module/Game/Databases/GenerateSql/game_configs.sql

@@ -1,19 +1,24 @@
--- 游戏配置表
+-- ******************************************************************
+-- 表 kku_game_configs 的创建SQL
+-- 对应的Model: App\Module\Game\Models\GameConfig
+-- 警告: 此文件由系统自动生成,禁止修改!
+-- ******************************************************************
+
 CREATE TABLE `kku_game_configs` (
-  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '配置ID,主键',
-  `key` varchar(100) NOT NULL COMMENT '配置键名,唯一标识',
-  `name` varchar(200) NOT NULL COMMENT '配置名称',
-  `description` text COMMENT '配置描述',
-  `group` varchar(50) NOT NULL COMMENT '配置分组',
-  `type` tinyint(4) NOT NULL COMMENT '配置类型:1布尔值,2整数,3小数,4字符串,5JSON',
-  `value` text COMMENT '配置值',
-  `default_value` text COMMENT '默认值',
-  `options` text COMMENT '可选项配置(JSON格式)',
-  `validation_rules` varchar(500) COMMENT '验证规则',
-  `is_enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否启用:0禁用,1启用',
-  `is_readonly` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否只读:0可编辑,1只读',
-  `sort_order` int(11) NOT NULL DEFAULT 0 COMMENT '排序权重',
-  `remark` text COMMENT '备注说明',
+  `id` int NOT NULL AUTO_INCREMENT COMMENT '配置ID,主键',
+  `key` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '配置键名,唯一标识',
+  `name` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '配置名称',
+  `description` text COLLATE utf8mb4_unicode_ci COMMENT '配置描述',
+  `group` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '配置分组',
+  `type` tinyint NOT NULL COMMENT '配置类型:1布尔值,2整数,3小数,4字符串,5JSON',
+  `value` text COLLATE utf8mb4_unicode_ci COMMENT '配置值',
+  `default_value` text COLLATE utf8mb4_unicode_ci COMMENT '默认值',
+  `options` text COLLATE utf8mb4_unicode_ci COMMENT '可选项配置(JSON格式)',
+  `validation_rules` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '验证规则',
+  `is_enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否启用:0禁用,1启用',
+  `is_readonly` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否只读:0可编辑,1只读',
+  `sort_order` int NOT NULL DEFAULT '0' COMMENT '排序权重',
+  `remark` text COLLATE utf8mb4_unicode_ci COMMENT '备注说明',
   `created_at` timestamp NULL DEFAULT NULL COMMENT '创建时间',
   `updated_at` timestamp NULL DEFAULT NULL COMMENT '更新时间',
   PRIMARY KEY (`id`),
@@ -21,32 +26,3 @@ CREATE TABLE `kku_game_configs` (
   KEY `idx_group` (`group`),
   KEY `idx_enabled` (`is_enabled`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='游戏配置表';
-
--- 插入默认配置数据
-INSERT INTO `kku_game_configs` (`key`, `name`, `description`, `group`, `type`, `value`, `default_value`, `sort_order`, `remark`) VALUES
--- 用户日志系统配置
-('user_log.enabled', '用户日志系统启用', '控制整个用户日志系统是否启用', 'user_log', 1, '1', '1', 10, '关闭后用户日志收集功能将不可用'),
-('user_log.auto_collect_enabled', '自动收集日志启用', '控制是否允许自动收集用户日志(定时任务等)', 'user_log', 1, '1', '1', 20, '关闭后只能通过强制执行收集日志'),
-('user_log.max_records_per_run', '单次最大处理记录数', '每次收集日志时的最大处理记录数', 'user_log', 2, '1000', '1000', 30, ''),
-('user_log.collection_interval', '收集间隔', '日志收集的间隔时间(秒)', 'user_log', 2, '2', '2', 40, ''),
-('user_log.retention_days', '日志保留天数', '用户日志的保留天数', 'user_log', 2, '30', '30', 50, ''),
-('user_log.auto_cleanup', '自动清理启用', '是否启用自动清理过期日志', 'user_log', 1, '1', '1', 60, ''),
-
--- 奖励系统配置
-('reward.enabled', '奖励系统启用', '控制整个奖励系统是否启用', 'reward', 1, '1', '1', 100, ''),
-('reward.max_reward_per_group', '单组最大奖励数', '单个奖励组最大奖励数量', 'reward', 2, '100', '100', 110, ''),
-('reward.log_retention_days', '奖励日志保留天数', '奖励日志的保留天数', 'reward', 2, '90', '90', 120, ''),
-
--- 条件系统配置
-('condition.enabled', '条件系统启用', '控制整个条件系统是否启用', 'condition', 1, '1', '1', 200, ''),
-('condition.cache_ttl', '条件缓存时间', '条件检查结果的缓存时间(秒)', 'condition', 2, '300', '300', 210, ''),
-
--- 消耗系统配置
-('consume.enabled', '消耗系统启用', '控制整个消耗系统是否启用', 'consume', 1, '1', '1', 300, ''),
-('consume.strict_mode', '严格模式', '是否启用严格模式(资源不足时直接失败)', 'consume', 1, '1', '1', 310, ''),
-
--- 系统配置
-('system.debug_mode', '调试模式', '启用调试模式,记录详细日志', 'system', 1, '0', '0', 900, '生产环境建议关闭'),
-('system.maintenance_mode', '维护模式', '系统维护模式,启用后部分功能受限', 'system', 1, '0', '0', 910, ''),
-('system.cache_enabled', '缓存启用', '是否启用系统缓存', 'system', 1, '1', '1', 920, ''),
-('system.cache_ttl', '缓存时间', '系统缓存的默认TTL(秒)', 'system', 2, '3600', '3600', 930, '');

+ 8 - 8
app/Module/Game/Models/GameConfig.php

@@ -14,16 +14,16 @@ use UCore\ModelCore;
  * @property  string  $key  配置键名,唯一标识
  * @property  string  $name  配置名称
  * @property  string  $description  配置描述
- * @property  GameConfigGroup  $group  配置分组
- * @property  GameConfigType  $type  配置类型
+ * @property  \App\Module\Game\Enums\GameConfigGroup  $group  配置分组
+ * @property  \App\Module\Game\Enums\GameConfigType  $type  配置类型:1布尔值,2整数,3小数,4字符串,5JSON
  * @property  string  $value  配置值
- * @property  string|null  $default_value  默认值
- * @property  string|null  $options  可选项配置(JSON格式)
- * @property  string|null  $validation_rules  验证规则
- * @property  bool  $is_enabled  是否启用
- * @property  bool  $is_readonly  是否只读
+ * @property  string  $default_value  默认值
+ * @property  array  $options  可选项配置(JSON格式)
+ * @property  string  $validation_rules  验证规则
+ * @property  bool  $is_enabled  是否启用:0禁用,1启用
+ * @property  bool  $is_readonly  是否只读:0可编辑,1只读
  * @property  int  $sort_order  排序权重
- * @property  string|null  $remark  备注说明
+ * @property  string  $remark  备注说明
  * @property  \Carbon\Carbon  $created_at  创建时间
  * @property  \Carbon\Carbon  $updated_at  更新时间
  * field end

+ 20 - 80
app/Module/Mex/Databases/GenerateSql/mex_configs.sql

@@ -1,19 +1,24 @@
--- Mex配置表
+-- ******************************************************************
+-- 表 kku_mex_configs 的创建SQL
+-- 对应的Model: App\Module\Mex\Models\MexConfig
+-- 警告: 此文件由系统自动生成,禁止修改!
+-- ******************************************************************
+
 CREATE TABLE `kku_mex_configs` (
-  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '配置ID,主键',
-  `key` varchar(100) NOT NULL COMMENT '配置键名,唯一标识',
-  `name` varchar(200) NOT NULL COMMENT '配置名称',
-  `description` text COMMENT '配置描述',
-  `group` varchar(50) NOT NULL COMMENT '配置分组',
-  `type` tinyint(4) NOT NULL COMMENT '配置类型:1布尔值,2整数,3小数,4字符串,5JSON,6数组',
-  `value` text COMMENT '配置值',
-  `default_value` text COMMENT '默认值',
-  `options` text COMMENT '可选项配置(JSON格式)',
-  `validation_rules` varchar(500) COMMENT '验证规则',
-  `is_enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否启用:0禁用,1启用',
-  `is_readonly` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否只读:0可编辑,1只读',
-  `sort_order` int(11) NOT NULL DEFAULT 0 COMMENT '排序权重',
-  `remark` text COMMENT '备注说明',
+  `id` int NOT NULL AUTO_INCREMENT COMMENT '配置ID,主键',
+  `key` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '配置键名,唯一标识',
+  `name` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '配置名称',
+  `description` text COLLATE utf8mb4_unicode_ci COMMENT '配置描述',
+  `group` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '配置分组',
+  `type` tinyint NOT NULL COMMENT '配置类型:1布尔值,2整数,3小数,4字符串,5JSON,6数组',
+  `value` text COLLATE utf8mb4_unicode_ci COMMENT '配置值',
+  `default_value` text COLLATE utf8mb4_unicode_ci COMMENT '默认值',
+  `options` text COLLATE utf8mb4_unicode_ci COMMENT '可选项配置(JSON格式)',
+  `validation_rules` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '验证规则',
+  `is_enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否启用:0禁用,1启用',
+  `is_readonly` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否只读:0可编辑,1只读',
+  `sort_order` int NOT NULL DEFAULT '0' COMMENT '排序权重',
+  `remark` text COLLATE utf8mb4_unicode_ci COMMENT '备注说明',
   `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
   `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
   PRIMARY KEY (`id`),
@@ -22,68 +27,3 @@ CREATE TABLE `kku_mex_configs` (
   KEY `idx_enabled` (`is_enabled`),
   KEY `idx_sort` (`sort_order`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Mex配置表';
-
--- 插入默认配置数据
-INSERT INTO `kku_mex_configs` (`key`, `name`, `description`, `group`, `type`, `value`, `default_value`, `sort_order`, `remark`) VALUES
--- 系统配置
-('system.enabled', '系统启用状态', '控制整个Mex系统是否启用', 'system', 1, '1', '1', 10, '关闭后所有交易功能将不可用'),
-('system.maintenance_mode', '维护模式', '系统维护模式,启用后禁止新订单', 'system', 1, '0', '0', 20, '维护期间只允许查询操作'),
-('system.debug_mode', '调试模式', '启用调试模式,记录详细日志', 'system', 1, '0', '0', 30, '生产环境建议关闭'),
-
--- 交易配置
-('trading.allow_buy', '允许买入', '是否允许用户下买单', 'trading', 1, '1', '1', 100, ''),
-('trading.allow_sell', '允许卖出', '是否允许用户下卖单', 'trading', 1, '1', '1', 110, ''),
-('trading.min_order_amount', '最小订单金额', '单笔订单最小金额限制', 'trading', 3, '0.01', '0.01', 120, ''),
-('trading.max_order_amount', '最大订单金额', '单笔订单最大金额限制', 'trading', 3, '100000.00', '100000.00', 130, ''),
-('trading.min_order_quantity', '最小订单数量', '单笔订单最小数量限制', 'trading', 2, '1', '1', 140, ''),
-('trading.max_order_quantity', '最大订单数量', '单笔订单最大数量限制', 'trading', 2, '10000', '10000', 150, ''),
-
--- 撮合配置
-('matching.enabled', '撮合功能启用', '是否启用自动撮合功能', 'matching', 1, '1', '1', 200, ''),
-('matching.auto_match', '自动撮合', '是否自动执行撮合任务', 'matching', 1, '1', '1', 210, ''),
-('matching.match_interval', '撮合间隔', '自动撮合执行间隔(秒)', 'matching', 2, '30', '30', 220, ''),
-('matching.batch_size', '撮合批次大小', '每次撮合处理的订单数量', 'matching', 2, '100', '100', 230, ''),
-('matching.timeout', '撮合超时时间', '单次撮合操作超时时间(秒)', 'matching', 2, '300', '300', 240, ''),
-
--- 仓库配置
-('warehouse.auto_inject', '自动注入', '是否自动向仓库注入商品', 'warehouse', 1, '0', '0', 300, ''),
-('warehouse.auto_recycle', '自动回收', '是否自动从仓库回收商品', 'warehouse', 1, '0', '0', 310, ''),
-('warehouse.inject_threshold', '注入阈值', '仓库商品数量低于此值时自动注入', 'warehouse', 2, '1000', '1000', 320, ''),
-('warehouse.recycle_threshold', '回收阈值', '仓库商品数量高于此值时自动回收', 'warehouse', 2, '10000', '10000', 330, ''),
-
--- 安全配置
-('security.rate_limit_enabled', '频率限制启用', '是否启用用户操作频率限制', 'security', 1, '1', '1', 400, ''),
-('security.max_orders_per_minute', '每分钟最大订单数', '单用户每分钟最大订单数', 'security', 2, '10', '10', 410, ''),
-('security.max_orders_per_hour', '每小时最大订单数', '单用户每小时最大订单数', 'security', 2, '100', '100', 420, ''),
-('security.ip_whitelist', 'IP白名单', '允许访问的IP地址列表', 'security', 6, '[]', '[]', 430, 'JSON数组格式'),
-('security.suspicious_detection', '异常检测', '是否启用异常交易检测', 'security', 1, '1', '1', 440, ''),
-
--- 性能配置
-('performance.cache_enabled', '缓存启用', '是否启用缓存功能', 'performance', 1, '1', '1', 500, ''),
-('performance.cache_ttl', '缓存过期时间', '缓存数据过期时间(秒)', 'performance', 2, '3600', '3600', 510, ''),
-('performance.queue_enabled', '队列启用', '是否启用队列处理', 'performance', 1, '1', '1', 520, ''),
-('performance.concurrent_limit', '并发限制', '最大并发处理数量', 'performance', 2, '10', '10', 530, ''),
-
--- 通知配置
-('notification.enabled', '通知启用', '是否启用通知功能', 'notification', 1, '1', '1', 600, ''),
-('notification.trade_success', '交易成功通知', '是否发送交易成功通知', 'notification', 1, '1', '1', 610, ''),
-('notification.order_matched', '订单撮合通知', '是否发送订单撮合通知', 'notification', 1, '0', '0', 620, ''),
-('notification.price_alert', '价格预警通知', '是否发送价格异常预警', 'notification', 1, '1', '1', 630, ''),
-
--- 管理员配置
-('admin.operation_log', '操作日志', '是否记录管理员操作日志', 'admin', 1, '1', '1', 700, ''),
-('admin.auto_approve', '自动审批', '管理员操作是否需要审批', 'admin', 1, '0', '0', 710, ''),
-('admin.inject_limit', '注入限制', '管理员单次注入数量限制', 'admin', 2, '100000', '100000', 720, ''),
-('admin.recycle_limit', '回收限制', '管理员单次回收数量限制', 'admin', 2, '100000', '100000', 730, ''),
-
--- 市场配置
-('market.price_protection', '价格保护', '是否启用价格保护机制', 'market', 1, '1', '1', 800, ''),
-('market.volatility_control', '波动控制', '是否启用价格波动控制', 'market', 1, '1', '1', 810, ''),
-('market.max_price_change', '最大价格变动', '单次价格变动最大百分比', 'market', 3, '20.0', '20.0', 820, '单位:百分比'),
-('market.circuit_breaker', '熔断机制', '是否启用市场熔断机制', 'market', 1, '0', '0', 830, ''),
-
--- 定价配置
-('pricing.dynamic_pricing', '动态定价', '是否启用动态定价算法', 'pricing', 1, '0', '0', 900, ''),
-('pricing.price_update_interval', '价格更新间隔', '价格更新间隔时间(分钟)', 'pricing', 2, '60', '60', 910, ''),
-('pricing.volatility_factor', '波动因子', '价格波动计算因子', 'pricing', 3, '1.0', '1.0', 920, ''),
-('pricing.trend_weight', '趋势权重', '价格趋势计算权重', 'pricing', 3, '0.5', '0.5', 930, '取值范围:0-1');

+ 20 - 10
app/Module/Mex/Databases/GenerateSql/mex_daily_price_trends.sql

@@ -1,28 +1,38 @@
 -- ******************************************************************
--- 农贸市场每日价格趋势
--- 执行时间: 2025年06月22日
--- 说明: 记录每日商品价格统计数据,用于价格趋势分析和图表展示
+-- 表 kku_mex_daily_price_trends 的创建SQL
+-- 对应的Model: App\Module\Mex\Models\MexDailyPriceTrend
+-- 警告: 此文件由系统自动生成,禁止修改!
 -- ******************************************************************
 
 CREATE TABLE `kku_mex_daily_price_trends` (
   `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '趋势记录ID,主键',
   `item_id` int NOT NULL COMMENT '商品ID,关联物品表',
-  `currency_type` int NOT NULL DEFAULT 2 COMMENT '币种类型,关联FUND_CURRENCY_TYPE枚举,默认2为钻石',
+  `currency_type` int NOT NULL DEFAULT '2' COMMENT '币种类型,关联FUND_CURRENCY_TYPE枚举,默认2为钻石',
   `trade_date` date NOT NULL COMMENT '交易日期',
   `open_price` decimal(15,5) DEFAULT NULL COMMENT '开盘价(当日第一笔成交价格)',
   `close_price` decimal(15,5) DEFAULT NULL COMMENT '收盘价(当日最后一笔成交价格)',
   `high_price` decimal(15,5) DEFAULT NULL COMMENT '最高价(当日最高成交价格)',
   `low_price` decimal(15,5) DEFAULT NULL COMMENT '最低价(当日最低成交价格)',
   `avg_price` decimal(15,5) DEFAULT NULL COMMENT '平均价(当日成交均价)',
-  `total_volume` int NOT NULL DEFAULT 0 COMMENT '成交量(当日总成交数量)',
+  `buy_open_price` decimal(15,5) DEFAULT NULL COMMENT '买入开盘价(当日第一笔买入成交价格)',
+  `buy_close_price` decimal(15,5) DEFAULT NULL COMMENT '买入收盘价(当日最后一笔买入成交价格)',
+  `buy_high_price` decimal(15,5) DEFAULT NULL COMMENT '买入最高价(当日买入最高成交价格)',
+  `buy_low_price` decimal(15,5) DEFAULT NULL COMMENT '买入最低价(当日买入最低成交价格)',
+  `buy_avg_price` decimal(15,5) DEFAULT NULL COMMENT '买入平均价(当日买入成交均价)',
+  `sell_open_price` decimal(15,5) DEFAULT NULL COMMENT '卖出开盘价(当日第一笔卖出成交价格)',
+  `sell_close_price` decimal(15,5) DEFAULT NULL COMMENT '卖出收盘价(当日最后一笔卖出成交价格)',
+  `sell_high_price` decimal(15,5) DEFAULT NULL COMMENT '卖出最高价(当日卖出最高成交价格)',
+  `sell_low_price` decimal(15,5) DEFAULT NULL COMMENT '卖出最低价(当日卖出最低成交价格)',
+  `sell_avg_price` decimal(15,5) DEFAULT NULL COMMENT '卖出平均价(当日卖出成交均价)',
+  `total_volume` int NOT NULL DEFAULT '0' COMMENT '成交量(当日总成交数量)',
   `total_amount` decimal(20,5) NOT NULL DEFAULT '0.00000' COMMENT '成交额(当日总成交金额)',
-  `transaction_count` int NOT NULL DEFAULT 0 COMMENT '成交笔数(当日总成交次数)',
-  `buy_volume` int NOT NULL DEFAULT 0 COMMENT '买入量(用户买入总数量)',
-  `sell_volume` int NOT NULL DEFAULT 0 COMMENT '卖出量(用户卖出总数量)',
+  `transaction_count` int NOT NULL DEFAULT '0' COMMENT '成交笔数(当日总成交次数)',
+  `buy_volume` int NOT NULL DEFAULT '0' COMMENT '买入量(用户买入总数量)',
+  `sell_volume` int NOT NULL DEFAULT '0' COMMENT '卖出量(用户卖出总数量)',
   `buy_amount` decimal(20,5) NOT NULL DEFAULT '0.00000' COMMENT '买入额(用户买入总金额)',
   `sell_amount` decimal(20,5) NOT NULL DEFAULT '0.00000' COMMENT '卖出额(用户卖出总金额)',
-  `admin_inject_volume` int NOT NULL DEFAULT 0 COMMENT '管理员注入量',
-  `admin_recycle_volume` int NOT NULL DEFAULT 0 COMMENT '管理员回收量',
+  `admin_inject_volume` int NOT NULL DEFAULT '0' COMMENT '管理员注入量',
+  `admin_recycle_volume` int NOT NULL DEFAULT '0' COMMENT '管理员回收量',
   `admin_inject_amount` decimal(20,5) NOT NULL DEFAULT '0.00000' COMMENT '管理员注入金额',
   `admin_recycle_amount` decimal(20,5) NOT NULL DEFAULT '0.00000' COMMENT '管理员回收金额',
   `price_change` decimal(15,5) DEFAULT NULL COMMENT '价格变化(相对前一日收盘价)',

+ 24 - 0
app/Module/Mex/Databases/GenerateSql/mex_match_logs.sql

@@ -0,0 +1,24 @@
+-- ******************************************************************
+-- 表 kku_mex_match_logs 的创建SQL
+-- 对应的Model: App\Module\Mex\Models\MexMatchLog
+-- 警告: 此文件由系统自动生成,禁止修改!
+-- ******************************************************************
+
+CREATE TABLE `kku_mex_match_logs` (
+  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '撮合日志ID,主键',
+  `match_type` enum('USER_BUY','USER_SELL') COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '撮合类型:USER_BUY用户买入撮合,USER_SELL用户卖出撮合',
+  `item_id` int NOT NULL COMMENT '商品ID,关联物品表',
+  `batch_size` int NOT NULL DEFAULT '100' COMMENT '批处理大小',
+  `matched_orders` int NOT NULL DEFAULT '0' COMMENT '成功撮合的订单数',
+  `total_amount` decimal(20,5) NOT NULL DEFAULT '0.00000' COMMENT '撮合总金额',
+  `success` tinyint(1) NOT NULL DEFAULT '0' COMMENT '撮合是否成功:0失败,1成功',
+  `message` text COLLATE utf8mb4_unicode_ci COMMENT '撮合结果消息',
+  `execution_time_ms` int DEFAULT NULL COMMENT '执行时间(毫秒)',
+  `error_message` text COLLATE utf8mb4_unicode_ci COMMENT '错误消息(失败时记录)',
+  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '撮合时间',
+  PRIMARY KEY (`id`),
+  KEY `idx_match_type` (`match_type`),
+  KEY `idx_item_id` (`item_id`),
+  KEY `idx_created_at` (`created_at`),
+  KEY `idx_success` (`success`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='农贸市场撮合日志表';

+ 1 - 0
app/Module/Mex/Databases/GenerateSql/mex_orders.sql

@@ -21,6 +21,7 @@ CREATE TABLE `kku_mex_orders` (
   `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
   `completed_at` timestamp NULL DEFAULT NULL COMMENT '完成时间',
   `failed_reason` text COLLATE utf8mb4_unicode_ci COMMENT '失败原因',
+  `last_match_failure_reason` text COLLATE utf8mb4_unicode_ci COMMENT '最后无法成交原因,记录撮合过程中无法成交的具体原因',
   PRIMARY KEY (`id`) USING BTREE,
   KEY `idx_user_id` (`user_id`) USING BTREE,
   KEY `idx_item_id` (`item_id`) USING BTREE,

+ 6 - 6
app/Module/Mex/Databases/GenerateSql/mex_price_adjustments.sql

@@ -1,7 +1,7 @@
 -- ******************************************************************
--- 农贸市场价格调整记录
--- 执行时间: 2025年06月22日
--- 说明: 记录管理员对价格配置的调整历史,便于追踪价格变化
+-- 表 kku_mex_price_adjustments 的创建SQL
+-- 对应的Model: App\Module\Mex\Models\MexPriceAdjustment
+-- 警告: 此文件由系统自动生成,禁止修改!
 -- ******************************************************************
 
 CREATE TABLE `kku_mex_price_adjustments` (
@@ -9,7 +9,7 @@ CREATE TABLE `kku_mex_price_adjustments` (
   `price_config_id` bigint unsigned NOT NULL COMMENT '价格配置ID,关联mex_price_configs表',
   `item_id` int NOT NULL COMMENT '商品ID,关联物品表',
   `admin_user_id` bigint NOT NULL COMMENT '操作管理员用户ID',
-  `adjustment_type` enum('MIN_PRICE','MAX_PRICE','PROTECTION_THRESHOLD','STATUS','BATCH') COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调整类型:MIN_PRICE最低价,MAX_PRICE最高价,PROTECTION_THRESHOLD保护阈值,STATUS启用状态,BATCH批量调整',
+  `adjustment_type` enum('MIN_PRICE','MAX_PRICE','PROTECTION_THRESHOLD','STATUS','BATCH') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '调整类型:MIN_PRICE最低价,MAX_PRICE最高价,PROTECTION_THRESHOLD保护阈值,STATUS启用状态,BATCH批量调整',
   `old_min_price` decimal(15,5) DEFAULT NULL COMMENT '调整前最低价',
   `new_min_price` decimal(15,5) DEFAULT NULL COMMENT '调整后最低价',
   `old_max_price` decimal(15,5) DEFAULT NULL COMMENT '调整前最高价',
@@ -18,8 +18,8 @@ CREATE TABLE `kku_mex_price_adjustments` (
   `new_protection_threshold` int DEFAULT NULL COMMENT '调整后保护阈值',
   `old_is_enabled` tinyint(1) DEFAULT NULL COMMENT '调整前启用状态',
   `new_is_enabled` tinyint(1) DEFAULT NULL COMMENT '调整后启用状态',
-  `adjustment_reason` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '调整原因',
-  `market_impact_note` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '市场影响说明',
+  `adjustment_reason` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '调整原因',
+  `market_impact_note` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '市场影响说明',
   `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '调整时间',
   PRIMARY KEY (`id`) USING BTREE,
   KEY `idx_price_config_id` (`price_config_id`) USING BTREE COMMENT '价格配置ID索引',

+ 7 - 7
app/Module/Mex/Models/MexConfig.php

@@ -16,15 +16,15 @@ use Illuminate\Database\Eloquent\Builder;
  * @property  string  $name  配置名称
  * @property  string  $description  配置描述
  * @property  \App\Module\Mex\Enums\MexConfigGroup  $group  配置分组
- * @property  \App\Module\Mex\Enums\MexConfigType  $type  配置类型
+ * @property  \App\Module\Mex\Enums\MexConfigType  $type  配置类型:1布尔值,2整数,3小数,4字符串,5JSON,6数组
  * @property  string  $value  配置值
- * @property  string|null  $default_value  默认值
- * @property  string|null  $options  可选项配置(JSON格式)
- * @property  string|null  $validation_rules  验证规则
- * @property  bool  $is_enabled  是否启用
- * @property  bool  $is_readonly  是否只读
+ * @property  string  $default_value  默认值
+ * @property  array  $options  可选项配置(JSON格式)
+ * @property  string  $validation_rules  验证规则
+ * @property  bool  $is_enabled  是否启用:0禁用,1启用
+ * @property  bool  $is_readonly  是否只读:0可编辑,1只读
  * @property  int  $sort_order  排序权重
- * @property  string|null  $remark  备注说明
+ * @property  string  $remark  备注说明
  * @property  \Carbon\Carbon  $created_at  创建时间
  * @property  \Carbon\Carbon  $updated_at  更新时间
  * field end

+ 11 - 1
app/Module/Mex/Models/MexDailyPriceTrend.php

@@ -14,12 +14,22 @@ use UCore\ModelCore;
  * @property  int  $id  趋势记录ID,主键
  * @property  int  $item_id  商品ID,关联物品表
  * @property  \App\Module\Fund\Enums\FUND_CURRENCY_TYPE  $currency_type  币种类型,关联FUND_CURRENCY_TYPE枚举,默认2为钻石
- * @property  string  $trade_date  交易日期
+ * @property  \Carbon\Carbon  $trade_date  交易日期
  * @property  float  $open_price  开盘价(当日第一笔成交价格)
  * @property  float  $close_price  收盘价(当日最后一笔成交价格)
  * @property  float  $high_price  最高价(当日最高成交价格)
  * @property  float  $low_price  最低价(当日最低成交价格)
  * @property  float  $avg_price  平均价(当日成交均价)
+ * @property  float  $buy_open_price  买入开盘价(当日第一笔买入成交价格)
+ * @property  float  $buy_close_price  买入收盘价(当日最后一笔买入成交价格)
+ * @property  float  $buy_high_price  买入最高价(当日买入最高成交价格)
+ * @property  float  $buy_low_price  买入最低价(当日买入最低成交价格)
+ * @property  float  $buy_avg_price  买入平均价(当日买入成交均价)
+ * @property  float  $sell_open_price  卖出开盘价(当日第一笔卖出成交价格)
+ * @property  float  $sell_close_price  卖出收盘价(当日最后一笔卖出成交价格)
+ * @property  float  $sell_high_price  卖出最高价(当日卖出最高成交价格)
+ * @property  float  $sell_low_price  卖出最低价(当日卖出最低成交价格)
+ * @property  float  $sell_avg_price  卖出平均价(当日卖出成交均价)
  * @property  int  $total_volume  成交量(当日总成交数量)
  * @property  float  $total_amount  成交额(当日总成交金额)
  * @property  int  $transaction_count  成交笔数(当日总成交次数)

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

@@ -36,7 +36,7 @@ class MexOrder extends ModelCore
 {
     protected $table = 'mex_orders';
 
-    // attrlist start
+    // attrlist start 
     protected $fillable = [
         'id',
         'user_id',

+ 1 - 0
app/Module/Transfer/Databases/GenerateSql/transfer_orders.sql

@@ -30,6 +30,7 @@ CREATE TABLE `kku_transfer_orders` (
   `fee_rate` decimal(5,4) DEFAULT '0.0000' COMMENT '使用的手续费率',
   `fee_amount` decimal(15,4) DEFAULT '0.0000' COMMENT '手续费金额',
   `actual_amount` decimal(15,4) DEFAULT '0.0000' COMMENT '实际到账金额(扣除手续费后)',
+  `totle_amount` decimal(15,4) DEFAULT '0.0000' COMMENT '支付扣除金额',
   PRIMARY KEY (`id`),
   UNIQUE KEY `uk_out_order` (`out_id`,`out_order_id`),
   KEY `idx_transfer_app_id` (`transfer_app_id`),

+ 54 - 35
app/Module/Transfer/Events/FeeCalculatedEvent.php

@@ -13,6 +13,7 @@ use Illuminate\Queue\SerializesModels;
  */
 class FeeCalculatedEvent
 {
+
     use Dispatchable, SerializesModels;
 
     /**
@@ -45,6 +46,11 @@ class FeeCalculatedEvent
      */
     public string $actualAmount;
 
+    /**
+     * 最终的实际支付金额
+     */
+    public string $totleAmount;
+
     /**
      * 是否被修改过
      */
@@ -74,6 +80,7 @@ class FeeCalculatedEvent
      * @param float $feeRate 手续费率
      * @param string $feeAmount 手续费金额
      * @param string $actualAmount 实际到账金额
+     * @param string $totleAmount 付款方支付金额
      * @param bool $isModified 是否被修改过
      * @param string|null $modificationReason 修改原因
      * @param string|null $modifiedBy 修改者标识
@@ -81,26 +88,29 @@ class FeeCalculatedEvent
      */
     public function __construct(
         TransferApp $app,
-        string $amount,
-        string $type,
-        float $feeRate,
-        string $feeAmount,
-        string $actualAmount,
-        bool $isModified = false,
-        ?string $modificationReason = null,
-        ?string $modifiedBy = null,
-        array $context = []
-    ) {
-        $this->app = $app;
-        $this->amount = $amount;
-        $this->type = $type;
-        $this->feeRate = $feeRate;
-        $this->feeAmount = $feeAmount;
-        $this->actualAmount = $actualAmount;
-        $this->isModified = $isModified;
+        string      $amount,
+        string      $type,
+        float       $feeRate,
+        string      $feeAmount,
+        string      $actualAmount,
+        string      $totleAmount,
+        bool        $isModified = false,
+        ?string     $modificationReason = null,
+        ?string     $modifiedBy = null,
+        array       $context = []
+    )
+    {
+        $this->app                = $app;
+        $this->amount             = $amount;
+        $this->type               = $type;
+        $this->feeRate            = $feeRate;
+        $this->feeAmount          = $feeAmount;
+        $this->actualAmount       = $actualAmount;
+        $this->isModified         = $isModified;
+        $this->totleAmount        = $totleAmount;
         $this->modificationReason = $modificationReason;
-        $this->modifiedBy = $modifiedBy;
-        $this->context = $context;
+        $this->modifiedBy         = $modifiedBy;
+        $this->context            = $context;
     }
 
     /**
@@ -111,17 +121,28 @@ class FeeCalculatedEvent
      */
     public static function fromCalculatingEvent(FeeCalculatingEvent $calculatingEvent): static
     {
+        if ($calculatingEvent->type == 'in') {
+            // 转入
+            $actualAmount = bcsub($calculatingEvent->amount, $calculatingEvent->feeAmount, 10);
+            $totleAmout   = $calculatingEvent->amount;
+
+        } else {
+            $actualAmount = $calculatingEvent->amount;
+            $totleAmout   = bcadd($calculatingEvent->amount, $calculatingEvent->feeAmount, 10);
+        }
+
         return new static(
-            app: $calculatingEvent->app,
-            amount: $calculatingEvent->amount,
-            type: $calculatingEvent->type,
-            feeRate: $calculatingEvent->feeRate,
-            feeAmount: $calculatingEvent->feeAmount,
-            actualAmount: $calculatingEvent->actualAmount,
-            isModified: $calculatingEvent->isModified,
+            app:                $calculatingEvent->app,
+            amount:             $calculatingEvent->amount,
+            type:               $calculatingEvent->type,
+            feeRate:            bcdiv($calculatingEvent->amount, $calculatingEvent->feeAmount, 10),
+            feeAmount:          $calculatingEvent->feeAmount,
+            actualAmount:       $actualAmount,
+            totleAmount:        $totleAmout,
+            isModified:         $calculatingEvent->isModified,
             modificationReason: $calculatingEvent->modificationReason,
-            modifiedBy: $calculatingEvent->modifiedBy,
-            context: $calculatingEvent->context
+            modifiedBy:         $calculatingEvent->modifiedBy,
+            context:            $calculatingEvent->context
         );
     }
 
@@ -133,12 +154,12 @@ class FeeCalculatedEvent
     public function getResult(): array
     {
         return [
-            'fee_rate' => $this->feeRate,
-            'fee_amount' => $this->feeAmount,
-            'actual_amount' => $this->actualAmount,
-            'is_modified' => $this->isModified,
+            'fee_rate'            => $this->feeRate,
+            'fee_amount'          => $this->feeAmount,
+            'actual_amount'       => $this->actualAmount,
+            'is_modified'         => $this->isModified,
             'modification_reason' => $this->modificationReason,
-            'modified_by' => $this->modifiedBy,
+            'modified_by'         => $this->modifiedBy,
         ];
     }
 
@@ -175,6 +196,4 @@ class FeeCalculatedEvent
     }
 
 
-
-
 }

+ 12 - 27
app/Module/Transfer/Events/FeeCalculatingEvent.php

@@ -8,7 +8,7 @@ use Illuminate\Queue\SerializesModels;
 
 /**
  * 手续费计算事件
- * 
+ *
  * 在计算手续费时触发,允许其他模块修改手续费数额
  */
 class FeeCalculatingEvent
@@ -30,20 +30,11 @@ class FeeCalculatingEvent
      */
     public string $type;
 
-    /**
-     * 计算出的手续费率
-     */
-    public float $feeRate;
-
     /**
      * 计算出的手续费金额
      */
     public string $feeAmount;
 
-    /**
-     * 实际到账金额
-     */
-    public string $actualAmount;
 
     /**
      * 是否被修改过
@@ -71,26 +62,22 @@ class FeeCalculatingEvent
      * @param TransferApp $app 划转应用
      * @param string $amount 原始金额
      * @param string $type 手续费类型
-     * @param float $feeRate 手续费率
      * @param string $feeAmount 手续费金额
-     * @param string $actualAmount 实际到账金额
      * @param array $context 额外的上下文数据
      */
     public function __construct(
         TransferApp $app,
         string $amount,
         string $type,
-        float $feeRate,
+
         string $feeAmount,
-        string $actualAmount,
+
         array $context = []
     ) {
         $this->app = $app;
         $this->amount = $amount;
         $this->type = $type;
-        $this->feeRate = $feeRate;
         $this->feeAmount = $feeAmount;
-        $this->actualAmount = $actualAmount;
         $this->context = $context;
     }
 
@@ -105,7 +92,7 @@ class FeeCalculatingEvent
     public function modifyFeeAmount(string $newFeeAmount, string $reason, string $modifiedBy): void
     {
         $this->feeAmount = $newFeeAmount;
-        $this->actualAmount = bcsub($this->amount, $newFeeAmount, 4);
+
         $this->isModified = true;
         $this->modificationReason = $reason;
         $this->modifiedBy = $modifiedBy;
@@ -121,9 +108,7 @@ class FeeCalculatingEvent
      */
     public function modifyFeeRate(float $newFeeRate, string $reason, string $modifiedBy): void
     {
-        $this->feeRate = $newFeeRate;
         $this->feeAmount = bcmul($this->amount, (string)$newFeeRate, 4);
-        $this->actualAmount = bcsub($this->amount, $this->feeAmount, 4);
         $this->isModified = true;
         $this->modificationReason = $reason;
         $this->modifiedBy = $modifiedBy;
@@ -138,9 +123,9 @@ class FeeCalculatingEvent
      */
     public function setFree(string $reason, string $modifiedBy): void
     {
-        $this->feeRate = 0.0;
+
         $this->feeAmount = '0.0000';
-        $this->actualAmount = $this->amount;
+
         $this->isModified = true;
         $this->modificationReason = $reason;
         $this->modifiedBy = $modifiedBy;
@@ -157,7 +142,7 @@ class FeeCalculatingEvent
     public function addFee(string $additionalFee, string $reason, string $modifiedBy): void
     {
         $this->feeAmount = bcadd($this->feeAmount, $additionalFee, 4);
-        $this->actualAmount = bcsub($this->amount, $this->feeAmount, 4);
+
         $this->isModified = true;
         $this->modificationReason = $reason;
         $this->modifiedBy = $modifiedBy;
@@ -174,14 +159,14 @@ class FeeCalculatingEvent
     public function reduceFee(string $discountFee, string $reason, string $modifiedBy): void
     {
         $newFeeAmount = bcsub($this->feeAmount, $discountFee, 4);
-        
+
         // 确保手续费不为负数
         if (bccomp($newFeeAmount, '0', 4) < 0) {
             $newFeeAmount = '0.0000';
         }
-        
+
         $this->feeAmount = $newFeeAmount;
-        $this->actualAmount = bcsub($this->amount, $this->feeAmount, 4);
+
         $this->isModified = true;
         $this->modificationReason = $reason;
         $this->modifiedBy = $modifiedBy;
@@ -195,9 +180,9 @@ class FeeCalculatingEvent
     public function getResult(): array
     {
         return [
-            'fee_rate' => $this->feeRate,
+
             'fee_amount' => $this->feeAmount,
-            'actual_amount' => $this->actualAmount,
+
             'is_modified' => $this->isModified,
             'modification_reason' => $this->modificationReason,
             'modified_by' => $this->modifiedBy,

+ 151 - 127
app/Module/Transfer/Logics/TransferLogic.php

@@ -4,8 +4,10 @@ namespace App\Module\Transfer\Logics;
 
 use App\Module\Transfer\Enums\TransferStatus;
 use App\Module\Transfer\Enums\TransferType;
+use App\Module\Transfer\Events\FeeCalculatedEvent;
 use App\Module\Transfer\Models\TransferApp;
 use App\Module\Transfer\Models\TransferOrder;
+use App\Module\Transfer\Services\FeeService;
 use App\Module\Transfer\Validations\TransferInValidation;
 use App\Module\Transfer\Validations\TransferOutValidation;
 use App\Module\Fund\Services\FundService;
@@ -19,6 +21,7 @@ use Illuminate\Support\Facades\Log;
  */
 class TransferLogic
 {
+
     /**
      * 创建转出订单(对外接口)
      *
@@ -34,24 +37,25 @@ class TransferLogic
      * @throws \Exception
      */
     public static function createTransferOut(
-        int $transferAppId,
-        int $userId,
-        string $amount,
-        string $password,
+        int     $transferAppId,
+        int     $userId,
+        string  $amount,
+        string  $password,
         ?string $googleCode = null,
         ?string $outUserId = null,
         ?string $remark = null,
-        array $callbackData = []
-    ): TransferOrder {
+        array   $callbackData = []
+    ): TransferOrder
+    {
         $data = [
             'transfer_app_id' => $transferAppId,
-            'user_id' => $userId,
-            'amount' => $amount,
-            'password' => $password,
-            'google_code' => $googleCode,
-            'out_user_id' => $outUserId,
-            'remark' => $remark,
-            'callback_data' => $callbackData,
+            'user_id'         => $userId,
+            'amount'          => $amount,
+            'password'        => $password,
+            'google_code'     => $googleCode,
+            'out_user_id'     => $outUserId,
+            'remark'          => $remark,
+            'callback_data'   => $callbackData,
         ];
 
         return self::createTransferOutFromArray($data);
@@ -59,6 +63,7 @@ class TransferLogic
 
     /**
      * 创建第三方应用转出订单(跳过密码验证)
+     * 我 =》 三方
      *
      * @param int $transferAppId 划转应用ID
      * @param int $userId 用户ID
@@ -70,20 +75,21 @@ class TransferLogic
      * @throws \Exception
      */
     public static function createTransferOutForThirdParty(
-        int $transferAppId,
-        int $userId,
-        string $amount,
+        int     $transferAppId,
+        int     $userId,
+        string  $amount,
         ?string $outUserId = null,
         ?string $remark = null,
-        array $callbackData = []
-    ): TransferOrder {
+        array   $callbackData = []
+    ): TransferOrder
+    {
         $data = [
             'transfer_app_id' => $transferAppId,
-            'user_id' => $userId,
-            'amount' => $amount,
-            'out_user_id' => $outUserId,
-            'remark' => $remark,
-            'callback_data' => $callbackData,
+            'user_id'         => $userId,
+            'amount'          => $amount,
+            'out_user_id'     => $outUserId,
+            'remark'          => $remark,
+            'callback_data'   => $callbackData,
         ];
 
         return self::createTransferOutFromArrayForThirdParty($data);
@@ -91,7 +97,7 @@ class TransferLogic
 
     /**
      * 创建第三方应用转出订单(内部实现,跳过密码验证)
-     *
+     * 我 =》 三方
      * 注意:第三方应用传入的金额是外部金额,需要转换为内部金额进行处理
      *
      * @param array $data 订单数据
@@ -110,13 +116,13 @@ class TransferLogic
         }
 
         // 验证汇率是否合理
-        if (bccomp((string) $app->exchange_rate, '0', 10) <= 0) {
+        if (bccomp((string)$app->exchange_rate, '0', 10) <= 0) {
             throw new \Exception('汇率配置错误:汇率必须大于0');
         }
 
         // 第三方应用金额处理:传入的是外部金额,需要转换为内部金额
-        $outAmount = (string) $data['amount']; // 外部金额(第三方系统金额)
-        $amount = bcmul($outAmount, (string) $app->exchange_rate, 10); // 内部金额 = 外部金额 × 汇率
+        $outAmount = (string)$data['amount'];                            // 外部金额(第三方系统金额)
+        $amount    = bcmul($outAmount, (string)$app->exchange_rate, 10); // 内部金额 = 外部金额 × 汇率
 
         // 验证外部金额是否合理
         if (bccomp($outAmount, '0', 10) <= 0) {
@@ -129,7 +135,7 @@ class TransferLogic
         }
 
         // 修改验证数据:将外部金额替换为内部金额,这样验证器就能正确验证余额
-        $validationData = $data;
+        $validationData           = $data;
         $validationData['amount'] = $amount; // 传递内部金额给验证器
 
         // 使用第三方应用专用验证类(跳过密码验证)
@@ -137,31 +143,35 @@ class TransferLogic
         $validation->validated();
 
         // 计算手续费(基于内部金额)
-        $feeInfo = $app->calculateOutFee($amount, ['user_id' => $data['user_id']]);
+        $FeeCalculatedEvent = \App\Module\Transfer\Services\FeeService::calculateOutFee($app, $amount, [ 'user_id' => $data['user_id'] ]);
 
         // 生成外部订单ID
         $outOrderId = self::generateOutOrderId('OUT');
 
         // 创建订单
+        /**
+         * @var TransferOrder $order
+         */
         $order = TransferOrder::create([
-            'transfer_app_id' => $app->id,
-            'out_id' => $app->out_id2 ?? 0,
-            'out_order_id' => $outOrderId,
-            'out_user_id' => $data['out_user_id'] ?? null,
-            'user_id' => $data['user_id'],
-            'currency_id' => $app->currency_id,
-            'fund_id' => $app->fund_id,
-            'type' => TransferType::OUT,
-            'status' => TransferStatus::CREATED,
-            'out_amount' => $outAmount,
-            'amount' => $amount,
-            'exchange_rate' => $app->exchange_rate,
-            'fee_rate' => $feeInfo['fee_rate'],
-            'fee_amount' => $feeInfo['fee_amount'],
-            'actual_amount' => $feeInfo['actual_amount'],
-            'callback_data' => $data['callback_data'] ?? [],
-            'remark' => $data['remark'] ?? null,
-        ]);
+                                           'transfer_app_id' => $app->id,
+                                           'out_id'          => $app->out_id2 ?? 0,
+                                           'out_order_id'    => $outOrderId,
+                                           'out_user_id'     => $data['out_user_id'] ?? null,
+                                           'user_id'         => $data['user_id'],
+                                           'currency_id'     => $app->currency_id,
+                                           'fund_id'         => $app->fund_id,
+                                           'type'            => TransferType::OUT,
+                                           'status'          => TransferStatus::CREATED,
+                                           'out_amount'      => $outAmount,
+                                           'amount'          => $FeeCalculatedEvent->amount,
+                                           'exchange_rate'   => $app->exchange_rate,
+                                           'fee_rate'        => $FeeCalculatedEvent->feeRate,
+                                           'fee_amount'      => $FeeCalculatedEvent->feeAmount,
+                                           'actual_amount'   => $FeeCalculatedEvent->actualAmount,
+                                           'totle_amount'    => $FeeCalculatedEvent->totleAmount,
+                                           'callback_data'   => $data['callback_data'] ?? [],
+                                           'remark'          => $data['remark'] ?? null,
+                                       ]);
 
         // 验证fund_to_uid必须存在
         if (empty($app->fund_to_uid)) {
@@ -207,16 +217,16 @@ class TransferLogic
 
             if (is_string($feeTradeResult)) {
                 Log::warning('Transfer out fee collection failed', [
-                    'order_id' => $order->id,
-                    'fee_amount' => $order->fee_amount,
+                    'order_id'        => $order->id,
+                    'fee_amount'      => $order->fee_amount,
                     'fee_account_uid' => $feeAccountUid,
-                    'error' => $feeTradeResult
+                    'error'           => $feeTradeResult
                 ]);
             } else {
                 Log::info('Transfer out fee collected successfully', [
-                    'order_id' => $order->id,
-                    'fee_amount' => $order->fee_amount,
-                    'fee_account_uid' => $feeAccountUid,
+                    'order_id'           => $order->id,
+                    'fee_amount'         => $order->fee_amount,
+                    'fee_account_uid'    => $feeAccountUid,
                     'configured_account' => $app->fee_account_uid
                 ]);
             }
@@ -241,7 +251,7 @@ class TransferLogic
 
     /**
      * 创建转出订单(内部实现)
-     *
+     * 我 =》 三方
      * 处理流程:
      * 1. 验证请求数据
      * 2. 获取应用配置
@@ -266,10 +276,10 @@ class TransferLogic
         }
 
         // 计算金额(转出:内部金额转换为外部金额)
-        $amount = (string) $data['amount']; // 内部金额
+        $amount = (string)$data['amount']; // 内部金额
 
         // 验证汇率是否合理
-        if (bccomp((string) $app->exchange_rate, '0', 10) <= 0) {
+        if (bccomp((string)$app->exchange_rate, '0', 10) <= 0) {
             throw new \Exception('汇率配置错误:汇率必须大于0');
         }
 
@@ -278,7 +288,7 @@ class TransferLogic
             throw new \Exception('转出金额必须大于0');
         }
 
-        $outAmount = bcdiv($amount, (string) $app->exchange_rate, 10); // 外部金额 = 内部金额 ÷ 汇率
+        $outAmount = bcdiv($amount, (string)$app->exchange_rate, 10); // 外部金额 = 内部金额 ÷ 汇率
 
         // 验证计算结果是否合理
         if (bccomp($outAmount, '0', 10) <= 0) {
@@ -286,31 +296,31 @@ class TransferLogic
         }
 
         // 计算手续费
-        $feeInfo = $app->calculateOutFee($amount, ['user_id' => $data['user_id']]);
+        $feeInfo = $app->calculateOutFee($amount, [ 'user_id' => $data['user_id'] ]);
 
         // 生成外部订单ID
         $outOrderId = self::generateOutOrderId('OUT');
 
         // 创建订单
         $order = TransferOrder::create([
-            'transfer_app_id' => $app->id,
-            'out_id' => $app->out_id2 ?? 0,
-            'out_order_id' => $outOrderId,
-            'out_user_id' => $data['out_user_id'] ?? null,
-            'user_id' => $data['user_id'],
-            'currency_id' => $app->currency_id,
-            'fund_id' => $app->fund_id,
-            'type' => TransferType::OUT,
-            'status' => TransferStatus::CREATED,
-            'out_amount' => $outAmount,
-            'amount' => $amount,
-            'exchange_rate' => $app->exchange_rate,
-            'fee_rate' => $feeInfo['fee_rate'],
-            'fee_amount' => $feeInfo['fee_amount'],
-            'actual_amount' => $feeInfo['actual_amount'],
-            'callback_data' => $data['callback_data'] ?? [],
-            'remark' => $data['remark'] ?? null,
-        ]);
+                                           'transfer_app_id' => $app->id,
+                                           'out_id'          => $app->out_id2 ?? 0,
+                                           'out_order_id'    => $outOrderId,
+                                           'out_user_id'     => $data['out_user_id'] ?? null,
+                                           'user_id'         => $data['user_id'],
+                                           'currency_id'     => $app->currency_id,
+                                           'fund_id'         => $app->fund_id,
+                                           'type'            => TransferType::OUT,
+                                           'status'          => TransferStatus::CREATED,
+                                           'out_amount'      => $outAmount,
+                                           'amount'          => $amount,
+                                           'exchange_rate'   => $app->exchange_rate,
+                                           'fee_rate'        => $feeInfo['fee_rate'],
+                                           'fee_amount'      => $feeInfo['fee_amount'],
+                                           'actual_amount'   => $feeInfo['actual_amount'],
+                                           'callback_data'   => $data['callback_data'] ?? [],
+                                           'remark'          => $data['remark'] ?? null,
+                                       ]);
 
         // 验证fund_to_uid必须存在
         if (empty($app->fund_to_uid)) {
@@ -327,7 +337,7 @@ class TransferLogic
 
         // 预先验证用户余额是否充足(转出金额 + 手续费)
         $userFundService = new FundService($data['user_id'], $app->fund_id);
-        $totalRequired = bcadd($order->amount, $order->fee_amount, 10);
+        $totalRequired   = bcadd($order->amount, $order->fee_amount, 10);
         if (bccomp((string)$userFundService->balance(), $totalRequired, 10) < 0) {
             $order->updateStatus(TransferStatus::FAILED, '用户余额不足');
             throw new \Exception('用户余额不足');
@@ -357,16 +367,16 @@ class TransferLogic
 
             if (is_string($feeTradeResult)) {
                 Log::warning('Transfer out fee collection failed', [
-                    'order_id' => $order->id,
-                    'fee_amount' => $order->fee_amount,
+                    'order_id'        => $order->id,
+                    'fee_amount'      => $order->fee_amount,
                     'fee_account_uid' => $feeAccountUid,
-                    'error' => $feeTradeResult
+                    'error'           => $feeTradeResult
                 ]);
             } else {
                 Log::info('Transfer out fee collected successfully', [
-                    'order_id' => $order->id,
-                    'fee_amount' => $order->fee_amount,
-                    'fee_account_uid' => $feeAccountUid,
+                    'order_id'           => $order->id,
+                    'fee_amount'         => $order->fee_amount,
+                    'fee_account_uid'    => $feeAccountUid,
                     'configured_account' => $app->fee_account_uid
                 ]);
             }
@@ -391,6 +401,7 @@ class TransferLogic
 
     /**
      * 创建转入订单(对外接口)
+     * 三方 =》 我
      *
      * @param int $transferAppId 划转应用ID
      * @param int $userId 用户ID
@@ -403,30 +414,31 @@ class TransferLogic
      * @throws \Exception
      */
     public static function createTransferIn(
-        int $transferAppId,
-        int $userId,
-        string $businessId,
-        string $amount,
+        int     $transferAppId,
+        int     $userId,
+        string  $businessId,
+        string  $amount,
         ?string $outUserId = null,
         ?string $remark = null,
-        array $callbackData = []
-    ): TransferOrder {
+        array   $callbackData = []
+    ): TransferOrder
+    {
         $data = [
             'transfer_app_id' => $transferAppId,
-            'user_id' => $userId,
-            'business_id' => $businessId,
-            'amount' => $amount,
-            'out_user_id' => $outUserId,
-            'remark' => $remark,
-            'callback_data' => $callbackData,
+            'user_id'         => $userId,
+            'business_id'     => $businessId,
+            'amount'          => $amount,
+            'out_user_id'     => $outUserId,
+            'remark'          => $remark,
+            'callback_data'   => $callbackData,
         ];
 
-        return self::createTransferInFromArray($data);
+        return self::createTransferInFromArray($data, $userId);
     }
 
     /**
      * 创建转入订单(内部实现)
-     *
+     * 三方 =》 我
      * 处理流程:
      * 1. 验证请求数据
      * 2. 获取应用配置
@@ -438,13 +450,16 @@ class TransferLogic
      * @return TransferOrder
      * @throws \Exception
      */
-    public static function createTransferInFromArray(array $data): TransferOrder
+    public static function createTransferInFromArray(array $data, $user_id): TransferOrder
     {
         // 验证请求数据
         $validation = new TransferInValidation($data);
         $validation->validated();
 
         // 获取应用配置
+        /**
+         * @var TransferApp $app
+         */
         $app = TransferApp::findOrFail($data['transfer_app_id']);
         if (!$app->is_enabled) {
             throw new \Exception('应用已禁用');
@@ -460,32 +475,39 @@ class TransferLogic
         }
 
         // 计算金额(转入:外部金额转换为内部金额)
-        $outAmount = (string) $data['amount']; // 外部金额
-        $amount = bcmul($outAmount, (string) $app->exchange_rate, 10); // 内部金额 = 外部金额 × 汇率
+        $outAmount = (string)$data['amount'];                            // 外部金额
+        $amount    = bcmul($outAmount, (string)$app->exchange_rate, 10); // 内部金额 = 外部金额 × 汇率
 
         // 计算手续费
-        $feeInfo = $app->calculateInFee($amount);
 
+        $feeInfo = FeeService::calculateInFee($app, $amount, [
+            'user_id' => $user_id
+        ]);
         // 创建订单
+        /**
+         * @var TransferOrder $order
+         */
         $order = TransferOrder::create([
-            'transfer_app_id' => $app->id,
-            'out_id' => $app->out_id2 ?? 0,
-            'out_order_id' => $data['business_id'],
-            'out_user_id' => $data['out_user_id'] ?? null,
-            'user_id' => $data['user_id'],
-            'currency_id' => $app->currency_id,
-            'fund_id' => $app->fund_id,
-            'type' => TransferType::IN,
-            'status' => TransferStatus::CREATED,
-            'out_amount' => $outAmount,
-            'amount' => $amount,
-            'exchange_rate' => $app->exchange_rate,
-            'fee_rate' => $feeInfo['fee_rate'],
-            'fee_amount' => $feeInfo['fee_amount'],
-            'actual_amount' => $feeInfo['actual_amount'],
-            'callback_data' => $data['callback_data'] ?? [],
-            'remark' => $data['remark'] ?? null,
-        ]);
+                                           'transfer_app_id' => $app->id,
+                                           'out_id'          => $app->out_id2 ?? 0,
+                                           'out_order_id'    => $data['business_id'],
+                                           'out_user_id'     => $data['out_user_id'] ?? null,
+                                           'user_id'         => $data['user_id'],
+                                           'currency_id'     => $app->currency_id,
+                                           'fund_id'         => $app->fund_id,
+                                           'type'            => TransferType::IN,
+                                           'status'          => TransferStatus::CREATED,
+                                           'out_amount'      => $outAmount,
+                                           'amount'          => $feeInfo->amount,
+                                           'exchange_rate'   => $app->exchange_rate,
+                                           'fee_rate'        => $feeInfo->feeRate,
+                                           'fee_amount'      => $feeInfo->feeAmount,
+                                           'actual_amount'   => $feeInfo->actualAmount,
+                                           'totle_amount'    => $feeInfo->totleAmount,
+
+                                           'callback_data' => $data['callback_data'] ?? [],
+                                           'remark'        => $data['remark'] ?? null,
+                                       ]);
 
         // 验证fund_in_uid必须存在
         if (empty($app->fund_in_uid)) {
@@ -501,7 +523,7 @@ class TransferLogic
         }
 
         // 验证来源账户余额是否充足
-        if ($sourceFundService->balance() < $amount) {
+        if ($sourceFundService->balance() < $order->totle_amount) {
             $order->updateStatus(TransferStatus::FAILED, '来源账户余额不足');
             throw new \Exception('来源账户余额不足');
         }
@@ -530,16 +552,16 @@ class TransferLogic
 
             if (is_string($feeTradeResult)) {
                 Log::warning('Transfer in fee collection failed', [
-                    'order_id' => $order->id,
-                    'fee_amount' => $order->fee_amount,
+                    'order_id'        => $order->id,
+                    'fee_amount'      => $order->fee_amount,
                     'fee_account_uid' => $feeAccountUid,
-                    'error' => $feeTradeResult
+                    'error'           => $feeTradeResult
                 ]);
             } else {
                 Log::info('Transfer in fee collected successfully', [
-                    'order_id' => $order->id,
-                    'fee_amount' => $order->fee_amount,
-                    'fee_account_uid' => $feeAccountUid,
+                    'order_id'           => $order->id,
+                    'fee_amount'         => $order->fee_amount,
+                    'fee_account_uid'    => $feeAccountUid,
                     'configured_account' => $app->fee_account_uid
                 ]);
             }
@@ -578,11 +600,12 @@ class TransferLogic
 
         if (!$order) {
             Log::warning('Transfer callback order not found', $callbackData);
+
             return false;
         }
 
         // 更新订单状态
-        $status = $callbackData['success'] ? TransferStatus::COMPLETED : TransferStatus::FAILED;
+        $status  = $callbackData['success'] ? TransferStatus::COMPLETED : TransferStatus::FAILED;
         $message = $callbackData['message'] ?? null;
 
         return $order->updateStatus($status, $message);
@@ -649,4 +672,5 @@ class TransferLogic
 
         return true;
     }
+
 }

+ 4 - 15
app/Module/Transfer/Models/TransferApp.php

@@ -3,12 +3,13 @@
 namespace App\Module\Transfer\Models;
 
 use App\Module\Transfer\Casts\TransferAppCast;
+use App\Module\Transfer\Events\FeeCalculatedEvent;
 use UCore\ModelCore;
 
 /**
  * 划转应用配置模型
  *
- * field start
+ * field start 
  * @property  int  $id  主键ID
  * @property  string  $keyname  应用标识符
  * @property  string  $title  应用显示名称
@@ -46,7 +47,7 @@ class TransferApp extends ModelCore
      */
     protected $table = 'transfer_apps';
 
-    // attrlist start
+    // attrlist start 
     protected $fillable = [
         'id',
         'keyname',
@@ -243,19 +244,7 @@ class TransferApp extends ModelCore
         return $this->calculateFee($amount, $this->fee_in_rate, $this->fee_in_min, $this->fee_in_max);
     }
 
-    /**
-     * 计算转出手续费
-     *
-     * @param string $amount 转出金额
-     * @param array $context 额外的上下文数据(包含用户ID等信息)
-     * @return array ['fee_rate' => 手续费率, 'fee_amount' => 手续费金额, 'actual_amount' => 用户总支付金额]
-     * @deprecated 模型内,不应该有逻辑
-     */
-    public function calculateOutFee(string $amount, array $context = []): array
-    {
-        // 使用FeeService来计算手续费,这样可以触发事件机制
-        return \App\Module\Transfer\Services\FeeService::calculateOutFee($this, $amount, $context);
-    }
+
 
 
 

+ 4 - 1
app/Module/Transfer/Models/TransferOrder.php

@@ -10,7 +10,7 @@ use UCore\ModelCore;
 
 /**
  * 划转订单模型
- * 
+ *
  * field start 
  * @property  int  $id  主键ID
  * @property  int  $transfer_app_id  划转应用ID
@@ -37,7 +37,9 @@ use UCore\ModelCore;
  * @property  float  $fee_rate  使用的手续费率
  * @property  float  $fee_amount  手续费金额
  * @property  float  $actual_amount  实际到账金额(扣除手续费后)
+ * @property  float  $totle_amount  支付扣除金额
  * field end
+ *
  */
 class TransferOrder extends ModelCore
 {
@@ -70,6 +72,7 @@ class TransferOrder extends ModelCore
         'fee_rate',
         'fee_amount',
         'actual_amount',
+        'totle_amount',
     ];
     // attrlist end
 

+ 28 - 30
app/Module/Transfer/Services/FeeService.php

@@ -11,7 +11,7 @@ use Illuminate\Support\Facades\Event;
 
 /**
  * 手续费服务类
- * 
+ *
  * 负责处理Transfer模块的手续费计算、收取和统计功能
  */
 class FeeService
@@ -22,9 +22,9 @@ class FeeService
      * @param TransferApp $app 划转应用
      * @param string $amount 转入金额
      * @param array $context 额外的上下文数据
-     * @return array ['fee_rate' => 手续费率, 'fee_amount' => 手续费金额, 'actual_amount' => 实际到账金额]
+     * @return FeeCalculatedEvent ['fee_rate' => 手续费率, 'fee_amount' => 手续费金额, 'actual_amount' => 实际到账金额]
      */
-    public static function calculateInFee(TransferApp $app, string $amount, array $context = []): array
+    public static function calculateInFee(TransferApp $app, string $amount, array $context = []): FeeCalculatedEvent
     {
         return self::calculateFeeWithEvents($app, $amount, 'in', $context);
     }
@@ -37,7 +37,7 @@ class FeeService
      * @param array $context 额外的上下文数据
      * @return array ['fee_rate' => 手续费率, 'fee_amount' => 手续费金额, 'actual_amount' => 实际到账金额]
      */
-    public static function calculateOutFee(TransferApp $app, string $amount, array $context = []): array
+    public static function calculateOutFee(TransferApp $app, string $amount, array $context = []): FeeCalculatedEvent
     {
         return self::calculateFeeWithEvents($app, $amount, 'out', $context);
     }
@@ -49,9 +49,9 @@ class FeeService
      * @param string $amount 金额
      * @param string $type 类型:'in' 或 'out'
      * @param array $context 额外的上下文数据
-     * @return array
+     * @return FeeCalculatedEvent
      */
-    private static function calculateFeeWithEvents(TransferApp $app, string $amount, string $type, array $context = []): array
+    private static function calculateFeeWithEvents(TransferApp $app, string $amount, string $type, array $context = []): FeeCalculatedEvent
     {
         // 获取应用配置的手续费参数
         if ($type === 'in') {
@@ -66,29 +66,27 @@ class FeeService
 
         // 使用原有逻辑计算基础手续费
         $baseResult = self::calculateFee($amount, $feeRate, $minFee, $maxFee);
-
         // 创建手续费计算事件
         $event = new FeeCalculatingEvent(
             app: $app,
             amount: $amount,
             type: $type,
-            feeRate: $baseResult['fee_rate'],
             feeAmount: $baseResult['fee_amount'],
-            actualAmount: $baseResult['actual_amount'],
             context: $context
         );
 
+
         // 触发事件,允许其他模块修改手续费
         Event::dispatch($event);
 
         // 获取最终结果
         $finalResult = $event->getResult();
-
+        dump($finalResult);
         // 触发计算完成事件
         $calculatedEvent = FeeCalculatedEvent::fromCalculatingEvent($event);
-        Event::dispatch($calculatedEvent);
 
-        return $finalResult;
+
+        return $calculatedEvent;
     }
 
     /**
@@ -103,23 +101,23 @@ class FeeService
     private static function calculateFee(string $amount, float $feeRate, float $minFee, float $maxFee): array
     {
         $amountDecimal = bcmul($amount, '1', 4); // 转换为4位小数
-        
+
         // 按比例计算手续费
         $feeAmount = bcmul($amountDecimal, (string)$feeRate, 4);
-        
+
         // 应用最低手续费限制
         if (bccomp($feeAmount, (string)$minFee, 4) < 0) {
             $feeAmount = bcmul((string)$minFee, '1', 4);
         }
-        
+
         // 应用最高手续费限制(如果设置了)
         if ($maxFee > 0 && bccomp($feeAmount, (string)$maxFee, 4) > 0) {
             $feeAmount = bcmul((string)$maxFee, '1', 4);
         }
-        
+
         // 计算实际到账金额
         $actualAmount = bcsub($amountDecimal, $feeAmount, 4);
-        
+
         return [
             'fee_rate' => $feeRate,
             'fee_amount' => $feeAmount,
@@ -129,7 +127,7 @@ class FeeService
 
     /**
      * 检查应用是否启用了手续费
-     * 
+     *
      * @param TransferApp $app 划转应用
      * @param string $type 类型:'in' 或 'out'
      * @return bool
@@ -141,13 +139,13 @@ class FeeService
         } elseif ($type === 'out') {
             return $app->fee_out_rate > 0 || $app->fee_out_min > 0;
         }
-        
+
         return false;
     }
 
     /**
      * 获取应用的手续费配置信息
-     * 
+     *
      * @param TransferApp $app 划转应用
      * @return array
      */
@@ -172,7 +170,7 @@ class FeeService
 
     /**
      * 获取订单的手续费统计信息
-     * 
+     *
      * @param int $appId 应用ID(0表示所有应用)
      * @param string $startDate 开始日期
      * @param string $endDate 结束日期
@@ -217,7 +215,7 @@ class FeeService
 
     /**
      * 获取应用的手续费收入统计
-     * 
+     *
      * @param int $appId 应用ID
      * @param int $days 统计天数(默认30天)
      * @return array
@@ -225,7 +223,7 @@ class FeeService
     public static function getAppFeeIncome(int $appId, int $days = 30): array
     {
         $startDate = now()->subDays($days)->startOfDay();
-        
+
         $orders = TransferOrder::where('transfer_app_id', $appId)
             ->where('status', 100)
             ->where('fee_amount', '>', 0)
@@ -262,7 +260,7 @@ class FeeService
 
     /**
      * 验证手续费配置的合法性
-     * 
+     *
      * @param array $config 手续费配置
      * @return array ['valid' => bool, 'errors' => array]
      */
@@ -298,14 +296,14 @@ class FeeService
         }
 
         // 验证最低和最高手续费的关系
-        if (isset($config['fee_in_min'], $config['fee_in_max']) && 
-            $config['fee_in_max'] > 0 && 
+        if (isset($config['fee_in_min'], $config['fee_in_max']) &&
+            $config['fee_in_max'] > 0 &&
             $config['fee_in_min'] > $config['fee_in_max']) {
             $errors[] = '转入最低手续费不能大于最高手续费';
         }
 
-        if (isset($config['fee_out_min'], $config['fee_out_max']) && 
-            $config['fee_out_max'] > 0 && 
+        if (isset($config['fee_out_min'], $config['fee_out_max']) &&
+            $config['fee_out_max'] > 0 &&
             $config['fee_out_min'] > $config['fee_out_max']) {
             $errors[] = '转出最低手续费不能大于最高手续费';
         }
@@ -318,7 +316,7 @@ class FeeService
 
     /**
      * 格式化手续费金额显示
-     * 
+     *
      * @param string|float $amount 手续费金额
      * @param int $decimals 小数位数
      * @return string
@@ -330,7 +328,7 @@ class FeeService
 
     /**
      * 格式化手续费率显示
-     * 
+     *
      * @param float $rate 手续费率
      * @param int $decimals 小数位数
      * @return string

+ 89 - 158
app/Module/Transfer/Services/TransferService.php

@@ -15,6 +15,7 @@ use App\Module\Transfer\Services\FeeService;
  */
 class TransferService
 {
+
     /**
      * 创建转出订单
      *
@@ -29,28 +30,30 @@ class TransferService
      * @return TransferOrderDto|string 成功返回DTO,失败返回错误信息
      */
     public static function createTransferOut(
-        int $transferAppId,
-        int $userId,
-        string $amount,
-        string $password,
+        int     $transferAppId,
+        int     $userId,
+        string  $amount,
+        string  $password,
         ?string $googleCode = null,
         ?string $outUserId = null,
         ?string $remark = null,
-        array $callbackData = []
-    ): TransferOrderDto|string {
+        array   $callbackData = []
+    ): TransferOrderDto|string
+    {
         try {
             $data = [
                 'transfer_app_id' => $transferAppId,
-                'user_id' => $userId,
-                'amount' => $amount,
-                'password' => $password,
-                'google_code' => $googleCode,
-                'out_user_id' => $outUserId,
-                'remark' => $remark,
-                'callback_data' => $callbackData,
+                'user_id'         => $userId,
+                'amount'          => $amount,
+                'password'        => $password,
+                'google_code'     => $googleCode,
+                'out_user_id'     => $outUserId,
+                'remark'          => $remark,
+                'callback_data'   => $callbackData,
             ];
 
             $order = TransferLogic::createTransferOutFromArray($data);
+
             return TransferOrderDto::fromModel($order);
         } catch (\Exception $e) {
             return $e->getMessage();
@@ -70,26 +73,28 @@ class TransferService
      * @return TransferOrderDto|string 成功返回DTO,失败返回错误信息
      */
     public static function createTransferIn(
-        int $transferAppId,
-        int $userId,
-        string $businessId,
-        string $amount,
+        int     $transferAppId,
+        int     $userId,
+        string  $businessId,
+        string  $amount,
         ?string $outUserId = null,
         ?string $remark = null,
-        array $callbackData = []
-    ): TransferOrderDto|string {
+        array   $callbackData = []
+    ): TransferOrderDto|string
+    {
         try {
             $data = [
                 'transfer_app_id' => $transferAppId,
-                'user_id' => $userId,
-                'business_id' => $businessId,
-                'amount' => $amount,
-                'out_user_id' => $outUserId,
-                'remark' => $remark,
-                'callback_data' => $callbackData,
+                'user_id'         => $userId,
+                'business_id'     => $businessId,
+                'amount'          => $amount,
+                'out_user_id'     => $outUserId,
+                'remark'          => $remark,
+                'callback_data'   => $callbackData,
             ];
 
-            $order = TransferLogic::createTransferInFromArray($data);
+            $order = TransferLogic::createTransferInFromArray($data, $userId);
+
             return TransferOrderDto::fromModel($order);
         } catch (\Exception $e) {
             return $e->getMessage();
@@ -98,7 +103,7 @@ class TransferService
 
     /**
      * 查询订单信息
-     * 
+     *
      * @param int $orderId 订单ID
      * @param int|null $userId 用户ID(可选,用于权限验证)
      * @return TransferOrderDto|null
@@ -106,13 +111,13 @@ class TransferService
     public static function getOrderInfo(int $orderId, ?int $userId = null): ?TransferOrderDto
     {
         $query = TransferOrder::where('id', $orderId);
-        
+
         if ($userId !== null) {
             $query->where('user_id', $userId);
         }
-        
+
         $order = $query->first();
-        
+
         return $order ? TransferOrderDto::fromModel($order) : null;
     }
 
@@ -134,14 +139,14 @@ class TransferService
 
     /**
      * 获取用户可用的划转应用列表
-     * 
+     *
      * @param int $userId 用户ID
      * @return TransferAppDto[]
      */
     public static function getAvailableApps(int $userId): array
     {
         $apps = TransferApp::where('is_enabled', true)->get();
-        
+
         return $apps->map(function ($app) {
             return TransferAppDto::fromModel($app);
         })->toArray();
@@ -149,7 +154,7 @@ class TransferService
 
     /**
      * 获取用户订单列表
-     * 
+     *
      * @param int $userId 用户ID
      * @param array $filters 筛选条件
      * @return array
@@ -157,60 +162,60 @@ class TransferService
     public static function getUserOrders(int $userId, array $filters = []): array
     {
         $query = TransferOrder::where('user_id', $userId);
-        
+
         // 应用筛选条件
         if (isset($filters['type'])) {
             $query->where('type', $filters['type']);
         }
-        
+
         if (isset($filters['status'])) {
             $query->where('status', $filters['status']);
         }
-        
+
         if (isset($filters['transfer_app_id'])) {
             $query->where('transfer_app_id', $filters['transfer_app_id']);
         }
-        
+
         if (isset($filters['start_date'])) {
             $query->where('created_at', '>=', $filters['start_date']);
         }
-        
+
         if (isset($filters['end_date'])) {
             $query->where('created_at', '<=', $filters['end_date']);
         }
-        
+
         // 分页参数
-        $page = $filters['page'] ?? 1;
+        $page    = $filters['page'] ?? 1;
         $perPage = $filters['per_page'] ?? 20;
-        
+
         $orders = $query->orderBy('created_at', 'desc')
-            ->paginate($perPage, ['*'], 'page', $page);
-        
+            ->paginate($perPage, [ '*' ], 'page', $page);
+
         return [
-            'data' => $orders->items(),
+            'data'         => $orders->items(),
             'current_page' => $orders->currentPage(),
-            'per_page' => $orders->perPage(),
-            'total' => $orders->total(),
-            'last_page' => $orders->lastPage(),
+            'per_page'     => $orders->perPage(),
+            'total'        => $orders->total(),
+            'last_page'    => $orders->lastPage(),
         ];
     }
 
     /**
      * 获取应用配置信息
-     * 
+     *
      * @param int $appId 应用ID
      * @return TransferAppDto|null
      */
     public static function getAppConfig(int $appId): ?TransferAppDto
     {
         $app = TransferApp::find($appId);
-        
+
         return $app ? TransferAppDto::fromModel($app) : null;
     }
 
     /**
      * 根据应用标识获取配置信息
-     * 
+     *
      * @param string $keyname 应用标识
      * @return TransferAppDto|null
      */
@@ -219,7 +224,7 @@ class TransferService
         $app = TransferApp::where('keyname', $keyname)
             ->where('is_enabled', true)
             ->first();
-            
+
         return $app ? TransferAppDto::fromModel($app) : null;
     }
 
@@ -236,8 +241,9 @@ class TransferService
         } catch (\Exception $e) {
             \Log::error('Transfer callback processing failed', [
                 'error' => $e->getMessage(),
-                'data' => $callbackData
+                'data'  => $callbackData
             ]);
+
             return false;
         }
     }
@@ -252,16 +258,17 @@ class TransferService
      * @return TransferOrderDto|string
      */
     public static function quickCreateTransferOut(
-        int $transferAppId,
-        int $userId,
+        int    $transferAppId,
+        int    $userId,
         string $amount,
         string $password
-    ): TransferOrderDto|string {
+    ): TransferOrderDto|string
+    {
         return self::createTransferOut(
             transferAppId: $transferAppId,
-            userId: $userId,
-            amount: $amount,
-            password: $password
+            userId:        $userId,
+            amount:        $amount,
+            password:      $password
         );
     }
 
@@ -275,98 +282,20 @@ class TransferService
      * @return TransferOrderDto|string
      */
     public static function quickCreateTransferIn(
-        int $transferAppId,
-        int $userId,
+        int    $transferAppId,
+        int    $userId,
         string $businessId,
         string $amount
-    ): TransferOrderDto|string {
+    ): TransferOrderDto|string
+    {
         return self::createTransferIn(
             transferAppId: $transferAppId,
-            userId: $userId,
-            businessId: $businessId,
-            amount: $amount
+            userId:        $userId,
+            businessId:    $businessId,
+            amount:        $amount
         );
     }
 
-    /**
-     * 从数组创建转出订单(向后兼容方法)
-     *
-     * @param array $data 订单数据
-     * @return TransferOrderDto|string
-     * @deprecated 建议使用 createTransferOut() 方法
-     */
-    public static function createTransferOutFromArray(array $data): TransferOrderDto|string
-    {
-        try {
-            $order = TransferLogic::createTransferOutFromArray($data);
-            return TransferOrderDto::fromModel($order);
-        } catch (\Exception $e) {
-            return $e->getMessage();
-        }
-    }
-
-    /**
-     * 从数组创建转入订单(向后兼容方法)
-     *
-     * @param array $data 订单数据
-     * @return TransferOrderDto|string
-     * @deprecated 建议使用 createTransferIn() 方法
-     */
-    public static function createTransferInFromArray(array $data): TransferOrderDto|string
-    {
-        try {
-            $order = TransferLogic::createTransferInFromArray($data);
-            return TransferOrderDto::fromModel($order);
-        } catch (\Exception $e) {
-            return $e->getMessage();
-        }
-    }
-
-    /**
-     * 计算转入手续费
-     *
-     * @param int $transferAppId 划转应用ID
-     * @param string $amount 转入金额
-     * @param array $context 额外的上下文数据
-     * @return array ['fee_rate' => 手续费率, 'fee_amount' => 手续费金额, 'actual_amount' => 实际到账金额]
-     */
-    public static function calculateInFee(int $transferAppId, string $amount, array $context = []): array
-    {
-        try {
-            $app = TransferApp::findOrFail($transferAppId);
-            return FeeService::calculateInFee($app, $amount, $context);
-        } catch (\Exception $e) {
-            return [
-                'fee_rate' => 0.0000,
-                'fee_amount' => '0.0000',
-                'actual_amount' => $amount,
-                'error' => $e->getMessage(),
-            ];
-        }
-    }
-
-    /**
-     * 计算转出手续费
-     *
-     * @param int $transferAppId 划转应用ID
-     * @param string $amount 转出金额
-     * @param array $context 额外的上下文数据
-     * @return array ['fee_rate' => 手续费率, 'fee_amount' => 手续费金额, 'actual_amount' => 实际到账金额]
-     */
-    public static function calculateOutFee(int $transferAppId, string $amount, array $context = []): array
-    {
-        try {
-            $app = TransferApp::findOrFail($transferAppId);
-            return FeeService::calculateOutFee($app, $amount, $context);
-        } catch (\Exception $e) {
-            return [
-                'fee_rate' => 0.0000,
-                'fee_amount' => '0.0000',
-                'actual_amount' => $amount,
-                'error' => $e->getMessage(),
-            ];
-        }
-    }
 
     /**
      * 获取应用的手续费配置
@@ -378,12 +307,13 @@ class TransferService
     {
         try {
             $app = TransferApp::findOrFail($transferAppId);
+
             return FeeService::getFeeConfig($app);
         } catch (\Exception $e) {
             return [
-                'error' => $e->getMessage(),
-                'in' => ['rate' => 0, 'min' => 0, 'max' => 0, 'enabled' => false],
-                'out' => ['rate' => 0, 'min' => 0, 'max' => 0, 'enabled' => false],
+                'error'       => $e->getMessage(),
+                'in'          => [ 'rate' => 0, 'min' => 0, 'max' => 0, 'enabled' => false ],
+                'out'         => [ 'rate' => 0, 'min' => 0, 'max' => 0, 'enabled' => false ],
                 'account_uid' => 0,
             ];
         }
@@ -403,14 +333,14 @@ class TransferService
             return FeeService::getFeeStatistics($appId, $startDate, $endDate);
         } catch (\Exception $e) {
             return [
-                'error' => $e->getMessage(),
+                'error'        => $e->getMessage(),
                 'total_orders' => 0,
-                'total_fee' => 0,
+                'total_fee'    => 0,
                 'avg_fee_rate' => 0,
-                'in_orders' => 0,
-                'in_fee' => 0,
-                'out_orders' => 0,
-                'out_fee' => 0,
+                'in_orders'    => 0,
+                'in_fee'       => 0,
+                'out_orders'   => 0,
+                'out_fee'      => 0,
             ];
         }
     }
@@ -428,14 +358,15 @@ class TransferService
             return FeeService::getAppFeeIncome($appId, $days);
         } catch (\Exception $e) {
             return [
-                'error' => $e->getMessage(),
-                'app_id' => $appId,
-                'days' => $days,
-                'total_fee' => 0,
-                'total_orders' => 0,
+                'error'         => $e->getMessage(),
+                'app_id'        => $appId,
+                'days'          => $days,
+                'total_fee'     => 0,
+                'total_orders'  => 0,
                 'avg_daily_fee' => 0,
-                'daily_stats' => [],
+                'daily_stats'   => [],
             ];
         }
     }
+
 }

+ 7 - 31
app/Module/Transfer/Services/TransferThirdPartyService.php

@@ -4,6 +4,7 @@ namespace App\Module\Transfer\Services;
 
 use App\Module\Transfer\Dtos\TransferOrderDto;
 use App\Module\Transfer\Dtos\TransferFeeDto;
+use App\Module\Transfer\Events\FeeCalculatedEvent;
 use App\Module\Transfer\Logics\TransferLogic;
 use App\Module\Transfer\Models\TransferApp;
 
@@ -16,6 +17,7 @@ class TransferThirdPartyService
 
     /**
      * 创建充值单(转入订单)
+     * 三方 =》 我
      *
      * @param int $thirdPartyAppId 三方应用ID
      * @param int $farmUserId 农场用户ID
@@ -223,41 +225,15 @@ class TransferThirdPartyService
         ];
     }
 
-    /**
-     * 计算充值手续费
-     *
-     * @param int $thirdPartyAppId 三方应用ID
-     * @param string $amount 充值金额
-     * @return TransferFeeDto
-     * @deprecated  暂时无用,有bug
-     */
-    public static function calculateRechargeFee(int $thirdPartyAppId, string $amount): TransferFeeDto
-    {
-        $transferApp = self::getTransferAppByThirdPartyId($thirdPartyAppId);
-
-        if (!$transferApp) {
-            return TransferFeeDto::error(
-                originalAmount: $amount,
-                errorMessage:   '未找到对应的划转应用配置'
-            );
-        }
 
-        // 将三方金额转换为农场内部金额(充值:外部金额转内部金额)
-        $internalAmount = bcmul($amount, (string)$transferApp->exchange_rate, 10);
-
-        // 获取手续费计算结果
-        $feeResult = $transferApp->calculateInFee($internalAmount);
 
-        // 将结果转换为DTO
-        return TransferFeeDto::f($feeResult, $amount);
-    }
 
 
     /**
      * 计算提现手续费(带上下文信息)
      *
      * @param int $thirdPartyAppId 三方应用ID
-     * @param string $amount 提现金额
+     * @param string $amount 提现金额(外部金额)
      * @param array $context 上下文信息(包含用户ID等,用于URS推广模块计算手续费率)
      * @return TransferFeeDto
      */
@@ -276,7 +252,7 @@ class TransferThirdPartyService
         $internalAmount = bcmul($amount, (string)$transferApp->exchange_rate, 10);
 
         // 获取手续费计算结果,传递上下文信息以便URS推广模块计算正确的手续费率
-        $feeResult = $transferApp->calculateOutFee($internalAmount, $context);
+        $FeeCalculatedEvent = \App\Module\Transfer\Services\FeeService::calculateOutFee($transferApp, $internalAmount, $context);
         // ['fee_rate' => 手续费率, 'fee_amount' => 手续费金额, 'actual_amount' => 用户总支付金额]
         //  public readonly float   $feeRate,
         //        public readonly string  $feeAmount,
@@ -288,10 +264,10 @@ class TransferThirdPartyService
         // 将结果转换为DTO
         return TransferFeeDto::success(
             originalAmount: $amount,
-            feeRate:        $feeResult['fee_rate'],
-            feeAmount:      $feeResult['fee_amount'],
+            feeRate:        $FeeCalculatedEvent->feeRate,
+            feeAmount:      $FeeCalculatedEvent->feeAmount,
             actualAmount:   $internalAmount,
-            totleAmount:    $feeResult['actual_amount'],
+            totleAmount:    $FeeCalculatedEvent->totleAmount,
             additionalInfo: []
         );
     }

+ 24 - 0
app/Module/Transfer/Tests/Unit/CalculateOutFeeTest.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace App\Module\Transfer\Tests\Unit;
+
+use Tests\TestCase;
+
+class CalculateOutFeeTest extends TestCase
+{
+
+    public function testA()
+    {
+        $app_id = 11;
+        $farmUserId = 39113;
+        $feeDto = \App\Module\Transfer\Services\TransferThirdPartyService::calculateWithdrawFeeWithContext(
+            $app_id,
+            1,
+            [ 'user_id' => $farmUserId ] // 传递农场用户ID,让URS推广模块能够根据房屋等级和达人等级计算手续费
+        );
+
+        dump($feeDto);
+
+    }
+
+}

+ 2 - 0
app/Module/UrsPromotion/Databases/GenerateSql/urs_promotion_talent_configs.sql

@@ -22,6 +22,8 @@ CREATE TABLE `kku_urs_promotion_talent_configs` (
   `planting_direct_rate` decimal(7,4) DEFAULT '0.0000' COMMENT '直推分成比例',
   `planting_indirect_rate` decimal(7,4) DEFAULT '0.0000' COMMENT '间推分成比例',
   `planting_third_rate` decimal(7,4) DEFAULT '0.0000' COMMENT '三推分成比例',
+  `active_direct_required` int NOT NULL DEFAULT '0' COMMENT '直推所需活跃人数',
+  `active_count_required` int NOT NULL DEFAULT '0' COMMENT '团队所需活跃人数',
   PRIMARY KEY (`id`),
   UNIQUE KEY `uk_level` (`level`),
   KEY `idx_sort_order` (`sort_order`),

+ 32 - 36
app/Module/UrsPromotion/Listeners/UrsTransferFeeListener.php

@@ -13,6 +13,7 @@ use Illuminate\Support\Facades\Log;
  */
 class UrsTransferFeeListener
 {
+
     /**
      * 处理手续费计算事件
      *
@@ -31,10 +32,11 @@ class UrsTransferFeeListener
             $userId = $event->context['user_id'] ?? null;
             if (!$userId) {
                 Log::warning('URS转出手续费监听器:未找到用户ID', [
-                    'app_id' => $event->app->id,
-                    'amount' => $event->amount,
+                    'app_id'  => $event->app->id,
+                    'amount'  => $event->amount,
                     'context' => $event->context
                 ]);
+
                 return;
             }
 
@@ -42,45 +44,39 @@ class UrsTransferFeeListener
             $ursFeeRate = UrsTransferFeeService::getBestFeeRateForUser($userId);
 
             // 应用URS费率(无论是否更优惠,都应该按照房屋等级收取相应费率)
-            if ($ursFeeRate !== $event->feeRate) {
-                $oldFeeRate = $event->feeRate;
-                $oldFeeAmount = $event->feeAmount;
-
-                // 修改手续费率
-                $event->modifyFeeRate(
-                    $ursFeeRate,
-                    'URS推广模块根据房屋等级调整费率',
-                    'UrsPromotionModule'
-                );
-
-                Log::info('URS转出手续费已调整', [
-                    'user_id' => $userId,
-                    'app_id' => $event->app->id,
-                    'amount' => $event->amount,
-                    'old_fee_rate' => $oldFeeRate,
-                    'new_fee_rate' => $ursFeeRate,
-                    'old_fee_amount' => $oldFeeAmount,
-                    'new_fee_amount' => $event->feeAmount,
-                    'adjustment_type' => $ursFeeRate > $oldFeeRate ? 'increase' : 'decrease',
-                    'adjustment_amount' => bcsub($event->feeAmount, $oldFeeAmount, 4)
-                ]);
-            } else {
-                Log::debug('URS转出手续费无需调整', [
-                    'user_id' => $userId,
-                    'app_id' => $event->app->id,
-                    'current_fee_rate' => $event->feeRate,
-                    'urs_fee_rate' => $ursFeeRate
-                ]);
-            }
+
+
+            $oldFeeAmount = $event->feeAmount;
+
+            // 修改手续费率
+            $event->modifyFeeRate(
+                $ursFeeRate,
+                'URS推广模块根据房屋等级调整费率',
+                'UrsPromotionModule'
+            );
+
+            Log::info('URS转出手续费已调整', [
+                'user_id' => $userId,
+                'app_id'  => $event->app->id,
+                'amount'  => $event->amount,
+
+                'new_fee_rate'      => $ursFeeRate,
+                'old_fee_amount'    => $oldFeeAmount,
+                'new_fee_amount'    => $event->feeAmount,
+                'adjustment_type'   => $event->feeAmount > $oldFeeAmount ? 'increase' : 'decrease',
+                'adjustment_amount' => bcsub($event->feeAmount, $oldFeeAmount, 4)
+            ]);
+
 
         } catch (\Exception $e) {
             Log::error('URS转出手续费监听器处理失败', [
                 'user_id' => $event->context['user_id'] ?? null,
-                'app_id' => $event->app->id,
-                'amount' => $event->amount,
-                'error' => $e->getMessage(),
-                'trace' => $e->getTraceAsString()
+                'app_id'  => $event->app->id,
+                'amount'  => $event->amount,
+                'error'   => $e->getMessage(),
+                'trace'   => $e->getTraceAsString()
             ]);
         }
     }
+
 }

+ 2 - 0
app/Module/UrsPromotion/Models/UrsTalentConfig.php

@@ -25,6 +25,8 @@ use App\Module\UrsPromotion\Enums\UrsTalentLevel;
  * @property  float  $planting_direct_rate  直推分成比例
  * @property  float  $planting_indirect_rate  间推分成比例
  * @property  float  $planting_third_rate  三推分成比例
+ * @property  int  $active_direct_required  直推所需活跃人数
+ * @property  int  $active_count_required  团队所需活跃人数
  * field end
  *
  *

+ 2 - 0
database/test/delete.sql

@@ -111,6 +111,8 @@ delete from   kku_mex_transactions where 1=1;
 # kku_mex_price_configs 不处理,配置项目,商品价格配置
 delete from   kku_mex_orders where 1=1;
 delete from   kku_mex_admin_operations where 1=1;
+delete from   kku_mex_match_logs where 1=1;
+
 
 # kku_jobs
 delete from kku_job_runs where 1=1;