|
|
@@ -0,0 +1,326 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace App\Module\UrsPromotion\Logics;
|
|
|
+
|
|
|
+use App\Module\UrsPromotion\Models\UrsPartnerDividendRecord;
|
|
|
+use App\Module\UrsPromotion\Models\UrsPartnerDividendDetail;
|
|
|
+use App\Module\UrsPromotion\Models\UrsUserTalent;
|
|
|
+use App\Module\UrsPromotion\Services\UrsUserMappingService;
|
|
|
+use App\Module\Transfer\Services\FeeStatisticsService;
|
|
|
+use App\Module\Transfer\Services\FeeService;
|
|
|
+use App\Module\Transfer\Models\TransferApp;
|
|
|
+use Illuminate\Support\Facades\DB;
|
|
|
+use Illuminate\Support\Facades\Log;
|
|
|
+use Carbon\Carbon;
|
|
|
+
|
|
|
+/**
|
|
|
+ * URS合伙人分红逻辑类
|
|
|
+ *
|
|
|
+ * 处理合伙人分红的核心业务逻辑
|
|
|
+ */
|
|
|
+class UrsPartnerDividendLogic
|
|
|
+{
|
|
|
+ /**
|
|
|
+ * 分红比例 (20%)
|
|
|
+ */
|
|
|
+ const DIVIDEND_RATE = 0.20;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 合伙人等级 (顶级达人)
|
|
|
+ */
|
|
|
+ const PARTNER_LEVEL = 5;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行每日合伙人分红
|
|
|
+ *
|
|
|
+ * @param string|null $date 分红日期,默认为今天
|
|
|
+ * @return array 分红结果
|
|
|
+ */
|
|
|
+ public function executeDailyDividend(?string $date = null): array
|
|
|
+ {
|
|
|
+ $date = $date ?: Carbon::today()->format('Y-m-d');
|
|
|
+
|
|
|
+ Log::info("开始执行合伙人分红", ['date' => $date]);
|
|
|
+
|
|
|
+ // 检查是否已经分红
|
|
|
+ if (UrsPartnerDividendRecord::isDividendProcessed($date)) {
|
|
|
+ $message = "日期 {$date} 的分红已经处理过了";
|
|
|
+ Log::warning($message);
|
|
|
+ return ['success' => false, 'message' => $message];
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ DB::beginTransaction();
|
|
|
+
|
|
|
+ // 1. 获取今日手续费统计
|
|
|
+ $totalFeeAmount = $this->getTodayTotalFeeAmount($date);
|
|
|
+ if ($totalFeeAmount <= 0) {
|
|
|
+ $message = "日期 {$date} 没有手续费收入,无需分红";
|
|
|
+ Log::info($message);
|
|
|
+ DB::rollBack();
|
|
|
+ return ['success' => false, 'message' => $message];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 计算分红金额 (总手续费的20%)
|
|
|
+ $dividendAmount = bcmul($totalFeeAmount, self::DIVIDEND_RATE, 10);
|
|
|
+
|
|
|
+ // 3. 获取所有合伙人
|
|
|
+ $partners = $this->getAllPartners();
|
|
|
+ if (empty($partners)) {
|
|
|
+ $message = "没有找到合伙人,无需分红";
|
|
|
+ Log::info($message);
|
|
|
+ DB::rollBack();
|
|
|
+ return ['success' => false, 'message' => $message];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 计算每个合伙人的分红金额
|
|
|
+ $partnerCount = count($partners);
|
|
|
+ $perPartnerAmount = bcdiv($dividendAmount, $partnerCount, 10);
|
|
|
+
|
|
|
+ // 5. 创建分红记录
|
|
|
+ $dividendRecord = $this->createDividendRecord($date, $totalFeeAmount, $dividendAmount, $partnerCount, $perPartnerAmount);
|
|
|
+
|
|
|
+ // 6. 创建分红详情并执行转账
|
|
|
+ $result = $this->processDividendDetails($dividendRecord, $partners, $perPartnerAmount);
|
|
|
+
|
|
|
+ // 7. 更新分红记录状态
|
|
|
+ $this->updateDividendRecordStatus($dividendRecord, $result);
|
|
|
+
|
|
|
+ DB::commit();
|
|
|
+
|
|
|
+ Log::info("合伙人分红执行完成", [
|
|
|
+ 'date' => $date,
|
|
|
+ 'total_fee_amount' => $totalFeeAmount,
|
|
|
+ 'dividend_amount' => $dividendAmount,
|
|
|
+ 'partner_count' => $partnerCount,
|
|
|
+ 'per_partner_amount' => $perPartnerAmount,
|
|
|
+ 'success_count' => $result['success_count'],
|
|
|
+ 'failed_count' => $result['failed_count']
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'success' => true,
|
|
|
+ 'message' => '分红执行完成',
|
|
|
+ 'data' => [
|
|
|
+ 'date' => $date,
|
|
|
+ 'total_fee_amount' => $totalFeeAmount,
|
|
|
+ 'dividend_amount' => $dividendAmount,
|
|
|
+ 'partner_count' => $partnerCount,
|
|
|
+ 'per_partner_amount' => $perPartnerAmount,
|
|
|
+ 'success_count' => $result['success_count'],
|
|
|
+ 'failed_count' => $result['failed_count']
|
|
|
+ ]
|
|
|
+ ];
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ DB::rollBack();
|
|
|
+ Log::error("合伙人分红执行失败", [
|
|
|
+ 'date' => $date,
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'trace' => $e->getTraceAsString()
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'success' => false,
|
|
|
+ 'message' => '分红执行失败: ' . $e->getMessage()
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取今日总手续费金额
|
|
|
+ */
|
|
|
+ private function getTodayTotalFeeAmount(string $date): string
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ // 获取所有应用的手续费统计
|
|
|
+ $result = FeeStatisticsService::getStatsByDateRange($date, $date);
|
|
|
+
|
|
|
+ // 检查是否有错误
|
|
|
+ if (isset($result['error'])) {
|
|
|
+ Log::warning("获取手续费统计有错误", [
|
|
|
+ 'date' => $date,
|
|
|
+ 'error' => $result['error']
|
|
|
+ ]);
|
|
|
+ return '0.0000000000';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 从返回结果中获取数据
|
|
|
+ $stats = $result['data'] ?? [];
|
|
|
+
|
|
|
+ $totalFee = '0.0000000000';
|
|
|
+ foreach ($stats as $stat) {
|
|
|
+ // $stat是数组格式,不是对象
|
|
|
+ $feeAmount = $stat['total_fee_amount'] ?? '0.0000000000';
|
|
|
+ $totalFee = bcadd($totalFee, $feeAmount, 10);
|
|
|
+ }
|
|
|
+
|
|
|
+ Log::info("获取今日手续费统计", [
|
|
|
+ 'date' => $date,
|
|
|
+ 'total_fee' => $totalFee,
|
|
|
+ 'stats_count' => count($stats)
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return $totalFee;
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error("获取今日手续费统计失败", [
|
|
|
+ 'date' => $date,
|
|
|
+ 'error' => $e->getMessage()
|
|
|
+ ]);
|
|
|
+ return '0.0000000000';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取所有合伙人
|
|
|
+ */
|
|
|
+ private function getAllPartners(): array
|
|
|
+ {
|
|
|
+ // 获取所有顶级达人(合伙人)
|
|
|
+ $talents = UrsUserTalent::where('talent_level', self::PARTNER_LEVEL)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ $partners = [];
|
|
|
+ foreach ($talents as $talent) {
|
|
|
+ // UrsUserTalent表中的user_id就是农场用户ID
|
|
|
+ $userId = $talent->user_id;
|
|
|
+
|
|
|
+ // 获取对应的URS用户ID
|
|
|
+ $ursUserId = UrsUserMappingService::getMappingUrsUserId($userId);
|
|
|
+
|
|
|
+ if ($ursUserId) {
|
|
|
+ $partners[] = [
|
|
|
+ 'user_id' => $userId,
|
|
|
+ 'urs_user_id' => $ursUserId,
|
|
|
+ 'talent_level' => $talent->talent_level
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Log::info("获取合伙人列表", [
|
|
|
+ 'total_talents' => $talents->count(),
|
|
|
+ 'valid_partners' => count($partners)
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return $partners;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建分红记录
|
|
|
+ */
|
|
|
+ private function createDividendRecord(string $date, string $totalFeeAmount, string $dividendAmount, int $partnerCount, string $perPartnerAmount): UrsPartnerDividendRecord
|
|
|
+ {
|
|
|
+ // 获取默认的转账应用ID (假设使用第一个启用的应用)
|
|
|
+ $transferApp = TransferApp::where('is_enabled', true)->first();
|
|
|
+ if (!$transferApp) {
|
|
|
+ throw new \Exception('没有找到可用的转账应用');
|
|
|
+ }
|
|
|
+
|
|
|
+ return UrsPartnerDividendRecord::create([
|
|
|
+ 'dividend_date' => $date,
|
|
|
+ 'total_fee_amount' => $totalFeeAmount,
|
|
|
+ 'dividend_amount' => $dividendAmount,
|
|
|
+ 'partner_count' => $partnerCount,
|
|
|
+ 'per_partner_amount' => $perPartnerAmount,
|
|
|
+ 'transfer_app_id' => $transferApp->id,
|
|
|
+ 'status' => UrsPartnerDividendRecord::STATUS_PROCESSING
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理分红详情并执行转账
|
|
|
+ */
|
|
|
+ private function processDividendDetails(UrsPartnerDividendRecord $dividendRecord, array $partners, string $perPartnerAmount): array
|
|
|
+ {
|
|
|
+ $successCount = 0;
|
|
|
+ $failedCount = 0;
|
|
|
+
|
|
|
+ foreach ($partners as $partner) {
|
|
|
+ try {
|
|
|
+ // 创建分红详情记录
|
|
|
+ $detail = UrsPartnerDividendDetail::create([
|
|
|
+ 'dividend_record_id' => $dividendRecord->id,
|
|
|
+ 'user_id' => $partner['user_id'],
|
|
|
+ 'urs_user_id' => $partner['urs_user_id'],
|
|
|
+ 'talent_level' => $partner['talent_level'],
|
|
|
+ 'dividend_amount' => $perPartnerAmount,
|
|
|
+ 'status' => UrsPartnerDividendDetail::STATUS_PENDING
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 执行手续费转移
|
|
|
+ $transferResult = FeeService::transfer(
|
|
|
+ $dividendRecord->transfer_app_id,
|
|
|
+ $partner['user_id'],
|
|
|
+ floatval($perPartnerAmount),
|
|
|
+ $dividendRecord->id,
|
|
|
+ 'partner_dividend'
|
|
|
+ );
|
|
|
+
|
|
|
+ if ($transferResult === true) {
|
|
|
+ // 转账成功
|
|
|
+ $detail->update([
|
|
|
+ 'status' => UrsPartnerDividendDetail::STATUS_COMPLETED
|
|
|
+ ]);
|
|
|
+ $successCount++;
|
|
|
+
|
|
|
+ Log::info("合伙人分红转账成功", [
|
|
|
+ 'user_id' => $partner['user_id'],
|
|
|
+ 'urs_user_id' => $partner['urs_user_id'],
|
|
|
+ 'amount' => $perPartnerAmount
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ // 转账失败
|
|
|
+ $detail->update([
|
|
|
+ 'status' => UrsPartnerDividendDetail::STATUS_FAILED,
|
|
|
+ 'error_message' => is_string($transferResult) ? $transferResult : '转账失败'
|
|
|
+ ]);
|
|
|
+ $failedCount++;
|
|
|
+
|
|
|
+ Log::error("合伙人分红转账失败", [
|
|
|
+ 'user_id' => $partner['user_id'],
|
|
|
+ 'urs_user_id' => $partner['urs_user_id'],
|
|
|
+ 'amount' => $perPartnerAmount,
|
|
|
+ 'error' => $transferResult
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ $failedCount++;
|
|
|
+ Log::error("处理合伙人分红详情失败", [
|
|
|
+ 'user_id' => $partner['user_id'],
|
|
|
+ 'urs_user_id' => $partner['urs_user_id'],
|
|
|
+ 'error' => $e->getMessage()
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'success_count' => $successCount,
|
|
|
+ 'failed_count' => $failedCount
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新分红记录状态
|
|
|
+ */
|
|
|
+ private function updateDividendRecordStatus(UrsPartnerDividendRecord $dividendRecord, array $result): void
|
|
|
+ {
|
|
|
+ if ($result['failed_count'] == 0) {
|
|
|
+ // 全部成功
|
|
|
+ $dividendRecord->update(['status' => UrsPartnerDividendRecord::STATUS_COMPLETED]);
|
|
|
+ } else if ($result['success_count'] == 0) {
|
|
|
+ // 全部失败
|
|
|
+ $dividendRecord->update([
|
|
|
+ 'status' => UrsPartnerDividendRecord::STATUS_FAILED,
|
|
|
+ 'error_message' => '所有分红转账都失败了'
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ // 部分成功
|
|
|
+ $dividendRecord->update([
|
|
|
+ 'status' => UrsPartnerDividendRecord::STATUS_COMPLETED,
|
|
|
+ 'error_message' => "部分转账失败,成功{$result['success_count']}个,失败{$result['failed_count']}个"
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|