ReportContext.php 4.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. <?php
  2. namespace App\Services\Reporting;
  3. use Carbon\Carbon;
  4. use Illuminate\Support\Facades\DB;
  5. use Illuminate\Support\Facades\Schema;
  6. /** Captures attribution at creation, never retrospectively guesses from the latest login. */
  7. class ReportContext
  8. {
  9. public const SOURCES = ['bets', 'lhc_order', 'jisu_game_order', 'sport_game_order', 'sport_order', 'recharges', 'withdraws', 'payment_orders', 'balance_logs', 'agent_withdrawals', 'share_claims'];
  10. public static function captureModel($model): void
  11. {
  12. $source = $model->getTable();
  13. if (!in_array($source, self::SOURCES, true) || !Schema::hasTable('reporting_contexts')) return;
  14. $row = $model->getAttributes(); $id = (string) $model->getKey();
  15. if ($id === '') return;
  16. $now = now('Asia/Shanghai')->format('Y-m-d H:i:s');
  17. $identity = self::identity($row, $now, $source);
  18. $platform = 'unknown';
  19. if ($model->wasRecentlyCreated && !app()->runningInConsole() && (str_starts_with(request()->path(), 'api/') || str_starts_with(request()->path(), 'agent/')) && request()->path() !== 'api/onMessage') {
  20. $value = request()->header('Platform', request()->input('platform'));
  21. $platform = is_string($value) && in_array(strtoupper($value), ['PC', 'H5', 'APP'], true) ? strtoupper($value) : 'unknown';
  22. }
  23. DB::table('reporting_contexts')->insertOrIgnore(['source' => $source, 'source_id' => $id,
  24. 'user_id' => $identity['user_id'], 'agent_id' => $identity['agent_id'], 'inviter_id' => $identity['inviter_id'],
  25. 'client_platform' => $platform, 'attribution_quality' => $model->wasRecentlyCreated ? 'event_snapshot' : 'historical_current_agent', 'occurred_at' => $now, 'succeeded_at' => null]);
  26. $success = ($source === 'withdraws' && (int) ($row['status'] ?? -1) === 1)
  27. || ($source === 'payment_orders' && (int) ($row['status'] ?? -1) === 2)
  28. || ($source === 'agent_withdrawals' && ($row['status'] ?? '') === 'paid')
  29. || ($source === 'lhc_order' && in_array((int) ($row['lottery_status'] ?? 0), [1, 2, 3, 4], true))
  30. || (in_array($source, ['sport_game_order', 'jisu_game_order'], true) && in_array((int) ($row['status'] ?? 0), [1, 2, 3], true))
  31. || ($source === 'bets' && in_array((int) ($row['status'] ?? 0), [2, 3], true))
  32. || ($source === 'sport_order' && ((int) ($row['settlement_status'] ?? 0) === 1 || (int) ($row['status'] ?? 0) === 2));
  33. if ($success && ($model->wasRecentlyCreated || $model->wasChanged(['status', 'lottery_status', 'settlement_status']))) {
  34. DB::table('reporting_contexts')->where('source', $source)->where('source_id', $id)->whereNull('succeeded_at')->update(['succeeded_at' => $now]);
  35. }
  36. }
  37. public static function identity(array $row, string $at, string $source = ''): array
  38. {
  39. $context = isset($row['id']) ? DB::table('reporting_contexts')->where('source', $source)->where('source_id', (string) $row['id'])->first() : null;
  40. if ($context) return ['user_id' => $context->user_id === null ? null : (int) $context->user_id,
  41. 'agent_id' => $context->agent_id === null ? null : (int) $context->agent_id, 'inviter_id' => $context->inviter_id === null ? null : (int) $context->inviter_id,
  42. 'client_platform' => $context->client_platform, 'attribution_quality' => $context->attribution_quality];
  43. $member = $row['member_id'] ?? ($source === 'sport_order' ? ($row['user_id'] ?? '') : '');
  44. $query = DB::table('users');
  45. if (!empty($row['report_user_id'])) $query->where('id', $row['report_user_id']);
  46. elseif ($member !== '') $query->where('member_id', (string) $member);
  47. else return ['user_id' => null, 'agent_id' => $source === 'agent_withdrawals' ? ($row['agent_id'] ?? null) : null,
  48. 'inviter_id' => null, 'client_platform' => 'unknown', 'attribution_quality' => 'unknown'];
  49. $users = $query->limit(2)->get();
  50. if ($users->count() !== 1 || (int) ($users[0]->from ?? 0) === 2) throw new \RuntimeException('真实会员身份不明确');
  51. $user = (array) $users[0]; $inviter = null;
  52. if (Schema::hasTable('share_members')) {
  53. $relation = DB::table('share_members')->where('user_id', $user['id'])->where('bound_at', '<=', $at)->first();
  54. $inviter = $relation && $relation->parent_user_id !== null ? (int) $relation->parent_user_id : null;
  55. }
  56. return ['user_id' => (int) $user['id'], 'agent_id' => isset($user['agent_id']) ? (int) $user['agent_id'] : null,
  57. 'inviter_id' => $inviter, 'client_platform' => 'unknown', 'attribution_quality' => 'historical_current_agent'];
  58. }
  59. }