doge 22 tuntia sitten
vanhempi
sitoutus
a2017d88f5
2 muutettua tiedostoa jossa 209 lisäystä ja 0 poistoa
  1. 73 0
      app/Console/Commands/CollectExecuteMember.php
  2. 136 0
      app/Services/CollectService.php

+ 73 - 0
app/Console/Commands/CollectExecuteMember.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Services\CollectService;
+use Illuminate\Console\Command;
+
+class CollectExecuteMember extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'collect:execute-member {member_id : 用户 member_id}';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = '按指定用户执行待归集记录的链上归集';
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+        $memberId = $this->argument('member_id');
+
+        $this->info("开始执行用户 {$memberId} 的归集...");
+
+        $result = CollectService::syncCollectStayByMember($memberId);
+        if (($result['handled_count'] ?? 0) === 0 && !empty($result['message'])) {
+            $this->error($result['message']);
+            return Command::FAILURE;
+        }
+
+        $this->table(
+            ['member_id', 'from_address', 'to_address', 'pending_count', 'handled_count', 'success_count', 'fail_count'],
+            [[
+                $result['member_id'] ?? $memberId,
+                $result['from_address'] ?? '',
+                $result['to_address'] ?? '',
+                $result['pending_count'] ?? 0,
+                $result['handled_count'] ?? 0,
+                $result['success_count'] ?? 0,
+                $result['fail_count'] ?? 0,
+            ]]
+        );
+
+        if (!empty($result['items'])) {
+            $this->table(
+                ['id', 'from_address', 'amount', 'status', 'txid', 'error'],
+                array_map(function ($item) {
+                    return [
+                        $item['id'] ?? null,
+                        $item['from_address'] ?? '',
+                        $item['amount'] ?? '',
+                        $item['status'] ?? '',
+                        $item['txid'] ?? '',
+                        $item['error'] ?? '',
+                    ];
+                }, $result['items'])
+            );
+        }
+
+        $this->info('处理完成');
+        return Command::SUCCESS;
+    }
+}

+ 136 - 0
app/Services/CollectService.php

@@ -236,6 +236,142 @@ class CollectService extends BaseService
         return $result;
         return $result;
     }
     }
 
 
+    /**
+     * @description: 处理指定会员待归集记录,会执行链上归集
+     * @param {*} $memberId
+     * @return array
+     */
+    public static function syncCollectStayByMember($memberId)
+    {
+        $result = [
+            'member_id' => $memberId,
+            'threshold' => self::$THRESHOLD,
+            'from_address' => null,
+            'to_address' => null,
+            'pending_count' => 0,
+            'handled_count' => 0,
+            'success_count' => 0,
+            'fail_count' => 0,
+            'items' => [],
+        ];
+
+        $walletInfo = WalletService::findOne(['member_id' => $memberId, 'coin' => 'USDT']);
+        if (empty($walletInfo) || empty($walletInfo->address)) {
+            $result['message'] = '未找到该用户的USDT钱包地址';
+            Log::warning('syncCollectStayByMember skipped: wallet missing', [
+                'member_id' => $memberId,
+            ]);
+            return $result;
+        }
+
+        $result['from_address'] = $walletInfo->address;
+
+        $to_address = self::getUsdtAddress();
+        $trx_private_key = self::getTrxPrivateKey();
+        $result['to_address'] = $to_address;
+
+        Log::info('syncCollectStayByMember start', [
+            'member_id' => $memberId,
+            'from_address' => $walletInfo->address,
+            'threshold' => self::$THRESHOLD,
+            'to_address' => $to_address,
+            'has_trx_private_key' => !empty($trx_private_key),
+        ]);
+
+        if (!$to_address || !$trx_private_key) {
+            $result['message'] = '归集配置不完整';
+            Log::warning('syncCollectStayByMember skipped: missing config', [
+                'member_id' => $memberId,
+                'to_address' => $to_address,
+                'has_trx_private_key' => !empty($trx_private_key),
+            ]);
+            return $result;
+        }
+
+        $list = self::findAll([
+            'status' => self::model()::STATUS_STAY,
+            'amount' => self::$THRESHOLD,
+            'from_address' => $walletInfo->address,
+        ]);
+        $result['pending_count'] = $list->count();
+
+        if ($list->isEmpty()) {
+            $result['message'] = '该用户没有待归集记录';
+            Log::info('syncCollectStayByMember finished: no pending collects', $result);
+            return $result;
+        }
+
+        foreach ($list as $v) {
+            $item = [
+                'id' => $v['id'],
+                'from_address' => $v['from_address'],
+                'amount' => $v['amount'],
+                'status' => 'pending',
+            ];
+            $data = [];
+            $wallets = WalletService::findOne(['address' => $v['from_address']]);
+
+            if (empty($wallets) || empty($wallets['private_key'])) {
+                $item['status'] = 'wallet_not_found';
+                $item['error'] = '未找到归集钱包私钥';
+                $data['remark'] = $item['error'];
+                $data['updated_at'] = now();
+                self::model()::where(self::getWhere(['id' => $v['id']]))->update($data);
+                $result['fail_count']++;
+                $result['handled_count']++;
+                $result['items'][] = $item;
+                Log::warning('syncCollectStayByMember wallet missing', $item + ['member_id' => $memberId]);
+                continue;
+            }
+
+            $privateKey = $wallets['private_key'];
+            $trxBalance = TronHelper::getTrxBalance($v['from_address']);
+            $item['trx_balance'] = $trxBalance;
+
+            if ($trxBalance < 10) {
+                $trxResult = TronHelper::sendTrx($trx_private_key, $v['from_address'], 10);
+                $item['trx_topup_result'] = $trxResult;
+                Log::info('syncCollectStayByMember topup trx', [
+                    'member_id' => $memberId,
+                    'from_address' => $v['from_address'],
+                    'trx_balance' => $trxBalance,
+                    'result' => $trxResult,
+                ]);
+            }
+
+            $transferResult = TronHelper::transferUSDT($privateKey, $to_address, $v['amount']);
+            $item['transfer_result'] = $transferResult;
+
+            $data['to_address'] = $to_address;
+            if (is_array($transferResult) && !empty($transferResult['success'])) {
+                $data['txid'] = $transferResult['txid'] ?? '';
+                $data['remark'] = 'success';
+                $data['status'] = self::model()::STATUS_START;
+                $item['status'] = 'success';
+                $item['txid'] = $data['txid'];
+                $result['success_count']++;
+                Log::info('syncCollectStayByMember transfer success', $item + ['member_id' => $memberId]);
+            } else {
+                $error = is_array($transferResult)
+                    ? ($transferResult['error'] ?? 'USDT归集失败')
+                    : (is_string($transferResult) ? $transferResult : 'USDT归集失败');
+                $data['remark'] = $error;
+                $item['status'] = 'failed';
+                $item['error'] = $error;
+                $result['fail_count']++;
+                Log::warning('syncCollectStayByMember transfer failed', $item + ['member_id' => $memberId]);
+            }
+
+            $data['updated_at'] = now();
+            self::model()::where(self::getWhere(['id' => $v['id']]))->update($data);
+            $result['handled_count']++;
+            $result['items'][] = $item;
+        }
+
+        Log::info('syncCollectStayByMember finished', $result);
+        return $result;
+    }
+
     /**
     /**
      * @description: 处理待归集的
      * @description: 处理待归集的
      * @return {*}
      * @return {*}