getTable(); if (!in_array($source, self::SOURCES, true) || !Schema::hasTable('reporting_contexts')) return; $row = $model->getAttributes(); $id = (string) $model->getKey(); if ($id === '') return; $now = now('Asia/Shanghai')->format('Y-m-d H:i:s'); $identity = self::identity($row, $now, $source); $platform = 'unknown'; if ($model->wasRecentlyCreated && !app()->runningInConsole() && (str_starts_with(request()->path(), 'api/') || str_starts_with(request()->path(), 'agent/')) && request()->path() !== 'api/onMessage') { $value = request()->header('Platform', request()->input('platform')); $platform = is_string($value) && in_array(strtoupper($value), ['PC', 'H5', 'APP'], true) ? strtoupper($value) : 'unknown'; } DB::table('reporting_contexts')->insertOrIgnore(['source' => $source, 'source_id' => $id, 'user_id' => $identity['user_id'], 'agent_id' => $identity['agent_id'], 'inviter_id' => $identity['inviter_id'], 'client_platform' => $platform, 'attribution_quality' => $model->wasRecentlyCreated ? 'event_snapshot' : 'historical_current_agent', 'occurred_at' => $now, 'succeeded_at' => null]); $success = ($source === 'withdraws' && (int) ($row['status'] ?? -1) === 1) || ($source === 'payment_orders' && (int) ($row['status'] ?? -1) === 2) || ($source === 'agent_withdrawals' && ($row['status'] ?? '') === 'paid') || ($source === 'lhc_order' && in_array((int) ($row['lottery_status'] ?? 0), [1, 2, 3, 4], true)) || (in_array($source, ['sport_game_order', 'jisu_game_order'], true) && in_array((int) ($row['status'] ?? 0), [1, 2, 3], true)) || ($source === 'bets' && in_array((int) ($row['status'] ?? 0), [2, 3], true)) || ($source === 'sport_order' && ((int) ($row['settlement_status'] ?? 0) === 1 || (int) ($row['status'] ?? 0) === 2)); if ($success && ($model->wasRecentlyCreated || $model->wasChanged(['status', 'lottery_status', 'settlement_status']))) { DB::table('reporting_contexts')->where('source', $source)->where('source_id', $id)->whereNull('succeeded_at')->update(['succeeded_at' => $now]); } } public static function identity(array $row, string $at, string $source = ''): array { $context = isset($row['id']) ? DB::table('reporting_contexts')->where('source', $source)->where('source_id', (string) $row['id'])->first() : null; if ($context) return ['user_id' => $context->user_id === null ? null : (int) $context->user_id, 'agent_id' => $context->agent_id === null ? null : (int) $context->agent_id, 'inviter_id' => $context->inviter_id === null ? null : (int) $context->inviter_id, 'client_platform' => $context->client_platform, 'attribution_quality' => $context->attribution_quality]; $member = $row['member_id'] ?? ($source === 'sport_order' ? ($row['user_id'] ?? '') : ''); $query = DB::table('users'); if (!empty($row['report_user_id'])) $query->where('id', $row['report_user_id']); elseif ($member !== '') $query->where('member_id', (string) $member); else return ['user_id' => null, 'agent_id' => $source === 'agent_withdrawals' ? ($row['agent_id'] ?? null) : null, 'inviter_id' => null, 'client_platform' => 'unknown', 'attribution_quality' => 'unknown']; $users = $query->limit(2)->get(); if ($users->count() !== 1 || (int) ($users[0]->from ?? 0) === 2) throw new \RuntimeException('真实会员身份不明确'); $user = (array) $users[0]; $inviter = null; if (Schema::hasTable('share_members')) { $relation = DB::table('share_members')->where('user_id', $user['id'])->where('bound_at', '<=', $at)->first(); $inviter = $relation && $relation->parent_user_id !== null ? (int) $relation->parent_user_id : null; } return ['user_id' => (int) $user['id'], 'agent_id' => isset($user['agent_id']) ? (int) $user['agent_id'] : null, 'inviter_id' => $inviter, 'client_platform' => 'unknown', 'attribution_quality' => 'historical_current_agent']; } }